##// END OF EJS Templates
comments: fixed reply-to from email links.
milka -
r4575:bd6d4156 stable
parent child Browse files
Show More
@@ -1,716 +1,716 b''
1 // # Copyright (C) 2010-2020 RhodeCode GmbH
1 // # Copyright (C) 2010-2020 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('repo_compare', url_data);
61 window.location = pyroutes.url('repo_compare', 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 container.show();
79 container.show();
80 if (!container.hasClass('loaded')) {
80 if (!container.hasClass('loaded')) {
81 $.ajax({url: url})
81 $.ajax({url: url})
82 .complete(function (data) {
82 .complete(function (data) {
83 var responseJSON = data.responseJSON;
83 var responseJSON = data.responseJSON;
84 container.addClass('loaded');
84 container.addClass('loaded');
85 container.html(responseJSON.size);
85 container.html(responseJSON.size);
86 callback(responseJSON.code_stats)
86 callback(responseJSON.code_stats)
87 })
87 })
88 .fail(function (data) {
88 .fail(function (data) {
89 console.log('failed to load repo stats');
89 console.log('failed to load repo stats');
90 });
90 });
91 }
91 }
92
92
93 };
93 };
94
94
95 var showRepoStats = function(target, data){
95 var showRepoStats = function(target, data){
96 var container = $('#' + target);
96 var container = $('#' + target);
97
97
98 if (container.hasClass('loaded')) {
98 if (container.hasClass('loaded')) {
99 return
99 return
100 }
100 }
101
101
102 var total = 0;
102 var total = 0;
103 var no_data = true;
103 var no_data = true;
104 var tbl = document.createElement('table');
104 var tbl = document.createElement('table');
105 tbl.setAttribute('class', 'trending_language_tbl rctable');
105 tbl.setAttribute('class', 'trending_language_tbl rctable');
106
106
107 $.each(data, function(key, val){
107 $.each(data, function(key, val){
108 total += val.count;
108 total += val.count;
109 });
109 });
110
110
111 var sortedStats = [];
111 var sortedStats = [];
112 for (var obj in data){
112 for (var obj in data){
113 sortedStats.push([obj, data[obj]])
113 sortedStats.push([obj, data[obj]])
114 }
114 }
115 var sortedData = sortedStats.sort(function (a, b) {
115 var sortedData = sortedStats.sort(function (a, b) {
116 return b[1].count - a[1].count
116 return b[1].count - a[1].count
117 });
117 });
118 var cnt = 0;
118 var cnt = 0;
119 $.each(sortedData, function(idx, val){
119 $.each(sortedData, function(idx, val){
120 cnt += 1;
120 cnt += 1;
121 no_data = false;
121 no_data = false;
122
122
123 var tr = document.createElement('tr');
123 var tr = document.createElement('tr');
124
124
125 var key = val[0];
125 var key = val[0];
126 var obj = {"desc": val[1].desc, "count": val[1].count};
126 var obj = {"desc": val[1].desc, "count": val[1].count};
127
127
128 // meta language names
128 // meta language names
129 var td1 = document.createElement('td');
129 var td1 = document.createElement('td');
130 var trending_language_label = document.createElement('div');
130 var trending_language_label = document.createElement('div');
131 trending_language_label.innerHTML = obj.desc;
131 trending_language_label.innerHTML = obj.desc;
132 td1.appendChild(trending_language_label);
132 td1.appendChild(trending_language_label);
133
133
134 // extensions
134 // extensions
135 var td2 = document.createElement('td');
135 var td2 = document.createElement('td');
136 var extension = document.createElement('div');
136 var extension = document.createElement('div');
137 extension.innerHTML = ".{0}".format(key)
137 extension.innerHTML = ".{0}".format(key)
138 td2.appendChild(extension);
138 td2.appendChild(extension);
139
139
140 // number of files
140 // number of files
141 var td3 = document.createElement('td');
141 var td3 = document.createElement('td');
142 var file_count = document.createElement('div');
142 var file_count = document.createElement('div');
143 var percentage_num = Math.round((obj.count / total * 100), 2);
143 var percentage_num = Math.round((obj.count / total * 100), 2);
144 var label = _ngettext('file', 'files', obj.count);
144 var label = _ngettext('file', 'files', obj.count);
145 file_count.innerHTML = "{0} {1} ({2}%)".format(obj.count, label, percentage_num) ;
145 file_count.innerHTML = "{0} {1} ({2}%)".format(obj.count, label, percentage_num) ;
146 td3.appendChild(file_count);
146 td3.appendChild(file_count);
147
147
148 // percentage
148 // percentage
149 var td4 = document.createElement('td');
149 var td4 = document.createElement('td');
150 td4.setAttribute("class", 'trending_language');
150 td4.setAttribute("class", 'trending_language');
151
151
152 var percentage = document.createElement('div');
152 var percentage = document.createElement('div');
153 percentage.setAttribute('class', 'lang-bar');
153 percentage.setAttribute('class', 'lang-bar');
154 percentage.innerHTML = "&nbsp;";
154 percentage.innerHTML = "&nbsp;";
155 percentage.style.width = percentage_num + '%';
155 percentage.style.width = percentage_num + '%';
156 td4.appendChild(percentage);
156 td4.appendChild(percentage);
157
157
158 tr.appendChild(td1);
158 tr.appendChild(td1);
159 tr.appendChild(td2);
159 tr.appendChild(td2);
160 tr.appendChild(td3);
160 tr.appendChild(td3);
161 tr.appendChild(td4);
161 tr.appendChild(td4);
162 tbl.appendChild(tr);
162 tbl.appendChild(tr);
163
163
164 });
164 });
165
165
166 $(container).html(tbl);
166 $(container).html(tbl);
167 $(container).addClass('loaded');
167 $(container).addClass('loaded');
168
168
169 $('#code_stats_show_more').on('click', function (e) {
169 $('#code_stats_show_more').on('click', function (e) {
170 e.preventDefault();
170 e.preventDefault();
171 $('.stats_hidden').each(function (idx) {
171 $('.stats_hidden').each(function (idx) {
172 $(this).css("display", "");
172 $(this).css("display", "");
173 });
173 });
174 $('#code_stats_show_more').hide();
174 $('#code_stats_show_more').hide();
175 });
175 });
176
176
177 };
177 };
178
178
179 // returns a node from given html;
179 // returns a node from given html;
180 var fromHTML = function(html){
180 var fromHTML = function(html){
181 var _html = document.createElement('element');
181 var _html = document.createElement('element');
182 _html.innerHTML = html;
182 _html.innerHTML = html;
183 return _html;
183 return _html;
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
207
208 var clipboardActivate = function() {
208 var clipboardActivate = function() {
209 /*
209 /*
210 *
210 *
211 * <i class="tooltip icon-plus clipboard-action" data-clipboard-text="${commit.raw_id}" title="${_('Copy the full commit id')}"></i>
211 * <i class="tooltip icon-plus clipboard-action" data-clipboard-text="${commit.raw_id}" title="${_('Copy the full commit id')}"></i>
212 * */
212 * */
213 var clipboard = new ClipboardJS('.clipboard-action');
213 var clipboard = new ClipboardJS('.clipboard-action');
214
214
215 clipboard.on('success', function(e) {
215 clipboard.on('success', function(e) {
216 var callback = function () {
216 var callback = function () {
217 $(e.trigger).animate({'opacity': 1.00}, 200)
217 $(e.trigger).animate({'opacity': 1.00}, 200)
218 };
218 };
219 $(e.trigger).animate({'opacity': 0.15}, 200, callback);
219 $(e.trigger).animate({'opacity': 0.15}, 200, callback);
220 e.clearSelection();
220 e.clearSelection();
221 });
221 });
222 };
222 };
223
223
224 var tooltipActivate = function () {
224 var tooltipActivate = function () {
225 var delay = 50;
225 var delay = 50;
226 var animation = 'fade';
226 var animation = 'fade';
227 var theme = 'tooltipster-shadow';
227 var theme = 'tooltipster-shadow';
228 var debug = false;
228 var debug = false;
229
229
230 $('.tooltip').tooltipster({
230 $('.tooltip').tooltipster({
231 debug: debug,
231 debug: debug,
232 theme: theme,
232 theme: theme,
233 animation: animation,
233 animation: animation,
234 delay: delay,
234 delay: delay,
235 contentCloning: true,
235 contentCloning: true,
236 contentAsHTML: true,
236 contentAsHTML: true,
237
237
238 functionBefore: function (instance, helper) {
238 functionBefore: function (instance, helper) {
239 var $origin = $(helper.origin);
239 var $origin = $(helper.origin);
240 var data = '<div style="white-space: pre-wrap">{0}</div>'.format(instance.content());
240 var data = '<div style="white-space: pre-wrap">{0}</div>'.format(instance.content());
241 instance.content(data);
241 instance.content(data);
242 }
242 }
243 });
243 });
244 var hovercardCache = {};
244 var hovercardCache = {};
245
245
246 var loadHoverCard = function (url, altHovercard, callback) {
246 var loadHoverCard = function (url, altHovercard, callback) {
247 var id = url;
247 var id = url;
248
248
249 if (hovercardCache[id] !== undefined) {
249 if (hovercardCache[id] !== undefined) {
250 callback(hovercardCache[id]);
250 callback(hovercardCache[id]);
251 return true;
251 return true;
252 }
252 }
253
253
254 hovercardCache[id] = undefined;
254 hovercardCache[id] = undefined;
255 $.get(url, function (data) {
255 $.get(url, function (data) {
256 hovercardCache[id] = data;
256 hovercardCache[id] = data;
257 callback(hovercardCache[id]);
257 callback(hovercardCache[id]);
258 return true;
258 return true;
259 }).fail(function (data, textStatus, errorThrown) {
259 }).fail(function (data, textStatus, errorThrown) {
260
260
261 if (parseInt(data.status) === 404) {
261 if (parseInt(data.status) === 404) {
262 var msg = "<p>{0}</p>".format(altHovercard || "No Data exists for this hovercard");
262 var msg = "<p>{0}</p>".format(altHovercard || "No Data exists for this hovercard");
263 } else {
263 } else {
264 var msg = "<p class='error-message'>Error while fetching hovercard.\nError code {0} ({1}).</p>".format(data.status,data.statusText);
264 var msg = "<p class='error-message'>Error while fetching hovercard.\nError code {0} ({1}).</p>".format(data.status,data.statusText);
265 }
265 }
266 callback(msg);
266 callback(msg);
267 return false
267 return false
268 });
268 });
269 };
269 };
270
270
271 $('.tooltip-hovercard').tooltipster({
271 $('.tooltip-hovercard').tooltipster({
272 debug: debug,
272 debug: debug,
273 theme: theme,
273 theme: theme,
274 animation: animation,
274 animation: animation,
275 delay: delay,
275 delay: delay,
276 interactive: true,
276 interactive: true,
277 contentCloning: true,
277 contentCloning: true,
278
278
279 trigger: 'custom',
279 trigger: 'custom',
280 triggerOpen: {
280 triggerOpen: {
281 mouseenter: true,
281 mouseenter: true,
282 },
282 },
283 triggerClose: {
283 triggerClose: {
284 mouseleave: true,
284 mouseleave: true,
285 originClick: true,
285 originClick: true,
286 touchleave: true
286 touchleave: true
287 },
287 },
288 content: _gettext('Loading...'),
288 content: _gettext('Loading...'),
289 contentAsHTML: true,
289 contentAsHTML: true,
290 updateAnimation: null,
290 updateAnimation: null,
291
291
292 functionBefore: function (instance, helper) {
292 functionBefore: function (instance, helper) {
293
293
294 var $origin = $(helper.origin);
294 var $origin = $(helper.origin);
295
295
296 // we set a variable so the data is only loaded once via Ajax, not every time the tooltip opens
296 // we set a variable so the data is only loaded once via Ajax, not every time the tooltip opens
297 if ($origin.data('loaded') !== true) {
297 if ($origin.data('loaded') !== true) {
298 var hovercardUrl = $origin.data('hovercardUrl');
298 var hovercardUrl = $origin.data('hovercardUrl');
299 var altHovercard = $origin.data('hovercardAlt');
299 var altHovercard = $origin.data('hovercardAlt');
300
300
301 if (hovercardUrl !== undefined && hovercardUrl !== "") {
301 if (hovercardUrl !== undefined && hovercardUrl !== "") {
302 var urlLoad = true;
302 var urlLoad = true;
303 if (hovercardUrl.substr(0, 12) === 'pyroutes.url') {
303 if (hovercardUrl.substr(0, 12) === 'pyroutes.url') {
304 hovercardUrl = eval(hovercardUrl)
304 hovercardUrl = eval(hovercardUrl)
305 } else if (hovercardUrl.substr(0, 11) === 'javascript:') {
305 } else if (hovercardUrl.substr(0, 11) === 'javascript:') {
306 var jsFunc = hovercardUrl.substr(11);
306 var jsFunc = hovercardUrl.substr(11);
307 urlLoad = false;
307 urlLoad = false;
308 loaded = true;
308 loaded = true;
309 instance.content(eval(jsFunc))
309 instance.content(eval(jsFunc))
310 }
310 }
311
311
312 if (urlLoad) {
312 if (urlLoad) {
313 var loaded = loadHoverCard(hovercardUrl, altHovercard, function (data) {
313 var loaded = loadHoverCard(hovercardUrl, altHovercard, function (data) {
314 instance.content(data);
314 instance.content(data);
315 })
315 })
316 }
316 }
317
317
318 } else {
318 } else {
319 if ($origin.data('hovercardAltHtml')) {
319 if ($origin.data('hovercardAltHtml')) {
320 var data = atob($origin.data('hovercardAltHtml'));
320 var data = atob($origin.data('hovercardAltHtml'));
321 } else {
321 } else {
322 var data = '<div style="white-space: pre-wrap">{0}</div>'.format(altHovercard)
322 var data = '<div style="white-space: pre-wrap">{0}</div>'.format(altHovercard)
323 }
323 }
324 var loaded = true;
324 var loaded = true;
325 instance.content(data);
325 instance.content(data);
326 }
326 }
327
327
328 // to remember that the data has been loaded
328 // to remember that the data has been loaded
329 $origin.data('loaded', loaded);
329 $origin.data('loaded', loaded);
330 }
330 }
331 }
331 }
332 })
332 })
333 };
333 };
334
334
335 // Formatting values in a Select2 dropdown of commit references
335 // Formatting values in a Select2 dropdown of commit references
336 var formatSelect2SelectionRefs = function(commit_ref){
336 var formatSelect2SelectionRefs = function(commit_ref){
337 var tmpl = '';
337 var tmpl = '';
338 if (!commit_ref.text || commit_ref.type === 'sha'){
338 if (!commit_ref.text || commit_ref.type === 'sha'){
339 return commit_ref.text;
339 return commit_ref.text;
340 }
340 }
341 if (commit_ref.type === 'branch'){
341 if (commit_ref.type === 'branch'){
342 tmpl = tmpl.concat('<i class="icon-branch"></i> ');
342 tmpl = tmpl.concat('<i class="icon-branch"></i> ');
343 } else if (commit_ref.type === 'tag'){
343 } else if (commit_ref.type === 'tag'){
344 tmpl = tmpl.concat('<i class="icon-tag"></i> ');
344 tmpl = tmpl.concat('<i class="icon-tag"></i> ');
345 } else if (commit_ref.type === 'book'){
345 } else if (commit_ref.type === 'book'){
346 tmpl = tmpl.concat('<i class="icon-bookmark"></i> ');
346 tmpl = tmpl.concat('<i class="icon-bookmark"></i> ');
347 }
347 }
348 return tmpl.concat(escapeHtml(commit_ref.text));
348 return tmpl.concat(escapeHtml(commit_ref.text));
349 };
349 };
350
350
351 // takes a given html element and scrolls it down offset pixels
351 // takes a given html element and scrolls it down offset pixels
352 function offsetScroll(element, offset) {
352 function offsetScroll(element, offset) {
353 setTimeout(function() {
353 setTimeout(function() {
354 var location = element.offset().top;
354 var location = element.offset().top;
355 // some browsers use body, some use html
355 // some browsers use body, some use html
356 $('html, body').animate({ scrollTop: (location - offset) });
356 $('html, body').animate({ scrollTop: (location - offset) });
357 }, 100);
357 }, 100);
358 }
358 }
359
359
360 // scroll an element `percent`% from the top of page in `time` ms
360 // scroll an element `percent`% from the top of page in `time` ms
361 function scrollToElement(element, percent, time) {
361 function scrollToElement(element, percent, time) {
362 percent = (percent === undefined ? 25 : percent);
362 percent = (percent === undefined ? 25 : percent);
363 time = (time === undefined ? 100 : time);
363 time = (time === undefined ? 100 : time);
364
364
365 var $element = $(element);
365 var $element = $(element);
366 if ($element.length == 0) {
366 if ($element.length == 0) {
367 throw('Cannot scroll to {0}'.format(element))
367 throw('Cannot scroll to {0}'.format(element))
368 }
368 }
369 var elOffset = $element.offset().top;
369 var elOffset = $element.offset().top;
370 var elHeight = $element.height();
370 var elHeight = $element.height();
371 var windowHeight = $(window).height();
371 var windowHeight = $(window).height();
372 var offset = elOffset;
372 var offset = elOffset;
373 if (elHeight < windowHeight) {
373 if (elHeight < windowHeight) {
374 offset = elOffset - ((windowHeight / (100 / percent)) - (elHeight / 2));
374 offset = elOffset - ((windowHeight / (100 / percent)) - (elHeight / 2));
375 }
375 }
376 setTimeout(function() {
376 setTimeout(function() {
377 $('html, body').animate({ scrollTop: offset});
377 $('html, body').animate({ scrollTop: offset});
378 }, time);
378 }, time);
379 }
379 }
380
380
381 /**
381 /**
382 * global hooks after DOM is loaded
382 * global hooks after DOM is loaded
383 */
383 */
384 $(document).ready(function() {
384 $(document).ready(function() {
385 firefoxAnchorFix();
385 firefoxAnchorFix();
386
386
387 $('.navigation a.menulink').on('click', function(e){
387 $('.navigation a.menulink').on('click', function(e){
388 var menuitem = $(this).parent('li');
388 var menuitem = $(this).parent('li');
389 if (menuitem.hasClass('open')) {
389 if (menuitem.hasClass('open')) {
390 menuitem.removeClass('open');
390 menuitem.removeClass('open');
391 } else {
391 } else {
392 menuitem.addClass('open');
392 menuitem.addClass('open');
393 $(document).on('click', function(event) {
393 $(document).on('click', function(event) {
394 if (!$(event.target).closest(menuitem).length) {
394 if (!$(event.target).closest(menuitem).length) {
395 menuitem.removeClass('open');
395 menuitem.removeClass('open');
396 }
396 }
397 });
397 });
398 }
398 }
399 });
399 });
400
400
401 $('body').on('click', '.cb-lineno a', function(event) {
401 $('body').on('click', '.cb-lineno a', function(event) {
402 function sortNumber(a,b) {
402 function sortNumber(a,b) {
403 return a - b;
403 return a - b;
404 }
404 }
405
405
406 var lineNo = $(this).data('lineNo');
406 var lineNo = $(this).data('lineNo');
407 var lineName = $(this).attr('name');
407 var lineName = $(this).attr('name');
408
408
409 if (lineNo) {
409 if (lineNo) {
410 var prevLine = $('.cb-line-selected a').data('lineNo');
410 var prevLine = $('.cb-line-selected a').data('lineNo');
411
411
412 // on shift, we do a range selection, if we got previous line
412 // on shift, we do a range selection, if we got previous line
413 if (event.shiftKey && prevLine !== undefined) {
413 if (event.shiftKey && prevLine !== undefined) {
414 var prevLine = parseInt(prevLine);
414 var prevLine = parseInt(prevLine);
415 var nextLine = parseInt(lineNo);
415 var nextLine = parseInt(lineNo);
416 var pos = [prevLine, nextLine].sort(sortNumber);
416 var pos = [prevLine, nextLine].sort(sortNumber);
417 var anchor = '#L{0}-{1}'.format(pos[0], pos[1]);
417 var anchor = '#L{0}-{1}'.format(pos[0], pos[1]);
418
418
419 // single click
419 // single click
420 } else {
420 } else {
421 var nextLine = parseInt(lineNo);
421 var nextLine = parseInt(lineNo);
422 var pos = [nextLine, nextLine];
422 var pos = [nextLine, nextLine];
423 var anchor = '#L{0}'.format(pos[0]);
423 var anchor = '#L{0}'.format(pos[0]);
424
424
425 }
425 }
426 // highlight
426 // highlight
427 var range = [];
427 var range = [];
428 for (var i = pos[0]; i <= pos[1]; i++) {
428 for (var i = pos[0]; i <= pos[1]; i++) {
429 range.push(i);
429 range.push(i);
430 }
430 }
431 // clear old selected lines
431 // clear old selected lines
432 $('.cb-line-selected').removeClass('cb-line-selected');
432 $('.cb-line-selected').removeClass('cb-line-selected');
433
433
434 $.each(range, function (i, lineNo) {
434 $.each(range, function (i, lineNo) {
435 var line_td = $('td.cb-lineno#L' + lineNo);
435 var line_td = $('td.cb-lineno#L' + lineNo);
436
436
437 if (line_td.length) {
437 if (line_td.length) {
438 line_td.addClass('cb-line-selected'); // line number td
438 line_td.addClass('cb-line-selected'); // line number td
439 line_td.prev().addClass('cb-line-selected'); // line data
439 line_td.prev().addClass('cb-line-selected'); // line data
440 line_td.next().addClass('cb-line-selected'); // line content
440 line_td.next().addClass('cb-line-selected'); // line content
441 }
441 }
442 });
442 });
443
443
444 } else if (lineName !== undefined) { // lineName only occurs in diffs
444 } else if (lineName !== undefined) { // lineName only occurs in diffs
445 // clear old selected lines
445 // clear old selected lines
446 $('td.cb-line-selected').removeClass('cb-line-selected');
446 $('td.cb-line-selected').removeClass('cb-line-selected');
447 var anchor = '#{0}'.format(lineName);
447 var anchor = '#{0}'.format(lineName);
448 var diffmode = templateContext.session_attrs.diffmode || "sideside";
448 var diffmode = templateContext.session_attrs.diffmode || "sideside";
449
449
450 if (diffmode === "unified") {
450 if (diffmode === "unified") {
451 $(this).closest('tr').find('td').addClass('cb-line-selected');
451 $(this).closest('tr').find('td').addClass('cb-line-selected');
452 } else {
452 } else {
453 var activeTd = $(this).closest('td');
453 var activeTd = $(this).closest('td');
454 activeTd.addClass('cb-line-selected');
454 activeTd.addClass('cb-line-selected');
455 activeTd.next('td').addClass('cb-line-selected');
455 activeTd.next('td').addClass('cb-line-selected');
456 }
456 }
457
457
458 }
458 }
459
459
460 // Replace URL without jumping to it if browser supports.
460 // Replace URL without jumping to it if browser supports.
461 // Default otherwise
461 // Default otherwise
462 if (history.pushState && anchor !== undefined) {
462 if (history.pushState && anchor !== undefined) {
463 var new_location = location.href.rstrip('#');
463 var new_location = location.href.rstrip('#');
464 if (location.hash) {
464 if (location.hash) {
465 // location without hash
465 // location without hash
466 new_location = new_location.replace(location.hash, "");
466 new_location = new_location.replace(location.hash, "");
467 }
467 }
468
468
469 // Make new anchor url
469 // Make new anchor url
470 new_location = new_location + anchor;
470 new_location = new_location + anchor;
471 history.pushState(true, document.title, new_location);
471 history.pushState(true, document.title, new_location);
472
472
473 return false;
473 return false;
474 }
474 }
475
475
476 });
476 });
477
477
478 $('.collapse_file').on('click', function(e) {
478 $('.collapse_file').on('click', function(e) {
479 e.stopPropagation();
479 e.stopPropagation();
480 if ($(e.target).is('a')) { return; }
480 if ($(e.target).is('a')) { return; }
481 var node = $(e.delegateTarget).first();
481 var node = $(e.delegateTarget).first();
482 var icon = $($(node.children().first()).children().first());
482 var icon = $($(node.children().first()).children().first());
483 var id = node.attr('fid');
483 var id = node.attr('fid');
484 var target = $('#'+id);
484 var target = $('#'+id);
485 var tr = $('#tr_'+id);
485 var tr = $('#tr_'+id);
486 var diff = $('#diff_'+id);
486 var diff = $('#diff_'+id);
487 if(node.hasClass('expand_file')){
487 if(node.hasClass('expand_file')){
488 node.removeClass('expand_file');
488 node.removeClass('expand_file');
489 icon.removeClass('expand_file_icon');
489 icon.removeClass('expand_file_icon');
490 node.addClass('collapse_file');
490 node.addClass('collapse_file');
491 icon.addClass('collapse_file_icon');
491 icon.addClass('collapse_file_icon');
492 diff.show();
492 diff.show();
493 tr.show();
493 tr.show();
494 target.show();
494 target.show();
495 } else {
495 } else {
496 node.removeClass('collapse_file');
496 node.removeClass('collapse_file');
497 icon.removeClass('collapse_file_icon');
497 icon.removeClass('collapse_file_icon');
498 node.addClass('expand_file');
498 node.addClass('expand_file');
499 icon.addClass('expand_file_icon');
499 icon.addClass('expand_file_icon');
500 diff.hide();
500 diff.hide();
501 tr.hide();
501 tr.hide();
502 target.hide();
502 target.hide();
503 }
503 }
504 });
504 });
505
505
506 $('#expand_all_files').click(function() {
506 $('#expand_all_files').click(function() {
507 $('.expand_file').each(function() {
507 $('.expand_file').each(function() {
508 var node = $(this);
508 var node = $(this);
509 var icon = $($(node.children().first()).children().first());
509 var icon = $($(node.children().first()).children().first());
510 var id = $(this).attr('fid');
510 var id = $(this).attr('fid');
511 var target = $('#'+id);
511 var target = $('#'+id);
512 var tr = $('#tr_'+id);
512 var tr = $('#tr_'+id);
513 var diff = $('#diff_'+id);
513 var diff = $('#diff_'+id);
514 node.removeClass('expand_file');
514 node.removeClass('expand_file');
515 icon.removeClass('expand_file_icon');
515 icon.removeClass('expand_file_icon');
516 node.addClass('collapse_file');
516 node.addClass('collapse_file');
517 icon.addClass('collapse_file_icon');
517 icon.addClass('collapse_file_icon');
518 diff.show();
518 diff.show();
519 tr.show();
519 tr.show();
520 target.show();
520 target.show();
521 });
521 });
522 });
522 });
523
523
524 $('#collapse_all_files').click(function() {
524 $('#collapse_all_files').click(function() {
525 $('.collapse_file').each(function() {
525 $('.collapse_file').each(function() {
526 var node = $(this);
526 var node = $(this);
527 var icon = $($(node.children().first()).children().first());
527 var icon = $($(node.children().first()).children().first());
528 var id = $(this).attr('fid');
528 var id = $(this).attr('fid');
529 var target = $('#'+id);
529 var target = $('#'+id);
530 var tr = $('#tr_'+id);
530 var tr = $('#tr_'+id);
531 var diff = $('#diff_'+id);
531 var diff = $('#diff_'+id);
532 node.removeClass('collapse_file');
532 node.removeClass('collapse_file');
533 icon.removeClass('collapse_file_icon');
533 icon.removeClass('collapse_file_icon');
534 node.addClass('expand_file');
534 node.addClass('expand_file');
535 icon.addClass('expand_file_icon');
535 icon.addClass('expand_file_icon');
536 diff.hide();
536 diff.hide();
537 tr.hide();
537 tr.hide();
538 target.hide();
538 target.hide();
539 });
539 });
540 });
540 });
541
541
542 // Mouse over behavior for comments and line selection
542 // Mouse over behavior for comments and line selection
543
543
544 // Select the line that comes from the url anchor
544 // Select the line that comes from the url anchor
545 // At the time of development, Chrome didn't seem to support jquery's :target
545 // At the time of development, Chrome didn't seem to support jquery's :target
546 // element, so I had to scroll manually
546 // element, so I had to scroll manually
547
547
548 if (location.hash) {
548 if (location.hash) {
549 var result = splitDelimitedHash(location.hash);
549 var result = splitDelimitedHash(location.hash);
550
550
551 var loc = result.loc;
551 var loc = result.loc;
552
552
553 if (loc.length > 1) {
553 if (loc.length > 1) {
554
554
555 var highlightable_line_tds = [];
555 var highlightable_line_tds = [];
556
556
557 // source code line format
557 // source code line format
558 var page_highlights = loc.substring(loc.indexOf('#') + 1).split('L');
558 var page_highlights = loc.substring(loc.indexOf('#') + 1).split('L');
559
559
560 // multi-line HL, for files
560 // multi-line HL, for files
561 if (page_highlights.length > 1) {
561 if (page_highlights.length > 1) {
562 var highlight_ranges = page_highlights[1].split(",");
562 var highlight_ranges = page_highlights[1].split(",");
563 var h_lines = [];
563 var h_lines = [];
564 for (var pos in highlight_ranges) {
564 for (var pos in highlight_ranges) {
565 var _range = highlight_ranges[pos].split('-');
565 var _range = highlight_ranges[pos].split('-');
566 if (_range.length === 2) {
566 if (_range.length === 2) {
567 var start = parseInt(_range[0]);
567 var start = parseInt(_range[0]);
568 var end = parseInt(_range[1]);
568 var end = parseInt(_range[1]);
569 if (start < end) {
569 if (start < end) {
570 for (var i = start; i <= end; i++) {
570 for (var i = start; i <= end; i++) {
571 h_lines.push(i);
571 h_lines.push(i);
572 }
572 }
573 }
573 }
574 } else {
574 } else {
575 h_lines.push(parseInt(highlight_ranges[pos]));
575 h_lines.push(parseInt(highlight_ranges[pos]));
576 }
576 }
577 }
577 }
578 for (pos in h_lines) {
578 for (pos in h_lines) {
579 var line_td = $('td.cb-lineno#L' + h_lines[pos]);
579 var line_td = $('td.cb-lineno#L' + h_lines[pos]);
580 if (line_td.length) {
580 if (line_td.length) {
581 highlightable_line_tds.push(line_td);
581 highlightable_line_tds.push(line_td);
582 }
582 }
583 }
583 }
584 }
584 }
585
585
586 // now check a direct id reference of line in diff / pull-request page)
586 // now check a direct id reference of line in diff / pull-request page)
587 if ($(loc).length > 0 && $(loc).hasClass('cb-lineno')) {
587 if ($(loc).length > 0 && $(loc).hasClass('cb-lineno')) {
588 highlightable_line_tds.push($(loc));
588 highlightable_line_tds.push($(loc));
589 }
589 }
590
590
591 // mark diff lines as selected
591 // mark diff lines as selected
592 $.each(highlightable_line_tds, function (i, $td) {
592 $.each(highlightable_line_tds, function (i, $td) {
593 $td.addClass('cb-line-selected'); // line number td
593 $td.addClass('cb-line-selected'); // line number td
594 $td.prev().addClass('cb-line-selected'); // line data
594 $td.prev().addClass('cb-line-selected'); // line data
595 $td.next().addClass('cb-line-selected'); // line content
595 $td.next().addClass('cb-line-selected'); // line content
596 });
596 });
597
597
598 if (highlightable_line_tds.length > 0) {
598 if (highlightable_line_tds.length > 0) {
599 var $first_line_td = highlightable_line_tds[0];
599 var $first_line_td = highlightable_line_tds[0];
600 scrollToElement($first_line_td);
600 scrollToElement($first_line_td);
601 $.Topic('/ui/plugins/code/anchor_focus').prepareOrPublish({
601 $.Topic('/ui/plugins/code/anchor_focus').prepareOrPublish({
602 td: $first_line_td,
602 td: $first_line_td,
603 remainder: result.remainder
603 remainder: result.remainder
604 });
604 });
605 } else {
605 } else {
606 // case for direct anchor to comments
606 // case for direct anchor to comments
607 var $line = $(loc);
607 var $line = $(loc);
608
608
609 if ($line.hasClass('comment-general')) {
609 if ($line.hasClass('comment-general')) {
610 $line.show();
610 $line.show();
611 } else if ($line.hasClass('comment-inline')) {
611 } else if ($line.hasClass('comment-inline')) {
612 $line.show();
612 $line.show();
613 var $cb = $line.closest('.cb');
613 var $cb = $line.closest('.cb');
614 $cb.removeClass('cb-collapsed')
614 $cb.removeClass('cb-collapsed')
615 }
615 }
616 if ($line.length > 0) {
616 if ($line.length > 0) {
617 $line.addClass('comment-selected-hl');
617 $line.addClass('comment-selected-hl');
618 offsetScroll($line, 70);
618 offsetScroll($line, 70);
619 }
619 }
620 if (!$line.hasClass('comment-outdated') && result.remainder === '/ReplyToComment') {
620 if (!$line.hasClass('comment-outdated') && result.remainder === '/ReplyToComment') {
621 $line.nextAll('.cb-comment-add-button').trigger('click');
621 $line.parent().find('.cb-comment-add-button').trigger('click');
622 }
622 }
623 }
623 }
624
624
625 }
625 }
626 }
626 }
627 collapsableContent();
627 collapsableContent();
628 });
628 });
629
629
630 var feedLifetimeOptions = function(query, initialData){
630 var feedLifetimeOptions = function(query, initialData){
631 var data = {results: []};
631 var data = {results: []};
632 var isQuery = typeof query.term !== 'undefined';
632 var isQuery = typeof query.term !== 'undefined';
633
633
634 var section = _gettext('Lifetime');
634 var section = _gettext('Lifetime');
635 var children = [];
635 var children = [];
636
636
637 //filter results
637 //filter results
638 $.each(initialData.results, function(idx, value) {
638 $.each(initialData.results, function(idx, value) {
639
639
640 if (!isQuery || query.term.length === 0 || value.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
640 if (!isQuery || query.term.length === 0 || value.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
641 children.push({
641 children.push({
642 'id': this.id,
642 'id': this.id,
643 'text': this.text
643 'text': this.text
644 })
644 })
645 }
645 }
646
646
647 });
647 });
648 data.results.push({
648 data.results.push({
649 'text': section,
649 'text': section,
650 'children': children
650 'children': children
651 });
651 });
652
652
653 if (isQuery) {
653 if (isQuery) {
654
654
655 var now = moment.utc();
655 var now = moment.utc();
656
656
657 var parseQuery = function(entry, now){
657 var parseQuery = function(entry, now){
658 var fmt = 'DD/MM/YYYY H:mm';
658 var fmt = 'DD/MM/YYYY H:mm';
659 var parsed = moment.utc(entry, fmt);
659 var parsed = moment.utc(entry, fmt);
660 var diffInMin = parsed.diff(now, 'minutes');
660 var diffInMin = parsed.diff(now, 'minutes');
661
661
662 if (diffInMin > 0){
662 if (diffInMin > 0){
663 return {
663 return {
664 id: diffInMin,
664 id: diffInMin,
665 text: parsed.format(fmt)
665 text: parsed.format(fmt)
666 }
666 }
667 } else {
667 } else {
668 return {
668 return {
669 id: undefined,
669 id: undefined,
670 text: parsed.format('DD/MM/YYYY') + ' ' + _gettext('date not in future')
670 text: parsed.format('DD/MM/YYYY') + ' ' + _gettext('date not in future')
671 }
671 }
672 }
672 }
673
673
674
674
675 };
675 };
676
676
677 data.results.push({
677 data.results.push({
678 'text': _gettext('Specified expiration date'),
678 'text': _gettext('Specified expiration date'),
679 'children': [{
679 'children': [{
680 'id': parseQuery(query.term, now).id,
680 'id': parseQuery(query.term, now).id,
681 'text': parseQuery(query.term, now).text
681 'text': parseQuery(query.term, now).text
682 }]
682 }]
683 });
683 });
684 }
684 }
685
685
686 query.callback(data);
686 query.callback(data);
687 };
687 };
688
688
689 /*
689 /*
690 * Retrievew via templateContext.session_attrs.key
690 * Retrievew via templateContext.session_attrs.key
691 * */
691 * */
692 var storeUserSessionAttr = function (key, val) {
692 var storeUserSessionAttr = function (key, val) {
693
693
694 var postData = {
694 var postData = {
695 'key': key,
695 'key': key,
696 'val': val,
696 'val': val,
697 'csrf_token': CSRF_TOKEN
697 'csrf_token': CSRF_TOKEN
698 };
698 };
699
699
700 var success = function(o) {
700 var success = function(o) {
701 return true
701 return true
702 };
702 };
703
703
704 ajaxPOST(pyroutes.url('store_user_session_value'), postData, success);
704 ajaxPOST(pyroutes.url('store_user_session_value'), postData, success);
705 return false;
705 return false;
706 };
706 };
707
707
708
708
709 var getUserSessionAttr = function(key) {
709 var getUserSessionAttr = function(key) {
710 var storeKey = templateContext.session_attrs;
710 var storeKey = templateContext.session_attrs;
711 var val = storeKey[key]
711 var val = storeKey[key]
712 if (val !== undefined) {
712 if (val !== undefined) {
713 return JSON.parse(val)
713 return JSON.parse(val)
714 }
714 }
715 return null
715 return null
716 }
716 }
General Comments 0
You need to be logged in to leave comments. Login now