##// END OF EJS Templates
frontend: remove unused chat code and convert it to topics
ergo -
r372:21804de5 default
parent child Browse files
Show More
@@ -0,0 +1,3 b''
1 /plugins/__REGISTER__ - launched after the onDomReady() code from rhodecode.js is executed
2 /ui/plugins/code/anchor_focus - launched when rc starts to scroll on load to anchor on PR/Codeview
3 /ui/plugins/code/comment_form_built - launched when injectInlineForm() is executed and the form object is created
@@ -1,413 +1,401 b''
1 // # Copyright (C) 2010-2016 RhodeCode GmbH
1 // # Copyright (C) 2010-2016 RhodeCode GmbH
2 // #
2 // #
3 // # This program is free software: you can redistribute it and/or modify
3 // # This program is free software: you can redistribute it and/or modify
4 // # it under the terms of the GNU Affero General Public License, version 3
4 // # it under the terms of the GNU Affero General Public License, version 3
5 // # (only), as published by the Free Software Foundation.
5 // # (only), as published by the Free Software Foundation.
6 // #
6 // #
7 // # This program is distributed in the hope that it will be useful,
7 // # This program is distributed in the hope that it will be useful,
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // # GNU General Public License for more details.
10 // # GNU General Public License for more details.
11 // #
11 // #
12 // # You should have received a copy of the GNU Affero General Public License
12 // # You should have received a copy of the GNU Affero General Public License
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 // #
14 // #
15 // # This program is dual-licensed. If you wish to learn more about the
15 // # This program is dual-licensed. If you wish to learn more about the
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 /**
19 /**
20 RhodeCode JS Files
20 RhodeCode JS Files
21 **/
21 **/
22
22
23 if (typeof console == "undefined" || typeof console.log == "undefined"){
23 if (typeof console == "undefined" || typeof console.log == "undefined"){
24 console = { log: function() {} }
24 console = { log: function() {} }
25 }
25 }
26
26
27 // TODO: move the following function to submodules
27 // TODO: move the following function to submodules
28
28
29 /**
29 /**
30 * show more
30 * show more
31 */
31 */
32 var show_more_event = function(){
32 var show_more_event = function(){
33 $('table .show_more').click(function(e) {
33 $('table .show_more').click(function(e) {
34 var cid = e.target.id.substring(1);
34 var cid = e.target.id.substring(1);
35 var button = $(this);
35 var button = $(this);
36 if (button.hasClass('open')) {
36 if (button.hasClass('open')) {
37 $('#'+cid).hide();
37 $('#'+cid).hide();
38 button.removeClass('open');
38 button.removeClass('open');
39 } else {
39 } else {
40 $('#'+cid).show();
40 $('#'+cid).show();
41 button.addClass('open one');
41 button.addClass('open one');
42 }
42 }
43 });
43 });
44 };
44 };
45
45
46 var compare_radio_buttons = function(repo_name, compare_ref_type){
46 var compare_radio_buttons = function(repo_name, compare_ref_type){
47 $('#compare_action').on('click', function(e){
47 $('#compare_action').on('click', function(e){
48 e.preventDefault();
48 e.preventDefault();
49
49
50 var source = $('input[name=compare_source]:checked').val();
50 var source = $('input[name=compare_source]:checked').val();
51 var target = $('input[name=compare_target]:checked').val();
51 var target = $('input[name=compare_target]:checked').val();
52 if(source && target){
52 if(source && target){
53 var url_data = {
53 var url_data = {
54 repo_name: repo_name,
54 repo_name: repo_name,
55 source_ref: source,
55 source_ref: source,
56 source_ref_type: compare_ref_type,
56 source_ref_type: compare_ref_type,
57 target_ref: target,
57 target_ref: target,
58 target_ref_type: compare_ref_type,
58 target_ref_type: compare_ref_type,
59 merge: 1
59 merge: 1
60 };
60 };
61 window.location = pyroutes.url('compare_url', url_data);
61 window.location = pyroutes.url('compare_url', url_data);
62 }
62 }
63 });
63 });
64 $('.compare-radio-button').on('click', function(e){
64 $('.compare-radio-button').on('click', function(e){
65 var source = $('input[name=compare_source]:checked').val();
65 var source = $('input[name=compare_source]:checked').val();
66 var target = $('input[name=compare_target]:checked').val();
66 var target = $('input[name=compare_target]:checked').val();
67 if(source && target){
67 if(source && target){
68 $('#compare_action').removeAttr("disabled");
68 $('#compare_action').removeAttr("disabled");
69 $('#compare_action').removeClass("disabled");
69 $('#compare_action').removeClass("disabled");
70 }
70 }
71 })
71 })
72 };
72 };
73
73
74 var showRepoSize = function(target, repo_name, commit_id, callback) {
74 var showRepoSize = function(target, repo_name, commit_id, callback) {
75 var container = $('#' + target);
75 var container = $('#' + target);
76 var url = pyroutes.url('repo_stats',
76 var url = pyroutes.url('repo_stats',
77 {"repo_name": repo_name, "commit_id": commit_id});
77 {"repo_name": repo_name, "commit_id": commit_id});
78
78
79 if (!container.hasClass('loaded')) {
79 if (!container.hasClass('loaded')) {
80 $.ajax({url: url})
80 $.ajax({url: url})
81 .complete(function (data) {
81 .complete(function (data) {
82 var responseJSON = data.responseJSON;
82 var responseJSON = data.responseJSON;
83 container.addClass('loaded');
83 container.addClass('loaded');
84 container.html(responseJSON.size);
84 container.html(responseJSON.size);
85 callback(responseJSON.code_stats)
85 callback(responseJSON.code_stats)
86 })
86 })
87 .fail(function (data) {
87 .fail(function (data) {
88 console.log('failed to load repo stats');
88 console.log('failed to load repo stats');
89 });
89 });
90 }
90 }
91
91
92 };
92 };
93
93
94 var showRepoStats = function(target, data){
94 var showRepoStats = function(target, data){
95 var container = $('#' + target);
95 var container = $('#' + target);
96
96
97 if (container.hasClass('loaded')) {
97 if (container.hasClass('loaded')) {
98 return
98 return
99 }
99 }
100
100
101 var total = 0;
101 var total = 0;
102 var no_data = true;
102 var no_data = true;
103 var tbl = document.createElement('table');
103 var tbl = document.createElement('table');
104 tbl.setAttribute('class', 'trending_language_tbl');
104 tbl.setAttribute('class', 'trending_language_tbl');
105
105
106 $.each(data, function(key, val){
106 $.each(data, function(key, val){
107 total += val.count;
107 total += val.count;
108 });
108 });
109
109
110 var sortedStats = [];
110 var sortedStats = [];
111 for (var obj in data){
111 for (var obj in data){
112 sortedStats.push([obj, data[obj]])
112 sortedStats.push([obj, data[obj]])
113 }
113 }
114 var sortedData = sortedStats.sort(function (a, b) {
114 var sortedData = sortedStats.sort(function (a, b) {
115 return b[1].count - a[1].count
115 return b[1].count - a[1].count
116 });
116 });
117 var cnt = 0;
117 var cnt = 0;
118 $.each(sortedData, function(idx, val){
118 $.each(sortedData, function(idx, val){
119 cnt += 1;
119 cnt += 1;
120 no_data = false;
120 no_data = false;
121
121
122 var hide = cnt > 2;
122 var hide = cnt > 2;
123 var tr = document.createElement('tr');
123 var tr = document.createElement('tr');
124 if (hide) {
124 if (hide) {
125 tr.setAttribute('style', 'display:none');
125 tr.setAttribute('style', 'display:none');
126 tr.setAttribute('class', 'stats_hidden');
126 tr.setAttribute('class', 'stats_hidden');
127 }
127 }
128
128
129 var key = val[0];
129 var key = val[0];
130 var obj = {"desc": val[1].desc, "count": val[1].count};
130 var obj = {"desc": val[1].desc, "count": val[1].count};
131
131
132 var percentage = Math.round((obj.count / total * 100), 2);
132 var percentage = Math.round((obj.count / total * 100), 2);
133
133
134 var td1 = document.createElement('td');
134 var td1 = document.createElement('td');
135 td1.width = 300;
135 td1.width = 300;
136 var trending_language_label = document.createElement('div');
136 var trending_language_label = document.createElement('div');
137 trending_language_label.innerHTML = obj.desc + " (.{0})".format(key);
137 trending_language_label.innerHTML = obj.desc + " (.{0})".format(key);
138 td1.appendChild(trending_language_label);
138 td1.appendChild(trending_language_label);
139
139
140 var td2 = document.createElement('td');
140 var td2 = document.createElement('td');
141 var trending_language = document.createElement('div');
141 var trending_language = document.createElement('div');
142 var nr_files = obj.count +" "+ _ngettext('file', 'files', obj.count);
142 var nr_files = obj.count +" "+ _ngettext('file', 'files', obj.count);
143
143
144 trending_language.title = key + " " + nr_files;
144 trending_language.title = key + " " + nr_files;
145
145
146 trending_language.innerHTML = "<span>" + percentage + "% " + nr_files
146 trending_language.innerHTML = "<span>" + percentage + "% " + nr_files
147 + "</span><b>" + percentage + "% " + nr_files + "</b>";
147 + "</span><b>" + percentage + "% " + nr_files + "</b>";
148
148
149 trending_language.setAttribute("class", 'trending_language');
149 trending_language.setAttribute("class", 'trending_language');
150 $('b', trending_language)[0].style.width = percentage + "%";
150 $('b', trending_language)[0].style.width = percentage + "%";
151 td2.appendChild(trending_language);
151 td2.appendChild(trending_language);
152
152
153 tr.appendChild(td1);
153 tr.appendChild(td1);
154 tr.appendChild(td2);
154 tr.appendChild(td2);
155 tbl.appendChild(tr);
155 tbl.appendChild(tr);
156 if (cnt == 3) {
156 if (cnt == 3) {
157 var show_more = document.createElement('tr');
157 var show_more = document.createElement('tr');
158 var td = document.createElement('td');
158 var td = document.createElement('td');
159 lnk = document.createElement('a');
159 lnk = document.createElement('a');
160
160
161 lnk.href = '#';
161 lnk.href = '#';
162 lnk.innerHTML = _ngettext('Show more');
162 lnk.innerHTML = _ngettext('Show more');
163 lnk.id = 'code_stats_show_more';
163 lnk.id = 'code_stats_show_more';
164 td.appendChild(lnk);
164 td.appendChild(lnk);
165
165
166 show_more.appendChild(td);
166 show_more.appendChild(td);
167 show_more.appendChild(document.createElement('td'));
167 show_more.appendChild(document.createElement('td'));
168 tbl.appendChild(show_more);
168 tbl.appendChild(show_more);
169 }
169 }
170 });
170 });
171
171
172 $(container).html(tbl);
172 $(container).html(tbl);
173 $(container).addClass('loaded');
173 $(container).addClass('loaded');
174
174
175 $('#code_stats_show_more').on('click', function (e) {
175 $('#code_stats_show_more').on('click', function (e) {
176 e.preventDefault();
176 e.preventDefault();
177 $('.stats_hidden').each(function (idx) {
177 $('.stats_hidden').each(function (idx) {
178 $(this).css("display", "");
178 $(this).css("display", "");
179 });
179 });
180 $('#code_stats_show_more').hide();
180 $('#code_stats_show_more').hide();
181 });
181 });
182
182
183 };
183 };
184
184
185
185
186 // Toggle Collapsable Content
186 // Toggle Collapsable Content
187 function collapsableContent() {
187 function collapsableContent() {
188
188
189 $('.collapsable-content').not('.no-hide').hide();
189 $('.collapsable-content').not('.no-hide').hide();
190
190
191 $('.btn-collapse').unbind(); //in case we've been here before
191 $('.btn-collapse').unbind(); //in case we've been here before
192 $('.btn-collapse').click(function() {
192 $('.btn-collapse').click(function() {
193 var button = $(this);
193 var button = $(this);
194 var togglename = $(this).data("toggle");
194 var togglename = $(this).data("toggle");
195 $('.collapsable-content[data-toggle='+togglename+']').toggle();
195 $('.collapsable-content[data-toggle='+togglename+']').toggle();
196 if ($(this).html()=="Show Less")
196 if ($(this).html()=="Show Less")
197 $(this).html("Show More");
197 $(this).html("Show More");
198 else
198 else
199 $(this).html("Show Less");
199 $(this).html("Show Less");
200 });
200 });
201 };
201 };
202
202
203 var timeagoActivate = function() {
203 var timeagoActivate = function() {
204 $("time.timeago").timeago();
204 $("time.timeago").timeago();
205 };
205 };
206
206
207 // Formatting values in a Select2 dropdown of commit references
207 // Formatting values in a Select2 dropdown of commit references
208 var formatSelect2SelectionRefs = function(commit_ref){
208 var formatSelect2SelectionRefs = function(commit_ref){
209 var tmpl = '';
209 var tmpl = '';
210 if (!commit_ref.text || commit_ref.type === 'sha'){
210 if (!commit_ref.text || commit_ref.type === 'sha'){
211 return commit_ref.text;
211 return commit_ref.text;
212 }
212 }
213 if (commit_ref.type === 'branch'){
213 if (commit_ref.type === 'branch'){
214 tmpl = tmpl.concat('<i class="icon-branch"></i> ');
214 tmpl = tmpl.concat('<i class="icon-branch"></i> ');
215 } else if (commit_ref.type === 'tag'){
215 } else if (commit_ref.type === 'tag'){
216 tmpl = tmpl.concat('<i class="icon-tag"></i> ');
216 tmpl = tmpl.concat('<i class="icon-tag"></i> ');
217 } else if (commit_ref.type === 'book'){
217 } else if (commit_ref.type === 'book'){
218 tmpl = tmpl.concat('<i class="icon-bookmark"></i> ');
218 tmpl = tmpl.concat('<i class="icon-bookmark"></i> ');
219 }
219 }
220 return tmpl.concat(commit_ref.text);
220 return tmpl.concat(commit_ref.text);
221 };
221 };
222
222
223 // takes a given html element and scrolls it down offset pixels
223 // takes a given html element and scrolls it down offset pixels
224 function offsetScroll(element, offset){
224 function offsetScroll(element, offset){
225 setTimeout(function(){
225 setTimeout(function(){
226 console.log(element);
226 console.log(element);
227 var location = element.offset().top;
227 var location = element.offset().top;
228 // some browsers use body, some use html
228 // some browsers use body, some use html
229 $('html, body').animate({ scrollTop: (location - offset) });
229 $('html, body').animate({ scrollTop: (location - offset) });
230 }, 100);
230 }, 100);
231 }
231 }
232
232
233 /**
233 /**
234 * global hooks after DOM is loaded
234 * global hooks after DOM is loaded
235 */
235 */
236 $(document).ready(function() {
236 $(document).ready(function() {
237 firefoxAnchorFix();
237 firefoxAnchorFix();
238
238
239 $('.navigation a.menulink').on('click', function(e){
239 $('.navigation a.menulink').on('click', function(e){
240 var menuitem = $(this).parent('li');
240 var menuitem = $(this).parent('li');
241 if (menuitem.hasClass('open')) {
241 if (menuitem.hasClass('open')) {
242 menuitem.removeClass('open');
242 menuitem.removeClass('open');
243 } else {
243 } else {
244 menuitem.addClass('open');
244 menuitem.addClass('open');
245 $(document).on('click', function(event) {
245 $(document).on('click', function(event) {
246 if (!$(event.target).closest(menuitem).length) {
246 if (!$(event.target).closest(menuitem).length) {
247 menuitem.removeClass('open');
247 menuitem.removeClass('open');
248 }
248 }
249 });
249 });
250 }
250 }
251 });
251 });
252 // Add tooltips
252 // Add tooltips
253 $('tr.line .lineno a').attr("title","Click to select line").addClass('tooltip');
253 $('tr.line .lineno a').attr("title","Click to select line").addClass('tooltip');
254 $('tr.line .add-comment-line a').attr("title","Click to comment").addClass('tooltip');
254 $('tr.line .add-comment-line a').attr("title","Click to comment").addClass('tooltip');
255
255
256 // Set colors and styles
256 // Set colors and styles
257 $('tr.line .lineno a').hover(
257 $('tr.line .lineno a').hover(
258 function(){
258 function(){
259 $(this).parents('tr.line').addClass('hover');
259 $(this).parents('tr.line').addClass('hover');
260 }, function(){
260 }, function(){
261 $(this).parents('tr.line').removeClass('hover');
261 $(this).parents('tr.line').removeClass('hover');
262 }
262 }
263 );
263 );
264
264
265 $('tr.line .lineno a').click(
265 $('tr.line .lineno a').click(
266 function(){
266 function(){
267 if ($(this).text() != ""){
267 if ($(this).text() != ""){
268 $('tr.line').removeClass('selected');
268 $('tr.line').removeClass('selected');
269 $(this).parents("tr.line").addClass('selected');
269 $(this).parents("tr.line").addClass('selected');
270
270
271 // Replace URL without jumping to it if browser supports.
271 // Replace URL without jumping to it if browser supports.
272 // Default otherwise
272 // Default otherwise
273 if (history.pushState) {
273 if (history.pushState) {
274 var new_location = location.href
274 var new_location = location.href
275 if (location.hash){
275 if (location.hash){
276 new_location = new_location.replace(location.hash, "");
276 new_location = new_location.replace(location.hash, "");
277 }
277 }
278
278
279 // Make new anchor url
279 // Make new anchor url
280 var new_location = new_location+$(this).attr('href');
280 var new_location = new_location+$(this).attr('href');
281 history.pushState(true, document.title, new_location);
281 history.pushState(true, document.title, new_location);
282
282
283 return false;
283 return false;
284 }
284 }
285 }
285 }
286 }
286 }
287 );
287 );
288
288
289 $('tr.line .add-comment-line a').hover(
289 $('tr.line .add-comment-line a').hover(
290 function(){
290 function(){
291 $(this).parents('tr.line').addClass('commenting');
291 $(this).parents('tr.line').addClass('commenting');
292 }, function(){
292 }, function(){
293 $(this).parents('tr.line').removeClass('commenting');
293 $(this).parents('tr.line').removeClass('commenting');
294 }
294 }
295 );
295 );
296
296
297 $('tr.line .add-comment-line a').on('click', function(e){
297 $('tr.line .add-comment-line a').on('click', function(e){
298 var tr = $(e.currentTarget).parents('tr.line')[0];
298 var tr = $(e.currentTarget).parents('tr.line')[0];
299 injectInlineForm(tr);
299 injectInlineForm(tr);
300 return false;
300 return false;
301 });
301 });
302
302
303
303
304 $('.collapse_file').on('click', function(e) {
304 $('.collapse_file').on('click', function(e) {
305 e.stopPropagation();
305 e.stopPropagation();
306 if ($(e.target).is('a')) { return; }
306 if ($(e.target).is('a')) { return; }
307 var node = $(e.delegateTarget).first();
307 var node = $(e.delegateTarget).first();
308 var icon = $($(node.children().first()).children().first());
308 var icon = $($(node.children().first()).children().first());
309 var id = node.attr('fid');
309 var id = node.attr('fid');
310 var target = $('#'+id);
310 var target = $('#'+id);
311 var tr = $('#tr_'+id);
311 var tr = $('#tr_'+id);
312 var diff = $('#diff_'+id);
312 var diff = $('#diff_'+id);
313 if(node.hasClass('expand_file')){
313 if(node.hasClass('expand_file')){
314 node.removeClass('expand_file');
314 node.removeClass('expand_file');
315 icon.removeClass('expand_file_icon');
315 icon.removeClass('expand_file_icon');
316 node.addClass('collapse_file');
316 node.addClass('collapse_file');
317 icon.addClass('collapse_file_icon');
317 icon.addClass('collapse_file_icon');
318 diff.show();
318 diff.show();
319 tr.show();
319 tr.show();
320 target.show();
320 target.show();
321 } else {
321 } else {
322 node.removeClass('collapse_file');
322 node.removeClass('collapse_file');
323 icon.removeClass('collapse_file_icon');
323 icon.removeClass('collapse_file_icon');
324 node.addClass('expand_file');
324 node.addClass('expand_file');
325 icon.addClass('expand_file_icon');
325 icon.addClass('expand_file_icon');
326 diff.hide();
326 diff.hide();
327 tr.hide();
327 tr.hide();
328 target.hide();
328 target.hide();
329 }
329 }
330 });
330 });
331
331
332 $('#expand_all_files').click(function() {
332 $('#expand_all_files').click(function() {
333 $('.expand_file').each(function() {
333 $('.expand_file').each(function() {
334 var node = $(this);
334 var node = $(this);
335 var icon = $($(node.children().first()).children().first());
335 var icon = $($(node.children().first()).children().first());
336 var id = $(this).attr('fid');
336 var id = $(this).attr('fid');
337 var target = $('#'+id);
337 var target = $('#'+id);
338 var tr = $('#tr_'+id);
338 var tr = $('#tr_'+id);
339 var diff = $('#diff_'+id);
339 var diff = $('#diff_'+id);
340 node.removeClass('expand_file');
340 node.removeClass('expand_file');
341 icon.removeClass('expand_file_icon');
341 icon.removeClass('expand_file_icon');
342 node.addClass('collapse_file');
342 node.addClass('collapse_file');
343 icon.addClass('collapse_file_icon');
343 icon.addClass('collapse_file_icon');
344 diff.show();
344 diff.show();
345 tr.show();
345 tr.show();
346 target.show();
346 target.show();
347 });
347 });
348 });
348 });
349
349
350 $('#collapse_all_files').click(function() {
350 $('#collapse_all_files').click(function() {
351 $('.collapse_file').each(function() {
351 $('.collapse_file').each(function() {
352 var node = $(this);
352 var node = $(this);
353 var icon = $($(node.children().first()).children().first());
353 var icon = $($(node.children().first()).children().first());
354 var id = $(this).attr('fid');
354 var id = $(this).attr('fid');
355 var target = $('#'+id);
355 var target = $('#'+id);
356 var tr = $('#tr_'+id);
356 var tr = $('#tr_'+id);
357 var diff = $('#diff_'+id);
357 var diff = $('#diff_'+id);
358 node.removeClass('collapse_file');
358 node.removeClass('collapse_file');
359 icon.removeClass('collapse_file_icon');
359 icon.removeClass('collapse_file_icon');
360 node.addClass('expand_file');
360 node.addClass('expand_file');
361 icon.addClass('expand_file_icon');
361 icon.addClass('expand_file_icon');
362 diff.hide();
362 diff.hide();
363 tr.hide();
363 tr.hide();
364 target.hide();
364 target.hide();
365 });
365 });
366 });
366 });
367
367
368 // Mouse over behavior for comments and line selection
368 // Mouse over behavior for comments and line selection
369
369
370 // Select the line that comes from the url anchor
370 // Select the line that comes from the url anchor
371 // At the time of development, Chrome didn't seem to support jquery's :target
371 // At the time of development, Chrome didn't seem to support jquery's :target
372 // element, so I had to scroll manually
372 // element, so I had to scroll manually
373 if (location.hash) {
373 if (location.hash) {
374 var splitIx = location.hash.indexOf('/?/');
374 var splitIx = location.hash.indexOf('/?/');
375 if (splitIx !== -1){
375 if (splitIx !== -1){
376 var loc = location.hash.slice(0, splitIx);
376 var loc = location.hash.slice(0, splitIx);
377 var remainder = location.hash.slice(splitIx + 2);
377 var remainder = location.hash.slice(splitIx + 2);
378 }
378 }
379 else{
379 else{
380 var loc = location.hash;
380 var loc = location.hash;
381 var remainder = null;
381 var remainder = null;
382 }
382 }
383 if (loc.length > 1){
383 if (loc.length > 1){
384 var lineno = $(loc+'.lineno');
384 var lineno = $(loc+'.lineno');
385 if (lineno.length > 0){
385 if (lineno.length > 0){
386 var tr = lineno.parents('tr.line');
386 var tr = lineno.parents('tr.line');
387 tr.addClass('selected');
387 tr.addClass('selected');
388 $.Topic('/ui/plugins/code/anchor_focus').prepare({
389 tr:tr,
390 remainder:remainder});
388
391
389 // once we scrolled into our line, trigger chat app
392 if (!remainder){
390 if (remainder){
391 tr.find('.add-comment-line a').trigger( "click" );
392 setTimeout(function(){
393 var nextNode = $(tr).next();
394 if(nextNode.hasClass('inline-comments')){
395 nextNode.next().find('.switch-to-chat').trigger( "click" );
396 }
397 else{
398 nextNode.find('.switch-to-chat').trigger( "click" );
399 }
400 // trigger scroll into, later so all elements are already loaded
401 tr[0].scrollIntoView();
402 }, 250);
403
404 }
405 else{
406 tr[0].scrollIntoView();
393 tr[0].scrollIntoView();
407 }
394 }
408 }
395 }
409 }
396 }
410 };
397 }
411
398
412 collapsableContent();
399 collapsableContent();
400 $.Topic('/plugins/__REGISTER__').prepare({});
413 });
401 });
@@ -1,664 +1,655 b''
1 // # Copyright (C) 2010-2016 RhodeCode GmbH
1 // # Copyright (C) 2010-2016 RhodeCode GmbH
2 // #
2 // #
3 // # This program is free software: you can redistribute it and/or modify
3 // # This program is free software: you can redistribute it and/or modify
4 // # it under the terms of the GNU Affero General Public License, version 3
4 // # it under the terms of the GNU Affero General Public License, version 3
5 // # (only), as published by the Free Software Foundation.
5 // # (only), as published by the Free Software Foundation.
6 // #
6 // #
7 // # This program is distributed in the hope that it will be useful,
7 // # This program is distributed in the hope that it will be useful,
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // # GNU General Public License for more details.
10 // # GNU General Public License for more details.
11 // #
11 // #
12 // # You should have received a copy of the GNU Affero General Public License
12 // # You should have received a copy of the GNU Affero General Public License
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 // #
14 // #
15 // # This program is dual-licensed. If you wish to learn more about the
15 // # This program is dual-licensed. If you wish to learn more about the
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 var firefoxAnchorFix = function() {
19 var firefoxAnchorFix = function() {
20 // hack to make anchor links behave properly on firefox, in our inline
20 // hack to make anchor links behave properly on firefox, in our inline
21 // comments generation when comments are injected firefox is misbehaving
21 // comments generation when comments are injected firefox is misbehaving
22 // when jumping to anchor links
22 // when jumping to anchor links
23 if (location.href.indexOf('#') > -1) {
23 if (location.href.indexOf('#') > -1) {
24 location.href += '';
24 location.href += '';
25 }
25 }
26 };
26 };
27
27
28 // returns a node from given html;
28 // returns a node from given html;
29 var fromHTML = function(html){
29 var fromHTML = function(html){
30 var _html = document.createElement('element');
30 var _html = document.createElement('element');
31 _html.innerHTML = html;
31 _html.innerHTML = html;
32 return _html;
32 return _html;
33 };
33 };
34
34
35 var tableTr = function(cls, body){
35 var tableTr = function(cls, body){
36 var _el = document.createElement('div');
36 var _el = document.createElement('div');
37 var _body = $(body).attr('id');
37 var _body = $(body).attr('id');
38 var comment_id = fromHTML(body).children[0].id.split('comment-')[1];
38 var comment_id = fromHTML(body).children[0].id.split('comment-')[1];
39 var id = 'comment-tr-{0}'.format(comment_id);
39 var id = 'comment-tr-{0}'.format(comment_id);
40 var _html = ('<table><tbody><tr id="{0}" class="{1}">'+
40 var _html = ('<table><tbody><tr id="{0}" class="{1}">'+
41 '<td class="add-comment-line"><span class="add-comment-content"></span></td>'+
41 '<td class="add-comment-line"><span class="add-comment-content"></span></td>'+
42 '<td></td>'+
42 '<td></td>'+
43 '<td></td>'+
43 '<td></td>'+
44 '<td>{2}</td>'+
44 '<td>{2}</td>'+
45 '</tr></tbody></table>').format(id, cls, body);
45 '</tr></tbody></table>').format(id, cls, body);
46 $(_el).html(_html);
46 $(_el).html(_html);
47 return _el.children[0].children[0].children[0];
47 return _el.children[0].children[0].children[0];
48 };
48 };
49
49
50 var removeInlineForm = function(form) {
50 var removeInlineForm = function(form) {
51 form.parentNode.removeChild(form);
51 form.parentNode.removeChild(form);
52 };
52 };
53
53
54 var createInlineForm = function(parent_tr, f_path, line) {
54 var createInlineForm = function(parent_tr, f_path, line) {
55 var tmpl = $('#comment-inline-form-template').html();
55 var tmpl = $('#comment-inline-form-template').html();
56 tmpl = tmpl.format(f_path, line);
56 tmpl = tmpl.format(f_path, line);
57 var form = tableTr('comment-form-inline', tmpl);
57 var form = tableTr('comment-form-inline', tmpl);
58 var form_hide_button = $(form).find('.hide-inline-form');
58 var form_hide_button = $(form).find('.hide-inline-form');
59
59
60 $(form_hide_button).click(function(e) {
60 $(form_hide_button).click(function(e) {
61 $('.inline-comments').removeClass('hide-comment-button');
61 $('.inline-comments').removeClass('hide-comment-button');
62 var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode;
62 var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode;
63 if ($(newtr.nextElementSibling).hasClass('inline-comments-button')) {
63 if ($(newtr.nextElementSibling).hasClass('inline-comments-button')) {
64 $(newtr.nextElementSibling).show();
64 $(newtr.nextElementSibling).show();
65 }
65 }
66 $(newtr).parents('.comment-form-inline').remove();
66 $(newtr).parents('.comment-form-inline').remove();
67 $(parent_tr).removeClass('form-open');
67 $(parent_tr).removeClass('form-open');
68 $(parent_tr).removeClass('hl-comment');
68 $(parent_tr).removeClass('hl-comment');
69 });
69 });
70
70
71 return form;
71 return form;
72 };
72 };
73
73
74 var getLineNo = function(tr) {
74 var getLineNo = function(tr) {
75 var line;
75 var line;
76 // Try to get the id and return "" (empty string) if it doesn't exist
76 // Try to get the id and return "" (empty string) if it doesn't exist
77 var o = ($(tr).find('.lineno.old').attr('id')||"").split('_');
77 var o = ($(tr).find('.lineno.old').attr('id')||"").split('_');
78 var n = ($(tr).find('.lineno.new').attr('id')||"").split('_');
78 var n = ($(tr).find('.lineno.new').attr('id')||"").split('_');
79 if (n.length >= 2) {
79 if (n.length >= 2) {
80 line = n[n.length-1];
80 line = n[n.length-1];
81 } else if (o.length >= 2) {
81 } else if (o.length >= 2) {
82 line = o[o.length-1];
82 line = o[o.length-1];
83 }
83 }
84 return line;
84 return line;
85 };
85 };
86
86
87 /**
87 /**
88 * make a single inline comment and place it inside
88 * make a single inline comment and place it inside
89 */
89 */
90 var renderInlineComment = function(json_data, show_add_button) {
90 var renderInlineComment = function(json_data, show_add_button) {
91 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
91 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
92 try {
92 try {
93 var html = json_data.rendered_text;
93 var html = json_data.rendered_text;
94 var lineno = json_data.line_no;
94 var lineno = json_data.line_no;
95 var target_id = json_data.target_id;
95 var target_id = json_data.target_id;
96 placeInline(target_id, lineno, html, show_add_button);
96 placeInline(target_id, lineno, html, show_add_button);
97 } catch (e) {
97 } catch (e) {
98 console.error(e);
98 console.error(e);
99 }
99 }
100 };
100 };
101
101
102 function bindDeleteCommentButtons() {
102 function bindDeleteCommentButtons() {
103 $('.delete-comment').one('click', function() {
103 $('.delete-comment').one('click', function() {
104 var comment_id = $(this).data("comment-id");
104 var comment_id = $(this).data("comment-id");
105
105
106 if (comment_id){
106 if (comment_id){
107 deleteComment(comment_id);
107 deleteComment(comment_id);
108 }
108 }
109 });
109 });
110 }
110 }
111
111
112 /**
112 /**
113 * Inject inline comment for on given TR this tr should be always an .line
113 * Inject inline comment for on given TR this tr should be always an .line
114 * tr containing the line. Code will detect comment, and always put the comment
114 * tr containing the line. Code will detect comment, and always put the comment
115 * block at the very bottom
115 * block at the very bottom
116 */
116 */
117 var injectInlineForm = function(tr){
117 var injectInlineForm = function(tr){
118 if (!$(tr).hasClass('line')) {
118 if (!$(tr).hasClass('line')) {
119 return;
119 return;
120 }
120 }
121
121
122 var _td = $(tr).find('.code').get(0);
122 var _td = $(tr).find('.code').get(0);
123 if ($(tr).hasClass('form-open') ||
123 if ($(tr).hasClass('form-open') ||
124 $(tr).hasClass('context') ||
124 $(tr).hasClass('context') ||
125 $(_td).hasClass('no-comment')) {
125 $(_td).hasClass('no-comment')) {
126 return;
126 return;
127 }
127 }
128 $(tr).addClass('form-open');
128 $(tr).addClass('form-open');
129 $(tr).addClass('hl-comment');
129 $(tr).addClass('hl-comment');
130 var node = $(tr.parentNode.parentNode.parentNode).find('.full_f_path').get(0);
130 var node = $(tr.parentNode.parentNode.parentNode).find('.full_f_path').get(0);
131 var f_path = $(node).attr('path');
131 var f_path = $(node).attr('path');
132 var lineno = getLineNo(tr);
132 var lineno = getLineNo(tr);
133 var form = createInlineForm(tr, f_path, lineno);
133 var form = createInlineForm(tr, f_path, lineno);
134
134
135 var parent = tr;
135 var parent = tr;
136 while (1) {
136 while (1) {
137 var n = parent.nextElementSibling;
137 var n = parent.nextElementSibling;
138 // next element are comments !
138 // next element are comments !
139 if ($(n).hasClass('inline-comments')) {
139 if ($(n).hasClass('inline-comments')) {
140 parent = n;
140 parent = n;
141 }
141 }
142 else {
142 else {
143 break;
143 break;
144 }
144 }
145 }
145 }
146 var _parent = $(parent).get(0);
146 var _parent = $(parent).get(0);
147 $(_parent).after(form);
147 $(_parent).after(form);
148 $('.comment-form-inline').prev('.inline-comments').addClass('hide-comment-button');
148 $('.comment-form-inline').prev('.inline-comments').addClass('hide-comment-button');
149 var f = $(form).get(0);
149 var f = $(form).get(0);
150
150
151 var _form = $(f).find('.inline-form').get(0);
151 var _form = $(f).find('.inline-form').get(0);
152
152
153 $('.switch-to-chat', _form).on('click', function(evt){
154 var fParent = $(_parent).closest('.injected_diff').parent().prev('*[fid]');
155 var fid = fParent.attr('fid');
156
157 // activate chat and trigger subscription to channels
158 $.Topic('/chat_controller').publish({
159 action:'subscribe_to_channels',
160 data: ['/chat${0}$/fid/{1}/{2}'.format(templateContext.repo_name, fid, lineno)]
161 });
162 $(_form).closest('td').find('.comment-inline-form').addClass('hidden');
163 $(_form).closest('td').find('.chat-holder').removeClass('hidden');
164 });
165
166 var pullRequestId = templateContext.pull_request_data.pull_request_id;
153 var pullRequestId = templateContext.pull_request_data.pull_request_id;
167 var commitId = templateContext.commit_data.commit_id;
154 var commitId = templateContext.commit_data.commit_id;
168
155
169 var commentForm = new CommentForm(_form, commitId, pullRequestId, lineno, false);
156 var commentForm = new CommentForm(_form, commitId, pullRequestId, lineno, false);
170 var cm = commentForm.getCmInstance();
157 var cm = commentForm.getCmInstance();
171
158
172 // set a CUSTOM submit handler for inline comments.
159 // set a CUSTOM submit handler for inline comments.
173 commentForm.setHandleFormSubmit(function(o) {
160 commentForm.setHandleFormSubmit(function(o) {
174 var text = commentForm.cm.getValue();
161 var text = commentForm.cm.getValue();
175
162
176 if (text === "") {
163 if (text === "") {
177 return;
164 return;
178 }
165 }
179
166
180 if (lineno === undefined) {
167 if (lineno === undefined) {
181 alert('missing line !');
168 alert('missing line !');
182 return;
169 return;
183 }
170 }
184 if (f_path === undefined) {
171 if (f_path === undefined) {
185 alert('missing file path !');
172 alert('missing file path !');
186 return;
173 return;
187 }
174 }
188
175
189 var excludeCancelBtn = false;
176 var excludeCancelBtn = false;
190 var submitEvent = true;
177 var submitEvent = true;
191 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
178 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
192 commentForm.cm.setOption("readOnly", true);
179 commentForm.cm.setOption("readOnly", true);
193 var postData = {
180 var postData = {
194 'text': text,
181 'text': text,
195 'f_path': f_path,
182 'f_path': f_path,
196 'line': lineno,
183 'line': lineno,
197 'csrf_token': CSRF_TOKEN
184 'csrf_token': CSRF_TOKEN
198 };
185 };
199 var submitSuccessCallback = function(o) {
186 var submitSuccessCallback = function(o) {
200 $(tr).removeClass('form-open');
187 $(tr).removeClass('form-open');
201 removeInlineForm(f);
188 removeInlineForm(f);
202 renderInlineComment(o);
189 renderInlineComment(o);
203 $('.inline-comments').removeClass('hide-comment-button');
190 $('.inline-comments').removeClass('hide-comment-button');
204
191
205 // re trigger the linkification of next/prev navigation
192 // re trigger the linkification of next/prev navigation
206 linkifyComments($('.inline-comment-injected'));
193 linkifyComments($('.inline-comment-injected'));
207 timeagoActivate();
194 timeagoActivate();
208 tooltip_activate();
195 tooltip_activate();
209 bindDeleteCommentButtons();
196 bindDeleteCommentButtons();
210 commentForm.setActionButtonsDisabled(false);
197 commentForm.setActionButtonsDisabled(false);
211
198
212 };
199 };
213 var submitFailCallback = function(){
200 var submitFailCallback = function(){
214 commentForm.resetCommentFormState(text)
201 commentForm.resetCommentFormState(text)
215 };
202 };
216 commentForm.submitAjaxPOST(
203 commentForm.submitAjaxPOST(
217 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
204 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
218 });
205 });
219
206
220 setTimeout(function() {
207 setTimeout(function() {
221 // callbacks
208 // callbacks
222 if (cm !== undefined) {
209 if (cm !== undefined) {
223 cm.focus();
210 cm.focus();
224 }
211 }
225 }, 10);
212 }, 10);
226
213
214 $.Topic('/ui/plugins/code/comment_form_built').prepare({
215 form:_form,
216 parent:_parent}
217 );
227 };
218 };
228
219
229 var deleteComment = function(comment_id) {
220 var deleteComment = function(comment_id) {
230 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id);
221 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id);
231 var postData = {
222 var postData = {
232 '_method': 'delete',
223 '_method': 'delete',
233 'csrf_token': CSRF_TOKEN
224 'csrf_token': CSRF_TOKEN
234 };
225 };
235
226
236 var success = function(o) {
227 var success = function(o) {
237 window.location.reload();
228 window.location.reload();
238 };
229 };
239 ajaxPOST(url, postData, success);
230 ajaxPOST(url, postData, success);
240 };
231 };
241
232
242 var createInlineAddButton = function(tr){
233 var createInlineAddButton = function(tr){
243 var label = _gettext('Add another comment');
234 var label = _gettext('Add another comment');
244 var html_el = document.createElement('div');
235 var html_el = document.createElement('div');
245 $(html_el).addClass('add-comment');
236 $(html_el).addClass('add-comment');
246 html_el.innerHTML = '<span class="btn btn-secondary">{0}</span>'.format(label);
237 html_el.innerHTML = '<span class="btn btn-secondary">{0}</span>'.format(label);
247 var add = new $(html_el);
238 var add = new $(html_el);
248 add.on('click', function(e) {
239 add.on('click', function(e) {
249 injectInlineForm(tr);
240 injectInlineForm(tr);
250 });
241 });
251 return add;
242 return add;
252 };
243 };
253
244
254 var placeAddButton = function(target_tr){
245 var placeAddButton = function(target_tr){
255 if(!target_tr){
246 if(!target_tr){
256 return;
247 return;
257 }
248 }
258 var last_node = target_tr;
249 var last_node = target_tr;
259 // scan
250 // scan
260 while (1){
251 while (1){
261 var n = last_node.nextElementSibling;
252 var n = last_node.nextElementSibling;
262 // next element are comments !
253 // next element are comments !
263 if($(n).hasClass('inline-comments')){
254 if($(n).hasClass('inline-comments')){
264 last_node = n;
255 last_node = n;
265 // also remove the comment button from previous
256 // also remove the comment button from previous
266 var comment_add_buttons = $(last_node).find('.add-comment');
257 var comment_add_buttons = $(last_node).find('.add-comment');
267 for(var i=0; i<comment_add_buttons.length; i++){
258 for(var i=0; i<comment_add_buttons.length; i++){
268 var b = comment_add_buttons[i];
259 var b = comment_add_buttons[i];
269 b.parentNode.removeChild(b);
260 b.parentNode.removeChild(b);
270 }
261 }
271 }
262 }
272 else{
263 else{
273 break;
264 break;
274 }
265 }
275 }
266 }
276 var add = createInlineAddButton(target_tr);
267 var add = createInlineAddButton(target_tr);
277 // get the comment div
268 // get the comment div
278 var comment_block = $(last_node).find('.comment')[0];
269 var comment_block = $(last_node).find('.comment')[0];
279 // attach add button
270 // attach add button
280 $(add).insertAfter(comment_block);
271 $(add).insertAfter(comment_block);
281 };
272 };
282
273
283 /**
274 /**
284 * Places the inline comment into the changeset block in proper line position
275 * Places the inline comment into the changeset block in proper line position
285 */
276 */
286 var placeInline = function(target_container, lineno, html, show_add_button) {
277 var placeInline = function(target_container, lineno, html, show_add_button) {
287 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
278 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
288
279
289 var lineid = "{0}_{1}".format(target_container, lineno);
280 var lineid = "{0}_{1}".format(target_container, lineno);
290 var target_line = $('#' + lineid).get(0);
281 var target_line = $('#' + lineid).get(0);
291 var comment = new $(tableTr('inline-comments', html));
282 var comment = new $(tableTr('inline-comments', html));
292 // check if there are comments already !
283 // check if there are comments already !
293 var parent_node = target_line.parentNode;
284 var parent_node = target_line.parentNode;
294 var root_parent = parent_node;
285 var root_parent = parent_node;
295 while (1) {
286 while (1) {
296 var n = parent_node.nextElementSibling;
287 var n = parent_node.nextElementSibling;
297 // next element are comments !
288 // next element are comments !
298 if ($(n).hasClass('inline-comments')) {
289 if ($(n).hasClass('inline-comments')) {
299 parent_node = n;
290 parent_node = n;
300 }
291 }
301 else {
292 else {
302 break;
293 break;
303 }
294 }
304 }
295 }
305 // put in the comment at the bottom
296 // put in the comment at the bottom
306 $(comment).insertAfter(parent_node);
297 $(comment).insertAfter(parent_node);
307 $(comment).find('.comment-inline').addClass('inline-comment-injected');
298 $(comment).find('.comment-inline').addClass('inline-comment-injected');
308 // scan nodes, and attach add button to last one
299 // scan nodes, and attach add button to last one
309 if (show_add_button) {
300 if (show_add_button) {
310 placeAddButton(root_parent);
301 placeAddButton(root_parent);
311 }
302 }
312
303
313 return target_line;
304 return target_line;
314 };
305 };
315
306
316 var linkifyComments = function(comments) {
307 var linkifyComments = function(comments) {
317
308
318 for (var i = 0; i < comments.length; i++) {
309 for (var i = 0; i < comments.length; i++) {
319 var comment_id = $(comments[i]).data('comment-id');
310 var comment_id = $(comments[i]).data('comment-id');
320 var prev_comment_id = $(comments[i - 1]).data('comment-id');
311 var prev_comment_id = $(comments[i - 1]).data('comment-id');
321 var next_comment_id = $(comments[i + 1]).data('comment-id');
312 var next_comment_id = $(comments[i + 1]).data('comment-id');
322
313
323 // place next/prev links
314 // place next/prev links
324 if (prev_comment_id) {
315 if (prev_comment_id) {
325 $('#prev_c_' + comment_id).show();
316 $('#prev_c_' + comment_id).show();
326 $('#prev_c_' + comment_id + " a.arrow_comment_link").attr(
317 $('#prev_c_' + comment_id + " a.arrow_comment_link").attr(
327 'href', '#comment-' + prev_comment_id).removeClass('disabled');
318 'href', '#comment-' + prev_comment_id).removeClass('disabled');
328 }
319 }
329 if (next_comment_id) {
320 if (next_comment_id) {
330 $('#next_c_' + comment_id).show();
321 $('#next_c_' + comment_id).show();
331 $('#next_c_' + comment_id + " a.arrow_comment_link").attr(
322 $('#next_c_' + comment_id + " a.arrow_comment_link").attr(
332 'href', '#comment-' + next_comment_id).removeClass('disabled');
323 'href', '#comment-' + next_comment_id).removeClass('disabled');
333 }
324 }
334 // place a first link to the total counter
325 // place a first link to the total counter
335 if (i === 0) {
326 if (i === 0) {
336 $('#inline-comments-counter').attr('href', '#comment-' + comment_id);
327 $('#inline-comments-counter').attr('href', '#comment-' + comment_id);
337 }
328 }
338 }
329 }
339
330
340 };
331 };
341
332
342 /**
333 /**
343 * Iterates over all the inlines, and places them inside proper blocks of data
334 * Iterates over all the inlines, and places them inside proper blocks of data
344 */
335 */
345 var renderInlineComments = function(file_comments, show_add_button) {
336 var renderInlineComments = function(file_comments, show_add_button) {
346 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
337 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
347
338
348 for (var i = 0; i < file_comments.length; i++) {
339 for (var i = 0; i < file_comments.length; i++) {
349 var box = file_comments[i];
340 var box = file_comments[i];
350
341
351 var target_id = $(box).attr('target_id');
342 var target_id = $(box).attr('target_id');
352
343
353 // actually comments with line numbers
344 // actually comments with line numbers
354 var comments = box.children;
345 var comments = box.children;
355
346
356 for (var j = 0; j < comments.length; j++) {
347 for (var j = 0; j < comments.length; j++) {
357 var data = {
348 var data = {
358 'rendered_text': comments[j].outerHTML,
349 'rendered_text': comments[j].outerHTML,
359 'line_no': $(comments[j]).attr('line'),
350 'line_no': $(comments[j]).attr('line'),
360 'target_id': target_id
351 'target_id': target_id
361 };
352 };
362 renderInlineComment(data, show_add_button);
353 renderInlineComment(data, show_add_button);
363 }
354 }
364 }
355 }
365
356
366 // since order of injection is random, we're now re-iterating
357 // since order of injection is random, we're now re-iterating
367 // from correct order and filling in links
358 // from correct order and filling in links
368 linkifyComments($('.inline-comment-injected'));
359 linkifyComments($('.inline-comment-injected'));
369 bindDeleteCommentButtons();
360 bindDeleteCommentButtons();
370 firefoxAnchorFix();
361 firefoxAnchorFix();
371 };
362 };
372
363
373
364
374 /* Comment form for main and inline comments */
365 /* Comment form for main and inline comments */
375 var CommentForm = (function() {
366 var CommentForm = (function() {
376 "use strict";
367 "use strict";
377
368
378 function CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions) {
369 function CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions) {
379
370
380 this.withLineNo = function(selector) {
371 this.withLineNo = function(selector) {
381 var lineNo = this.lineNo;
372 var lineNo = this.lineNo;
382 if (lineNo === undefined) {
373 if (lineNo === undefined) {
383 return selector
374 return selector
384 } else {
375 } else {
385 return selector + '_' + lineNo;
376 return selector + '_' + lineNo;
386 }
377 }
387 };
378 };
388
379
389 this.commitId = commitId;
380 this.commitId = commitId;
390 this.pullRequestId = pullRequestId;
381 this.pullRequestId = pullRequestId;
391 this.lineNo = lineNo;
382 this.lineNo = lineNo;
392 this.initAutocompleteActions = initAutocompleteActions;
383 this.initAutocompleteActions = initAutocompleteActions;
393
384
394 this.previewButton = this.withLineNo('#preview-btn');
385 this.previewButton = this.withLineNo('#preview-btn');
395 this.previewContainer = this.withLineNo('#preview-container');
386 this.previewContainer = this.withLineNo('#preview-container');
396
387
397 this.previewBoxSelector = this.withLineNo('#preview-box');
388 this.previewBoxSelector = this.withLineNo('#preview-box');
398
389
399 this.editButton = this.withLineNo('#edit-btn');
390 this.editButton = this.withLineNo('#edit-btn');
400 this.editContainer = this.withLineNo('#edit-container');
391 this.editContainer = this.withLineNo('#edit-container');
401
392
402 this.cancelButton = this.withLineNo('#cancel-btn');
393 this.cancelButton = this.withLineNo('#cancel-btn');
403
394
404 this.statusChange = '#change_status';
395 this.statusChange = '#change_status';
405 this.cmBox = this.withLineNo('#text');
396 this.cmBox = this.withLineNo('#text');
406 this.cm = initCommentBoxCodeMirror(this.cmBox, this.initAutocompleteActions);
397 this.cm = initCommentBoxCodeMirror(this.cmBox, this.initAutocompleteActions);
407
398
408 this.submitForm = formElement;
399 this.submitForm = formElement;
409 this.submitButton = $(this.submitForm).find('input[type="submit"]');
400 this.submitButton = $(this.submitForm).find('input[type="submit"]');
410 this.submitButtonText = this.submitButton.val();
401 this.submitButtonText = this.submitButton.val();
411
402
412 this.previewUrl = pyroutes.url('changeset_comment_preview',
403 this.previewUrl = pyroutes.url('changeset_comment_preview',
413 {'repo_name': templateContext.repo_name});
404 {'repo_name': templateContext.repo_name});
414
405
415 // based on commitId, or pullReuqestId decide where do we submit
406 // based on commitId, or pullReuqestId decide where do we submit
416 // out data
407 // out data
417 if (this.commitId){
408 if (this.commitId){
418 this.submitUrl = pyroutes.url('changeset_comment',
409 this.submitUrl = pyroutes.url('changeset_comment',
419 {'repo_name': templateContext.repo_name,
410 {'repo_name': templateContext.repo_name,
420 'revision': this.commitId});
411 'revision': this.commitId});
421
412
422 } else if (this.pullRequestId) {
413 } else if (this.pullRequestId) {
423 this.submitUrl = pyroutes.url('pullrequest_comment',
414 this.submitUrl = pyroutes.url('pullrequest_comment',
424 {'repo_name': templateContext.repo_name,
415 {'repo_name': templateContext.repo_name,
425 'pull_request_id': this.pullRequestId});
416 'pull_request_id': this.pullRequestId});
426
417
427 } else {
418 } else {
428 throw new Error(
419 throw new Error(
429 'CommentForm requires pullRequestId, or commitId to be specified.')
420 'CommentForm requires pullRequestId, or commitId to be specified.')
430 }
421 }
431
422
432 this.getCmInstance = function(){
423 this.getCmInstance = function(){
433 return this.cm
424 return this.cm
434 };
425 };
435
426
436 var self = this;
427 var self = this;
437
428
438 this.getCommentStatus = function() {
429 this.getCommentStatus = function() {
439 return $(this.submitForm).find(this.statusChange).val();
430 return $(this.submitForm).find(this.statusChange).val();
440 };
431 };
441
432
442 this.isAllowedToSubmit = function() {
433 this.isAllowedToSubmit = function() {
443 return !$(this.submitButton).prop('disabled');
434 return !$(this.submitButton).prop('disabled');
444 };
435 };
445
436
446 this.initStatusChangeSelector = function(){
437 this.initStatusChangeSelector = function(){
447 var formatChangeStatus = function(state, escapeMarkup) {
438 var formatChangeStatus = function(state, escapeMarkup) {
448 var originalOption = state.element;
439 var originalOption = state.element;
449 return '<div class="flag_status ' + $(originalOption).data('status') + ' pull-left"></div>' +
440 return '<div class="flag_status ' + $(originalOption).data('status') + ' pull-left"></div>' +
450 '<span>' + escapeMarkup(state.text) + '</span>';
441 '<span>' + escapeMarkup(state.text) + '</span>';
451 };
442 };
452 var formatResult = function(result, container, query, escapeMarkup) {
443 var formatResult = function(result, container, query, escapeMarkup) {
453 return formatChangeStatus(result, escapeMarkup);
444 return formatChangeStatus(result, escapeMarkup);
454 };
445 };
455
446
456 var formatSelection = function(data, container, escapeMarkup) {
447 var formatSelection = function(data, container, escapeMarkup) {
457 return formatChangeStatus(data, escapeMarkup);
448 return formatChangeStatus(data, escapeMarkup);
458 };
449 };
459
450
460 $(this.submitForm).find(this.statusChange).select2({
451 $(this.submitForm).find(this.statusChange).select2({
461 placeholder: _gettext('Status Review'),
452 placeholder: _gettext('Status Review'),
462 formatResult: formatResult,
453 formatResult: formatResult,
463 formatSelection: formatSelection,
454 formatSelection: formatSelection,
464 containerCssClass: "drop-menu status_box_menu",
455 containerCssClass: "drop-menu status_box_menu",
465 dropdownCssClass: "drop-menu-dropdown",
456 dropdownCssClass: "drop-menu-dropdown",
466 dropdownAutoWidth: true,
457 dropdownAutoWidth: true,
467 minimumResultsForSearch: -1
458 minimumResultsForSearch: -1
468 });
459 });
469 $(this.submitForm).find(this.statusChange).on('change', function() {
460 $(this.submitForm).find(this.statusChange).on('change', function() {
470 var status = self.getCommentStatus();
461 var status = self.getCommentStatus();
471 if (status && !self.lineNo) {
462 if (status && !self.lineNo) {
472 $(self.submitButton).prop('disabled', false);
463 $(self.submitButton).prop('disabled', false);
473 }
464 }
474 //todo, fix this name
465 //todo, fix this name
475 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
466 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
476 self.cm.setOption('placeholder', placeholderText);
467 self.cm.setOption('placeholder', placeholderText);
477 })
468 })
478 };
469 };
479
470
480 // reset the comment form into it's original state
471 // reset the comment form into it's original state
481 this.resetCommentFormState = function(content) {
472 this.resetCommentFormState = function(content) {
482 content = content || '';
473 content = content || '';
483
474
484 $(this.editContainer).show();
475 $(this.editContainer).show();
485 $(this.editButton).hide();
476 $(this.editButton).hide();
486
477
487 $(this.previewContainer).hide();
478 $(this.previewContainer).hide();
488 $(this.previewButton).show();
479 $(this.previewButton).show();
489
480
490 this.setActionButtonsDisabled(true);
481 this.setActionButtonsDisabled(true);
491 self.cm.setValue(content);
482 self.cm.setValue(content);
492 self.cm.setOption("readOnly", false);
483 self.cm.setOption("readOnly", false);
493 };
484 };
494
485
495 this.submitAjaxPOST = function(url, postData, successHandler, failHandler) {
486 this.submitAjaxPOST = function(url, postData, successHandler, failHandler) {
496 failHandler = failHandler || function() {};
487 failHandler = failHandler || function() {};
497 var postData = toQueryString(postData);
488 var postData = toQueryString(postData);
498 var request = $.ajax({
489 var request = $.ajax({
499 url: url,
490 url: url,
500 type: 'POST',
491 type: 'POST',
501 data: postData,
492 data: postData,
502 headers: {'X-PARTIAL-XHR': true}
493 headers: {'X-PARTIAL-XHR': true}
503 })
494 })
504 .done(function(data) {
495 .done(function(data) {
505 successHandler(data);
496 successHandler(data);
506 })
497 })
507 .fail(function(data, textStatus, errorThrown){
498 .fail(function(data, textStatus, errorThrown){
508 alert(
499 alert(
509 "Error while submitting comment.\n" +
500 "Error while submitting comment.\n" +
510 "Error code {0} ({1}).".format(data.status, data.statusText));
501 "Error code {0} ({1}).".format(data.status, data.statusText));
511 failHandler()
502 failHandler()
512 });
503 });
513 return request;
504 return request;
514 };
505 };
515
506
516 // overwrite a submitHandler, we need to do it for inline comments
507 // overwrite a submitHandler, we need to do it for inline comments
517 this.setHandleFormSubmit = function(callback) {
508 this.setHandleFormSubmit = function(callback) {
518 this.handleFormSubmit = callback;
509 this.handleFormSubmit = callback;
519 };
510 };
520
511
521 // default handler for for submit for main comments
512 // default handler for for submit for main comments
522 this.handleFormSubmit = function() {
513 this.handleFormSubmit = function() {
523 var text = self.cm.getValue();
514 var text = self.cm.getValue();
524 var status = self.getCommentStatus();
515 var status = self.getCommentStatus();
525
516
526 if (text === "" && !status) {
517 if (text === "" && !status) {
527 return;
518 return;
528 }
519 }
529
520
530 var excludeCancelBtn = false;
521 var excludeCancelBtn = false;
531 var submitEvent = true;
522 var submitEvent = true;
532 self.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
523 self.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
533 self.cm.setOption("readOnly", true);
524 self.cm.setOption("readOnly", true);
534 var postData = {
525 var postData = {
535 'text': text,
526 'text': text,
536 'changeset_status': status,
527 'changeset_status': status,
537 'csrf_token': CSRF_TOKEN
528 'csrf_token': CSRF_TOKEN
538 };
529 };
539
530
540 var submitSuccessCallback = function(o) {
531 var submitSuccessCallback = function(o) {
541 if (status) {
532 if (status) {
542 location.reload(true);
533 location.reload(true);
543 } else {
534 } else {
544 $('#injected_page_comments').append(o.rendered_text);
535 $('#injected_page_comments').append(o.rendered_text);
545 self.resetCommentFormState();
536 self.resetCommentFormState();
546 bindDeleteCommentButtons();
537 bindDeleteCommentButtons();
547 timeagoActivate();
538 timeagoActivate();
548 tooltip_activate();
539 tooltip_activate();
549 }
540 }
550 };
541 };
551 var submitFailCallback = function(){
542 var submitFailCallback = function(){
552 self.resetCommentFormState(text)
543 self.resetCommentFormState(text)
553 };
544 };
554 self.submitAjaxPOST(
545 self.submitAjaxPOST(
555 self.submitUrl, postData, submitSuccessCallback, submitFailCallback);
546 self.submitUrl, postData, submitSuccessCallback, submitFailCallback);
556 };
547 };
557
548
558 this.previewSuccessCallback = function(o) {
549 this.previewSuccessCallback = function(o) {
559 $(self.previewBoxSelector).html(o);
550 $(self.previewBoxSelector).html(o);
560 $(self.previewBoxSelector).removeClass('unloaded');
551 $(self.previewBoxSelector).removeClass('unloaded');
561
552
562 // swap buttons
553 // swap buttons
563 $(self.previewButton).hide();
554 $(self.previewButton).hide();
564 $(self.editButton).show();
555 $(self.editButton).show();
565
556
566 // unlock buttons
557 // unlock buttons
567 self.setActionButtonsDisabled(false);
558 self.setActionButtonsDisabled(false);
568 };
559 };
569
560
570 this.setActionButtonsDisabled = function(state, excludeCancelBtn, submitEvent) {
561 this.setActionButtonsDisabled = function(state, excludeCancelBtn, submitEvent) {
571 excludeCancelBtn = excludeCancelBtn || false;
562 excludeCancelBtn = excludeCancelBtn || false;
572 submitEvent = submitEvent || false;
563 submitEvent = submitEvent || false;
573
564
574 $(this.editButton).prop('disabled', state);
565 $(this.editButton).prop('disabled', state);
575 $(this.previewButton).prop('disabled', state);
566 $(this.previewButton).prop('disabled', state);
576
567
577 if (!excludeCancelBtn) {
568 if (!excludeCancelBtn) {
578 $(this.cancelButton).prop('disabled', state);
569 $(this.cancelButton).prop('disabled', state);
579 }
570 }
580
571
581 var submitState = state;
572 var submitState = state;
582 if (!submitEvent && this.getCommentStatus() && !this.lineNo) {
573 if (!submitEvent && this.getCommentStatus() && !this.lineNo) {
583 // if the value of commit review status is set, we allow
574 // if the value of commit review status is set, we allow
584 // submit button, but only on Main form, lineNo means inline
575 // submit button, but only on Main form, lineNo means inline
585 submitState = false
576 submitState = false
586 }
577 }
587 $(this.submitButton).prop('disabled', submitState);
578 $(this.submitButton).prop('disabled', submitState);
588 if (submitEvent) {
579 if (submitEvent) {
589 $(this.submitButton).val(_gettext('Submitting...'));
580 $(this.submitButton).val(_gettext('Submitting...'));
590 } else {
581 } else {
591 $(this.submitButton).val(this.submitButtonText);
582 $(this.submitButton).val(this.submitButtonText);
592 }
583 }
593
584
594 };
585 };
595
586
596 // lock preview/edit/submit buttons on load, but exclude cancel button
587 // lock preview/edit/submit buttons on load, but exclude cancel button
597 var excludeCancelBtn = true;
588 var excludeCancelBtn = true;
598 this.setActionButtonsDisabled(true, excludeCancelBtn);
589 this.setActionButtonsDisabled(true, excludeCancelBtn);
599
590
600 // anonymous users don't have access to initialized CM instance
591 // anonymous users don't have access to initialized CM instance
601 if (this.cm !== undefined){
592 if (this.cm !== undefined){
602 this.cm.on('change', function(cMirror) {
593 this.cm.on('change', function(cMirror) {
603 if (cMirror.getValue() === "") {
594 if (cMirror.getValue() === "") {
604 self.setActionButtonsDisabled(true, excludeCancelBtn)
595 self.setActionButtonsDisabled(true, excludeCancelBtn)
605 } else {
596 } else {
606 self.setActionButtonsDisabled(false, excludeCancelBtn)
597 self.setActionButtonsDisabled(false, excludeCancelBtn)
607 }
598 }
608 });
599 });
609 }
600 }
610
601
611 $(this.editButton).on('click', function(e) {
602 $(this.editButton).on('click', function(e) {
612 e.preventDefault();
603 e.preventDefault();
613
604
614 $(self.previewButton).show();
605 $(self.previewButton).show();
615 $(self.previewContainer).hide();
606 $(self.previewContainer).hide();
616 $(self.editButton).hide();
607 $(self.editButton).hide();
617 $(self.editContainer).show();
608 $(self.editContainer).show();
618
609
619 });
610 });
620
611
621 $(this.previewButton).on('click', function(e) {
612 $(this.previewButton).on('click', function(e) {
622 e.preventDefault();
613 e.preventDefault();
623 var text = self.cm.getValue();
614 var text = self.cm.getValue();
624
615
625 if (text === "") {
616 if (text === "") {
626 return;
617 return;
627 }
618 }
628
619
629 var postData = {
620 var postData = {
630 'text': text,
621 'text': text,
631 'renderer': DEFAULT_RENDERER,
622 'renderer': DEFAULT_RENDERER,
632 'csrf_token': CSRF_TOKEN
623 'csrf_token': CSRF_TOKEN
633 };
624 };
634
625
635 // lock ALL buttons on preview
626 // lock ALL buttons on preview
636 self.setActionButtonsDisabled(true);
627 self.setActionButtonsDisabled(true);
637
628
638 $(self.previewBoxSelector).addClass('unloaded');
629 $(self.previewBoxSelector).addClass('unloaded');
639 $(self.previewBoxSelector).html(_gettext('Loading ...'));
630 $(self.previewBoxSelector).html(_gettext('Loading ...'));
640 $(self.editContainer).hide();
631 $(self.editContainer).hide();
641 $(self.previewContainer).show();
632 $(self.previewContainer).show();
642
633
643 // by default we reset state of comment preserving the text
634 // by default we reset state of comment preserving the text
644 var previewFailCallback = function(){
635 var previewFailCallback = function(){
645 self.resetCommentFormState(text)
636 self.resetCommentFormState(text)
646 };
637 };
647 self.submitAjaxPOST(
638 self.submitAjaxPOST(
648 self.previewUrl, postData, self.previewSuccessCallback, previewFailCallback);
639 self.previewUrl, postData, self.previewSuccessCallback, previewFailCallback);
649
640
650 });
641 });
651
642
652 $(this.submitForm).submit(function(e) {
643 $(this.submitForm).submit(function(e) {
653 e.preventDefault();
644 e.preventDefault();
654 var allowedToSubmit = self.isAllowedToSubmit();
645 var allowedToSubmit = self.isAllowedToSubmit();
655 if (!allowedToSubmit){
646 if (!allowedToSubmit){
656 return false;
647 return false;
657 }
648 }
658 self.handleFormSubmit();
649 self.handleFormSubmit();
659 });
650 });
660
651
661 }
652 }
662
653
663 return CommentForm;
654 return CommentForm;
664 })();
655 })();
General Comments 0
You need to be logged in to leave comments. Login now