##// END OF EJS Templates
frontend: use splitDelimitedHash when dealing with hash parsing
ergo -
r789:1deb9d88 default
parent child Browse files
Show More
@@ -1,394 +1,388 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 = _gettext('Show more');
162 lnk.innerHTML = _gettext('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 var location = element.offset().top;
226 var location = element.offset().top;
227 // some browsers use body, some use html
227 // some browsers use body, some use html
228 $('html, body').animate({ scrollTop: (location - offset) });
228 $('html, body').animate({ scrollTop: (location - offset) });
229 }, 100);
229 }, 100);
230 }
230 }
231
231
232 /**
232 /**
233 * global hooks after DOM is loaded
233 * global hooks after DOM is loaded
234 */
234 */
235 $(document).ready(function() {
235 $(document).ready(function() {
236 firefoxAnchorFix();
236 firefoxAnchorFix();
237
237
238 $('.navigation a.menulink').on('click', function(e){
238 $('.navigation a.menulink').on('click', function(e){
239 var menuitem = $(this).parent('li');
239 var menuitem = $(this).parent('li');
240 if (menuitem.hasClass('open')) {
240 if (menuitem.hasClass('open')) {
241 menuitem.removeClass('open');
241 menuitem.removeClass('open');
242 } else {
242 } else {
243 menuitem.addClass('open');
243 menuitem.addClass('open');
244 $(document).on('click', function(event) {
244 $(document).on('click', function(event) {
245 if (!$(event.target).closest(menuitem).length) {
245 if (!$(event.target).closest(menuitem).length) {
246 menuitem.removeClass('open');
246 menuitem.removeClass('open');
247 }
247 }
248 });
248 });
249 }
249 }
250 });
250 });
251 $('.compare_view_files').on(
251 $('.compare_view_files').on(
252 'mouseenter mouseleave', 'tr.line .lineno a',function(event) {
252 'mouseenter mouseleave', 'tr.line .lineno a',function(event) {
253 if (event.type === "mouseenter") {
253 if (event.type === "mouseenter") {
254 $(this).parents('tr.line').addClass('hover');
254 $(this).parents('tr.line').addClass('hover');
255 } else {
255 } else {
256 $(this).parents('tr.line').removeClass('hover');
256 $(this).parents('tr.line').removeClass('hover');
257 }
257 }
258 });
258 });
259
259
260 $('.compare_view_files').on(
260 $('.compare_view_files').on(
261 'mouseenter mouseleave', 'tr.line .add-comment-line a',function(event){
261 'mouseenter mouseleave', 'tr.line .add-comment-line a',function(event){
262 if (event.type === "mouseenter") {
262 if (event.type === "mouseenter") {
263 $(this).parents('tr.line').addClass('commenting');
263 $(this).parents('tr.line').addClass('commenting');
264 } else {
264 } else {
265 $(this).parents('tr.line').removeClass('commenting');
265 $(this).parents('tr.line').removeClass('commenting');
266 }
266 }
267 });
267 });
268
268
269 $('.compare_view_files').on(
269 $('.compare_view_files').on(
270 'click', 'tr.line .lineno a',function(event) {
270 'click', 'tr.line .lineno a',function(event) {
271 if ($(this).text() != ""){
271 if ($(this).text() != ""){
272 $('tr.line').removeClass('selected');
272 $('tr.line').removeClass('selected');
273 $(this).parents("tr.line").addClass('selected');
273 $(this).parents("tr.line").addClass('selected');
274
274
275 // Replace URL without jumping to it if browser supports.
275 // Replace URL without jumping to it if browser supports.
276 // Default otherwise
276 // Default otherwise
277 if (history.pushState) {
277 if (history.pushState) {
278 var new_location = location.href;
278 var new_location = location.href;
279 if (location.hash){
279 if (location.hash){
280 new_location = new_location.replace(location.hash, "");
280 new_location = new_location.replace(location.hash, "");
281 }
281 }
282
282
283 // Make new anchor url
283 // Make new anchor url
284 var new_location = new_location+$(this).attr('href');
284 var new_location = new_location+$(this).attr('href');
285 history.pushState(true, document.title, new_location);
285 history.pushState(true, document.title, new_location);
286
286
287 return false;
287 return false;
288 }
288 }
289 }
289 }
290 });
290 });
291
291
292 $('.compare_view_files').on(
292 $('.compare_view_files').on(
293 'click', 'tr.line .add-comment-line a',function(event) {
293 'click', 'tr.line .add-comment-line a',function(event) {
294 var tr = $(event.currentTarget).parents('tr.line')[0];
294 var tr = $(event.currentTarget).parents('tr.line')[0];
295 injectInlineForm(tr);
295 injectInlineForm(tr);
296 return false;
296 return false;
297 });
297 });
298
298
299 $('.collapse_file').on('click', function(e) {
299 $('.collapse_file').on('click', function(e) {
300 e.stopPropagation();
300 e.stopPropagation();
301 if ($(e.target).is('a')) { return; }
301 if ($(e.target).is('a')) { return; }
302 var node = $(e.delegateTarget).first();
302 var node = $(e.delegateTarget).first();
303 var icon = $($(node.children().first()).children().first());
303 var icon = $($(node.children().first()).children().first());
304 var id = node.attr('fid');
304 var id = node.attr('fid');
305 var target = $('#'+id);
305 var target = $('#'+id);
306 var tr = $('#tr_'+id);
306 var tr = $('#tr_'+id);
307 var diff = $('#diff_'+id);
307 var diff = $('#diff_'+id);
308 if(node.hasClass('expand_file')){
308 if(node.hasClass('expand_file')){
309 node.removeClass('expand_file');
309 node.removeClass('expand_file');
310 icon.removeClass('expand_file_icon');
310 icon.removeClass('expand_file_icon');
311 node.addClass('collapse_file');
311 node.addClass('collapse_file');
312 icon.addClass('collapse_file_icon');
312 icon.addClass('collapse_file_icon');
313 diff.show();
313 diff.show();
314 tr.show();
314 tr.show();
315 target.show();
315 target.show();
316 } else {
316 } else {
317 node.removeClass('collapse_file');
317 node.removeClass('collapse_file');
318 icon.removeClass('collapse_file_icon');
318 icon.removeClass('collapse_file_icon');
319 node.addClass('expand_file');
319 node.addClass('expand_file');
320 icon.addClass('expand_file_icon');
320 icon.addClass('expand_file_icon');
321 diff.hide();
321 diff.hide();
322 tr.hide();
322 tr.hide();
323 target.hide();
323 target.hide();
324 }
324 }
325 });
325 });
326
326
327 $('#expand_all_files').click(function() {
327 $('#expand_all_files').click(function() {
328 $('.expand_file').each(function() {
328 $('.expand_file').each(function() {
329 var node = $(this);
329 var node = $(this);
330 var icon = $($(node.children().first()).children().first());
330 var icon = $($(node.children().first()).children().first());
331 var id = $(this).attr('fid');
331 var id = $(this).attr('fid');
332 var target = $('#'+id);
332 var target = $('#'+id);
333 var tr = $('#tr_'+id);
333 var tr = $('#tr_'+id);
334 var diff = $('#diff_'+id);
334 var diff = $('#diff_'+id);
335 node.removeClass('expand_file');
335 node.removeClass('expand_file');
336 icon.removeClass('expand_file_icon');
336 icon.removeClass('expand_file_icon');
337 node.addClass('collapse_file');
337 node.addClass('collapse_file');
338 icon.addClass('collapse_file_icon');
338 icon.addClass('collapse_file_icon');
339 diff.show();
339 diff.show();
340 tr.show();
340 tr.show();
341 target.show();
341 target.show();
342 });
342 });
343 });
343 });
344
344
345 $('#collapse_all_files').click(function() {
345 $('#collapse_all_files').click(function() {
346 $('.collapse_file').each(function() {
346 $('.collapse_file').each(function() {
347 var node = $(this);
347 var node = $(this);
348 var icon = $($(node.children().first()).children().first());
348 var icon = $($(node.children().first()).children().first());
349 var id = $(this).attr('fid');
349 var id = $(this).attr('fid');
350 var target = $('#'+id);
350 var target = $('#'+id);
351 var tr = $('#tr_'+id);
351 var tr = $('#tr_'+id);
352 var diff = $('#diff_'+id);
352 var diff = $('#diff_'+id);
353 node.removeClass('collapse_file');
353 node.removeClass('collapse_file');
354 icon.removeClass('collapse_file_icon');
354 icon.removeClass('collapse_file_icon');
355 node.addClass('expand_file');
355 node.addClass('expand_file');
356 icon.addClass('expand_file_icon');
356 icon.addClass('expand_file_icon');
357 diff.hide();
357 diff.hide();
358 tr.hide();
358 tr.hide();
359 target.hide();
359 target.hide();
360 });
360 });
361 });
361 });
362
362
363 // Mouse over behavior for comments and line selection
363 // Mouse over behavior for comments and line selection
364
364
365 // Select the line that comes from the url anchor
365 // Select the line that comes from the url anchor
366 // At the time of development, Chrome didn't seem to support jquery's :target
366 // At the time of development, Chrome didn't seem to support jquery's :target
367 // element, so I had to scroll manually
367 // element, so I had to scroll manually
368 if (location.hash) {
368 if (location.hash) {
369 var splitIx = location.hash.indexOf('/?/');
369 var result = splitDelimitedHash(location.hash);
370 if (splitIx !== -1){
370 var loc = result.loc;
371 var loc = location.hash.slice(0, splitIx);
371 var remainder = result.remainder;
372 var remainder = location.hash.slice(splitIx + 2);
373 }
374 else{
375 var loc = location.hash;
376 var remainder = null;
377 }
378 if (loc.length > 1){
372 if (loc.length > 1){
379 var lineno = $(loc+'.lineno');
373 var lineno = $(loc+'.lineno');
380 if (lineno.length > 0){
374 if (lineno.length > 0){
381 var tr = lineno.parents('tr.line');
375 var tr = lineno.parents('tr.line');
382 tr.addClass('selected');
376 tr.addClass('selected');
383
377
384 tr[0].scrollIntoView();
378 tr[0].scrollIntoView();
385
379
386 $.Topic('/ui/plugins/code/anchor_focus').prepareOrPublish({
380 $.Topic('/ui/plugins/code/anchor_focus').prepareOrPublish({
387 tr:tr,
381 tr:tr,
388 remainder:remainder});
382 remainder:remainder});
389 }
383 }
390 }
384 }
391 }
385 }
392
386
393 collapsableContent();
387 collapsableContent();
394 });
388 });
@@ -1,151 +1,174 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 * INJECT .format function into String
20 * INJECT .format function into String
21 * Usage: "My name is {0} {1}".format("Johny","Bravo")
21 * Usage: "My name is {0} {1}".format("Johny","Bravo")
22 * Return "My name is Johny Bravo"
22 * Return "My name is Johny Bravo"
23 * Inspired by https://gist.github.com/1049426
23 * Inspired by https://gist.github.com/1049426
24 */
24 */
25 String.prototype.format = function() {
25 String.prototype.format = function() {
26
26
27 function format() {
27 function format() {
28 var str = this;
28 var str = this;
29 var len = arguments.length+1;
29 var len = arguments.length+1;
30 var safe = undefined;
30 var safe = undefined;
31 var arg = undefined;
31 var arg = undefined;
32
32
33 // For each {0} {1} {n...} replace with the argument in that position. If
33 // For each {0} {1} {n...} replace with the argument in that position. If
34 // the argument is an object or an array it will be stringified to JSON.
34 // the argument is an object or an array it will be stringified to JSON.
35 for (var i=0; i < len; arg = arguments[i++]) {
35 for (var i=0; i < len; arg = arguments[i++]) {
36 safe = typeof arg === 'object' ? JSON.stringify(arg) : arg;
36 safe = typeof arg === 'object' ? JSON.stringify(arg) : arg;
37 str = str.replace(new RegExp('\\{'+(i-1)+'\\}', 'g'), safe);
37 str = str.replace(new RegExp('\\{'+(i-1)+'\\}', 'g'), safe);
38 }
38 }
39 return str;
39 return str;
40 }
40 }
41
41
42 // Save a reference of what may already exist under the property native.
42 // Save a reference of what may already exist under the property native.
43 // Allows for doing something like: if("".format.native) { /* use native */ }
43 // Allows for doing something like: if("".format.native) { /* use native */ }
44 format.native = String.prototype.format;
44 format.native = String.prototype.format;
45
45
46 // Replace the prototype property
46 // Replace the prototype property
47 return format;
47 return format;
48 }();
48 }();
49
49
50 String.prototype.strip = function(char) {
50 String.prototype.strip = function(char) {
51 if(char === undefined){
51 if(char === undefined){
52 char = '\\s';
52 char = '\\s';
53 }
53 }
54 return this.replace(new RegExp('^'+char+'+|'+char+'+$','g'), '');
54 return this.replace(new RegExp('^'+char+'+|'+char+'+$','g'), '');
55 };
55 };
56
56
57 String.prototype.lstrip = function(char) {
57 String.prototype.lstrip = function(char) {
58 if(char === undefined){
58 if(char === undefined){
59 char = '\\s';
59 char = '\\s';
60 }
60 }
61 return this.replace(new RegExp('^'+char+'+'),'');
61 return this.replace(new RegExp('^'+char+'+'),'');
62 };
62 };
63
63
64 String.prototype.rstrip = function(char) {
64 String.prototype.rstrip = function(char) {
65 if(char === undefined){
65 if(char === undefined){
66 char = '\\s';
66 char = '\\s';
67 }
67 }
68 return this.replace(new RegExp(''+char+'+$'),'');
68 return this.replace(new RegExp(''+char+'+$'),'');
69 };
69 };
70
70
71 String.prototype.capitalizeFirstLetter = function() {
71 String.prototype.capitalizeFirstLetter = function() {
72 return this.charAt(0).toUpperCase() + this.slice(1);
72 return this.charAt(0).toUpperCase() + this.slice(1);
73 };
73 };
74
74
75
75
76 /**
76 /**
77 * Splits remainder
78 *
79 * @param input
80 */
81 function splitDelimitedHash(input){
82 var splitIx = input.indexOf('/?/');
83 if (splitIx !== -1){
84 var loc = input.slice(0, splitIx);
85 var remainder = input.slice(splitIx + 2);
86 }
87 else{
88 var loc = input;
89 var remainder = null;
90 }
91 //fixes for some urls generated incorrectly
92 var result = loc.match('#+(.*)');
93 if (result !== null){
94 loc = '#' + result[1];
95 }
96 return {loc:loc, remainder: remainder}
97 }
98
99 /**
77 * Escape html characters in string
100 * Escape html characters in string
78 */
101 */
79 var entityMap = {
102 var entityMap = {
80 "&": "&amp;",
103 "&": "&amp;",
81 "<": "&lt;",
104 "<": "&lt;",
82 ">": "&gt;",
105 ">": "&gt;",
83 '"': '&quot;',
106 '"': '&quot;',
84 "'": '&#39;',
107 "'": '&#39;',
85 "/": '&#x2F;'
108 "/": '&#x2F;'
86 };
109 };
87
110
88 function escapeHtml(string) {
111 function escapeHtml(string) {
89 return String(string).replace(/[&<>"'\/]/g, function (s) {
112 return String(string).replace(/[&<>"'\/]/g, function (s) {
90 return entityMap[s];
113 return entityMap[s];
91 });
114 });
92 }
115 }
93
116
94 /** encode/decode html special chars**/
117 /** encode/decode html special chars**/
95 var htmlEnDeCode = (function() {
118 var htmlEnDeCode = (function() {
96 var charToEntityRegex,
119 var charToEntityRegex,
97 entityToCharRegex,
120 entityToCharRegex,
98 charToEntity,
121 charToEntity,
99 entityToChar;
122 entityToChar;
100
123
101 function resetCharacterEntities() {
124 function resetCharacterEntities() {
102 charToEntity = {};
125 charToEntity = {};
103 entityToChar = {};
126 entityToChar = {};
104 // add the default set
127 // add the default set
105 addCharacterEntities({
128 addCharacterEntities({
106 '&amp;' : '&',
129 '&amp;' : '&',
107 '&gt;' : '>',
130 '&gt;' : '>',
108 '&lt;' : '<',
131 '&lt;' : '<',
109 '&quot;' : '"',
132 '&quot;' : '"',
110 '&#39;' : "'"
133 '&#39;' : "'"
111 });
134 });
112 }
135 }
113
136
114 function addCharacterEntities(newEntities) {
137 function addCharacterEntities(newEntities) {
115 var charKeys = [],
138 var charKeys = [],
116 entityKeys = [],
139 entityKeys = [],
117 key, echar;
140 key, echar;
118 for (key in newEntities) {
141 for (key in newEntities) {
119 echar = newEntities[key];
142 echar = newEntities[key];
120 entityToChar[key] = echar;
143 entityToChar[key] = echar;
121 charToEntity[echar] = key;
144 charToEntity[echar] = key;
122 charKeys.push(echar);
145 charKeys.push(echar);
123 entityKeys.push(key);
146 entityKeys.push(key);
124 }
147 }
125 charToEntityRegex = new RegExp('(' + charKeys.join('|') + ')', 'g');
148 charToEntityRegex = new RegExp('(' + charKeys.join('|') + ')', 'g');
126 entityToCharRegex = new RegExp('(' + entityKeys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
149 entityToCharRegex = new RegExp('(' + entityKeys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
127 }
150 }
128
151
129 function htmlEncode(value){
152 function htmlEncode(value){
130 var htmlEncodeReplaceFn = function(match, capture) {
153 var htmlEncodeReplaceFn = function(match, capture) {
131 return charToEntity[capture];
154 return charToEntity[capture];
132 };
155 };
133
156
134 return (!value) ? value : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn);
157 return (!value) ? value : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn);
135 }
158 }
136
159
137 function htmlDecode(value) {
160 function htmlDecode(value) {
138 var htmlDecodeReplaceFn = function(match, capture) {
161 var htmlDecodeReplaceFn = function(match, capture) {
139 return (capture in entityToChar) ? entityToChar[capture] : String.fromCharCode(parseInt(capture.substr(2), 10));
162 return (capture in entityToChar) ? entityToChar[capture] : String.fromCharCode(parseInt(capture.substr(2), 10));
140 };
163 };
141
164
142 return (!value) ? value : String(value).replace(entityToCharRegex, htmlDecodeReplaceFn);
165 return (!value) ? value : String(value).replace(entityToCharRegex, htmlDecodeReplaceFn);
143 }
166 }
144
167
145 resetCharacterEntities();
168 resetCharacterEntities();
146
169
147 return {
170 return {
148 htmlEncode: htmlEncode,
171 htmlEncode: htmlEncode,
149 htmlDecode: htmlDecode
172 htmlDecode: htmlDecode
150 };
173 };
151 })();
174 })();
@@ -1,393 +1,393 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 <%inherit file="/base/base.html"/>
3 <%inherit file="/base/base.html"/>
4 <%namespace name="diff_block" file="/changeset/diff_block.html"/>
4 <%namespace name="diff_block" file="/changeset/diff_block.html"/>
5
5
6 <%def name="title()">
6 <%def name="title()">
7 ${_('%s Commit') % c.repo_name} - ${h.show_id(c.commit)}
7 ${_('%s Commit') % c.repo_name} - ${h.show_id(c.commit)}
8 %if c.rhodecode_name:
8 %if c.rhodecode_name:
9 &middot; ${h.branding(c.rhodecode_name)}
9 &middot; ${h.branding(c.rhodecode_name)}
10 %endif
10 %endif
11 </%def>
11 </%def>
12
12
13 <%def name="menu_bar_nav()">
13 <%def name="menu_bar_nav()">
14 ${self.menu_items(active='repositories')}
14 ${self.menu_items(active='repositories')}
15 </%def>
15 </%def>
16
16
17 <%def name="menu_bar_subnav()">
17 <%def name="menu_bar_subnav()">
18 ${self.repo_menu(active='changelog')}
18 ${self.repo_menu(active='changelog')}
19 </%def>
19 </%def>
20
20
21 <%def name="main()">
21 <%def name="main()">
22 <script>
22 <script>
23 // TODO: marcink switch this to pyroutes
23 // TODO: marcink switch this to pyroutes
24 AJAX_COMMENT_DELETE_URL = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}";
24 AJAX_COMMENT_DELETE_URL = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}";
25 templateContext.commit_data.commit_id = "${c.commit.raw_id}";
25 templateContext.commit_data.commit_id = "${c.commit.raw_id}";
26 </script>
26 </script>
27 <div class="box">
27 <div class="box">
28 <div class="title">
28 <div class="title">
29 ${self.repo_page_title(c.rhodecode_db_repo)}
29 ${self.repo_page_title(c.rhodecode_db_repo)}
30 </div>
30 </div>
31
31
32 <div id="changeset_compare_view_content" class="summary changeset">
32 <div id="changeset_compare_view_content" class="summary changeset">
33 <div class="summary-detail">
33 <div class="summary-detail">
34 <div class="summary-detail-header">
34 <div class="summary-detail-header">
35 <span class="breadcrumbs files_location">
35 <span class="breadcrumbs files_location">
36 <h4>${_('Commit')}
36 <h4>${_('Commit')}
37 <code>
37 <code>
38 ${h.show_id(c.commit)}
38 ${h.show_id(c.commit)}
39 </code>
39 </code>
40 </h4>
40 </h4>
41 </span>
41 </span>
42 <span id="parent_link">
42 <span id="parent_link">
43 <a href="#" title="${_('Parent Commit')}">${_('Parent')}</a>
43 <a href="#" title="${_('Parent Commit')}">${_('Parent')}</a>
44 </span>
44 </span>
45 |
45 |
46 <span id="child_link">
46 <span id="child_link">
47 <a href="#" title="${_('Child Commit')}">${_('Child')}</a>
47 <a href="#" title="${_('Child Commit')}">${_('Child')}</a>
48 </span>
48 </span>
49 </div>
49 </div>
50
50
51 <div class="fieldset">
51 <div class="fieldset">
52 <div class="left-label">
52 <div class="left-label">
53 ${_('Description')}:
53 ${_('Description')}:
54 </div>
54 </div>
55 <div class="right-content">
55 <div class="right-content">
56 <div id="trimmed_message_box" class="commit">${h.urlify_commit_message(c.commit.message,c.repo_name)}</div>
56 <div id="trimmed_message_box" class="commit">${h.urlify_commit_message(c.commit.message,c.repo_name)}</div>
57 <div id="message_expand" style="display:none;">
57 <div id="message_expand" style="display:none;">
58 ${_('Expand')}
58 ${_('Expand')}
59 </div>
59 </div>
60 </div>
60 </div>
61 </div>
61 </div>
62
62
63 %if c.statuses:
63 %if c.statuses:
64 <div class="fieldset">
64 <div class="fieldset">
65 <div class="left-label">
65 <div class="left-label">
66 ${_('Commit status')}:
66 ${_('Commit status')}:
67 </div>
67 </div>
68 <div class="right-content">
68 <div class="right-content">
69 <div class="changeset-status-ico">
69 <div class="changeset-status-ico">
70 <div class="${'flag_status %s' % c.statuses[0]} pull-left"></div>
70 <div class="${'flag_status %s' % c.statuses[0]} pull-left"></div>
71 </div>
71 </div>
72 <div title="${_('Commit status')}" class="changeset-status-lbl">[${h.commit_status_lbl(c.statuses[0])}]</div>
72 <div title="${_('Commit status')}" class="changeset-status-lbl">[${h.commit_status_lbl(c.statuses[0])}]</div>
73 </div>
73 </div>
74 </div>
74 </div>
75 %endif
75 %endif
76
76
77 <div class="fieldset">
77 <div class="fieldset">
78 <div class="left-label">
78 <div class="left-label">
79 ${_('References')}:
79 ${_('References')}:
80 </div>
80 </div>
81 <div class="right-content">
81 <div class="right-content">
82 <div class="tags">
82 <div class="tags">
83
83
84 %if c.commit.merge:
84 %if c.commit.merge:
85 <span class="mergetag tag">
85 <span class="mergetag tag">
86 ${_('merge')}
86 ${_('merge')}
87 </span>
87 </span>
88 %endif
88 %endif
89
89
90 %if h.is_hg(c.rhodecode_repo):
90 %if h.is_hg(c.rhodecode_repo):
91 %for book in c.commit.bookmarks:
91 %for book in c.commit.bookmarks:
92 <span class="booktag tag" title="${_('Bookmark %s') % book}">
92 <span class="booktag tag" title="${_('Bookmark %s') % book}">
93 <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-bookmark"></i>${h.shorter(book)}</a>
93 <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-bookmark"></i>${h.shorter(book)}</a>
94 </span>
94 </span>
95 %endfor
95 %endfor
96 %endif
96 %endif
97
97
98 %for tag in c.commit.tags:
98 %for tag in c.commit.tags:
99 <span class="tagtag tag" title="${_('Tag %s') % tag}">
99 <span class="tagtag tag" title="${_('Tag %s') % tag}">
100 <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-tag"></i>${tag}</a>
100 <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-tag"></i>${tag}</a>
101 </span>
101 </span>
102 %endfor
102 %endfor
103
103
104 %if c.commit.branch:
104 %if c.commit.branch:
105 <span class="branchtag tag" title="${_('Branch %s') % c.commit.branch}">
105 <span class="branchtag tag" title="${_('Branch %s') % c.commit.branch}">
106 <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-code-fork"></i>${h.shorter(c.commit.branch)}</a>
106 <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-code-fork"></i>${h.shorter(c.commit.branch)}</a>
107 </span>
107 </span>
108 %endif
108 %endif
109 </div>
109 </div>
110 </div>
110 </div>
111 </div>
111 </div>
112
112
113 <div class="fieldset">
113 <div class="fieldset">
114 <div class="left-label">
114 <div class="left-label">
115 ${_('Diffs')}:
115 ${_('Diffs')}:
116 </div>
116 </div>
117 <div class="right-content">
117 <div class="right-content">
118 <div class="diff-actions">
118 <div class="diff-actions">
119 <a href="${h.url('changeset_raw_home',repo_name=c.repo_name,revision=c.commit.raw_id)}" class="tooltip" title="${h.tooltip(_('Raw diff'))}">
119 <a href="${h.url('changeset_raw_home',repo_name=c.repo_name,revision=c.commit.raw_id)}" class="tooltip" title="${h.tooltip(_('Raw diff'))}">
120 ${_('Raw Diff')}
120 ${_('Raw Diff')}
121 </a>
121 </a>
122 |
122 |
123 <a href="${h.url('changeset_patch_home',repo_name=c.repo_name,revision=c.commit.raw_id)}" class="tooltip" title="${h.tooltip(_('Patch diff'))}">
123 <a href="${h.url('changeset_patch_home',repo_name=c.repo_name,revision=c.commit.raw_id)}" class="tooltip" title="${h.tooltip(_('Patch diff'))}">
124 ${_('Patch Diff')}
124 ${_('Patch Diff')}
125 </a>
125 </a>
126 |
126 |
127 <a href="${h.url('changeset_download_home',repo_name=c.repo_name,revision=c.commit.raw_id,diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}">
127 <a href="${h.url('changeset_download_home',repo_name=c.repo_name,revision=c.commit.raw_id,diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}">
128 ${_('Download Diff')}
128 ${_('Download Diff')}
129 </a>
129 </a>
130 |
130 |
131 ${c.ignorews_url(request.GET)}
131 ${c.ignorews_url(request.GET)}
132 |
132 |
133 ${c.context_url(request.GET)}
133 ${c.context_url(request.GET)}
134 </div>
134 </div>
135 </div>
135 </div>
136 </div>
136 </div>
137
137
138 <div class="fieldset">
138 <div class="fieldset">
139 <div class="left-label">
139 <div class="left-label">
140 ${_('Comments')}:
140 ${_('Comments')}:
141 </div>
141 </div>
142 <div class="right-content">
142 <div class="right-content">
143 <div class="comments-number">
143 <div class="comments-number">
144 %if c.comments:
144 %if c.comments:
145 <a href="#comments">${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)}</a>,
145 <a href="#comments">${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)}</a>,
146 %else:
146 %else:
147 ${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)}
147 ${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)}
148 %endif
148 %endif
149 %if c.inline_cnt:
149 %if c.inline_cnt:
150 ## this is replaced with a proper link to first comment via JS linkifyComments() func
150 ## this is replaced with a proper link to first comment via JS linkifyComments() func
151 <a href="#inline-comments" id="inline-comments-counter">${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}</a>
151 <a href="#inline-comments" id="inline-comments-counter">${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}</a>
152 %else:
152 %else:
153 ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}
153 ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}
154 %endif
154 %endif
155 </div>
155 </div>
156 </div>
156 </div>
157 </div>
157 </div>
158
158
159 </div> <!-- end summary-detail -->
159 </div> <!-- end summary-detail -->
160
160
161 <div id="commit-stats" class="sidebar-right">
161 <div id="commit-stats" class="sidebar-right">
162 <div class="summary-detail-header">
162 <div class="summary-detail-header">
163 <h4 class="item">
163 <h4 class="item">
164 ${_('Author')}
164 ${_('Author')}
165 </h4>
165 </h4>
166 </div>
166 </div>
167 <div class="sidebar-right-content">
167 <div class="sidebar-right-content">
168 ${self.gravatar_with_user(c.commit.author)}
168 ${self.gravatar_with_user(c.commit.author)}
169 <div class="user-inline-data">- ${h.age_component(c.commit.date)}</div>
169 <div class="user-inline-data">- ${h.age_component(c.commit.date)}</div>
170 </div>
170 </div>
171 </div><!-- end sidebar -->
171 </div><!-- end sidebar -->
172 </div> <!-- end summary -->
172 </div> <!-- end summary -->
173 <div class="cs_files_title">
173 <div class="cs_files_title">
174 <span class="cs_files_expand">
174 <span class="cs_files_expand">
175 <span id="files_link"><a href="#" title="${_('Browse files at current commit')}">${_('Browse files')}</a></span> |
175 <span id="files_link"><a href="#" title="${_('Browse files at current commit')}">${_('Browse files')}</a></span> |
176
176
177 <span id="expand_all_files">${_('Expand All')}</span> | <span id="collapse_all_files">${_('Collapse All')}</span>
177 <span id="expand_all_files">${_('Expand All')}</span> | <span id="collapse_all_files">${_('Collapse All')}</span>
178 </span>
178 </span>
179 <h2>
179 <h2>
180 ${diff_block.diff_summary_text(len(c.files), c.lines_added, c.lines_deleted, c.limited_diff)}
180 ${diff_block.diff_summary_text(len(c.files), c.lines_added, c.lines_deleted, c.limited_diff)}
181 </h2>
181 </h2>
182 </div>
182 </div>
183 </div>
183 </div>
184
184
185 <div class="cs_files">
185 <div class="cs_files">
186
186
187 %if not c.files:
187 %if not c.files:
188 <p class="empty_data">${_('No files')}</p>
188 <p class="empty_data">${_('No files')}</p>
189 %endif
189 %endif
190
190
191 <table class="compare_view_files commit_diff">
191 <table class="compare_view_files commit_diff">
192 %for FID, (cs1, cs2, change, path, diff, stats, file) in c.changes[c.commit.raw_id].iteritems():
192 %for FID, (cs1, cs2, change, path, diff, stats, file) in c.changes[c.commit.raw_id].iteritems():
193 <tr class="cs_${change} collapse_file" fid="${FID}">
193 <tr class="cs_${change} collapse_file" fid="${FID}">
194 <td class="cs_icon_td">
194 <td class="cs_icon_td">
195 <span class="collapse_file_icon" fid="${FID}"></span>
195 <span class="collapse_file_icon" fid="${FID}"></span>
196 </td>
196 </td>
197 <td class="cs_icon_td">
197 <td class="cs_icon_td">
198 <div class="flag_status not_reviewed hidden"></div>
198 <div class="flag_status not_reviewed hidden"></div>
199 </td>
199 </td>
200 <td class="cs_${change}" id="a_${FID}">
200 <td class="cs_${change}" id="a_${FID}">
201 <div class="node">
201 <div class="node">
202 <a href="#a_${FID}">
202 <a href="#a_${FID}">
203 <i class="icon-file-${change.lower()}"></i>
203 <i class="icon-file-${change.lower()}"></i>
204 ${h.safe_unicode(path)}
204 ${h.safe_unicode(path)}
205 </a>
205 </a>
206 </div>
206 </div>
207 </td>
207 </td>
208 <td>
208 <td>
209 <div class="changes pull-right">${h.fancy_file_stats(stats)}</div>
209 <div class="changes pull-right">${h.fancy_file_stats(stats)}</div>
210 <div class="comment-bubble pull-right" data-path="${path}">
210 <div class="comment-bubble pull-right" data-path="${path}">
211 <i class="icon-comment"></i>
211 <i class="icon-comment"></i>
212 </div>
212 </div>
213 </td>
213 </td>
214 </tr>
214 </tr>
215 <tr fid="${FID}" id="diff_${FID}" class="diff_links">
215 <tr fid="${FID}" id="diff_${FID}" class="diff_links">
216 <td></td>
216 <td></td>
217 <td></td>
217 <td></td>
218 <td class="cs_${change}">
218 <td class="cs_${change}">
219 ${diff_block.diff_menu(c.repo_name, h.safe_unicode(path), cs1, cs2, change, file)}
219 ${diff_block.diff_menu(c.repo_name, h.safe_unicode(path), cs1, cs2, change, file)}
220 </td>
220 </td>
221 <td class="td-actions rc-form">
221 <td class="td-actions rc-form">
222 ${c.ignorews_url(request.GET, h.FID(cs2,path))} |
222 ${c.ignorews_url(request.GET, h.FID(cs2,path))} |
223 ${c.context_url(request.GET, h.FID(cs2,path))} |
223 ${c.context_url(request.GET, h.FID(cs2,path))} |
224 <div data-comment-id="${h.FID(cs2,path)}" class="btn-link show-inline-comments comments-visible">
224 <div data-comment-id="${h.FID(cs2,path)}" class="btn-link show-inline-comments comments-visible">
225 <span class="comments-show">${_('Show comments')}</span>
225 <span class="comments-show">${_('Show comments')}</span>
226 <span class="comments-hide">${_('Hide comments')}</span>
226 <span class="comments-hide">${_('Hide comments')}</span>
227 </div>
227 </div>
228 </td>
228 </td>
229 </tr>
229 </tr>
230 <tr id="tr_${FID}">
230 <tr id="tr_${FID}">
231 <td></td>
231 <td></td>
232 <td></td>
232 <td></td>
233 <td class="injected_diff" colspan="2">
233 <td class="injected_diff" colspan="2">
234 <div class="diff-container" id="${'diff-container-%s' % (id(change))}">
234 <div class="diff-container" id="${'diff-container-%s' % (id(change))}">
235 <div id="${FID}" class="diffblock margined comm">
235 <div id="${FID}" class="diffblock margined comm">
236 <div class="code-body">
236 <div class="code-body">
237 <div class="full_f_path" path="${h.safe_unicode(path)}"></div>
237 <div class="full_f_path" path="${h.safe_unicode(path)}"></div>
238 ${diff|n}
238 ${diff|n}
239 % if file and file["is_limited_diff"]:
239 % if file and file["is_limited_diff"]:
240 % if file["exceeds_limit"]:
240 % if file["exceeds_limit"]:
241 ${diff_block.file_message()}
241 ${diff_block.file_message()}
242 % else:
242 % else:
243 <h5>${_('Diff was truncated. File content available only in full diff.')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a></h5>
243 <h5>${_('Diff was truncated. File content available only in full diff.')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a></h5>
244 % endif
244 % endif
245 % endif
245 % endif
246 </div>
246 </div>
247 </div>
247 </div>
248 </div>
248 </div>
249 </td>
249 </td>
250 </tr>
250 </tr>
251 %endfor
251 %endfor
252 </table>
252 </table>
253 </div>
253 </div>
254
254
255 % if c.limited_diff:
255 % if c.limited_diff:
256 ${diff_block.changeset_message()}
256 ${diff_block.changeset_message()}
257 % endif
257 % endif
258
258
259 ## template for inline comment form
259 ## template for inline comment form
260 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
260 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
261 ${comment.comment_inline_form()}
261 ${comment.comment_inline_form()}
262
262
263 ## render comments and inlines
263 ## render comments and inlines
264 ${comment.generate_comments()}
264 ${comment.generate_comments()}
265
265
266 ## main comment form and it status
266 ## main comment form and it status
267 ${comment.comments(h.url('changeset_comment', repo_name=c.repo_name, revision=c.commit.raw_id),
267 ${comment.comments(h.url('changeset_comment', repo_name=c.repo_name, revision=c.commit.raw_id),
268 h.commit_status(c.rhodecode_db_repo, c.commit.raw_id))}
268 h.commit_status(c.rhodecode_db_repo, c.commit.raw_id))}
269
269
270 ## FORM FOR MAKING JS ACTION AS CHANGESET COMMENTS
270 ## FORM FOR MAKING JS ACTION AS CHANGESET COMMENTS
271 <script type="text/javascript">
271 <script type="text/javascript">
272
272
273 $(document).ready(function() {
273 $(document).ready(function() {
274
274
275 var boxmax = parseInt($('#trimmed_message_box').css('max-height'), 10);
275 var boxmax = parseInt($('#trimmed_message_box').css('max-height'), 10);
276 if($('#trimmed_message_box').height() === boxmax){
276 if($('#trimmed_message_box').height() === boxmax){
277 $('#message_expand').show();
277 $('#message_expand').show();
278 }
278 }
279
279
280 $('#message_expand').on('click', function(e){
280 $('#message_expand').on('click', function(e){
281 $('#trimmed_message_box').css('max-height', 'none');
281 $('#trimmed_message_box').css('max-height', 'none');
282 $(this).hide();
282 $(this).hide();
283 });
283 });
284
284
285 $('.show-inline-comments').on('click', function(e){
285 $('.show-inline-comments').on('click', function(e){
286 var boxid = $(this).attr('data-comment-id');
286 var boxid = $(this).attr('data-comment-id');
287 var button = $(this);
287 var button = $(this);
288
288
289 if(button.hasClass("comments-visible")) {
289 if(button.hasClass("comments-visible")) {
290 $('#{0} .inline-comments'.format(boxid)).each(function(index){
290 $('#{0} .inline-comments'.format(boxid)).each(function(index){
291 $(this).hide();
291 $(this).hide();
292 })
292 })
293 button.removeClass("comments-visible");
293 button.removeClass("comments-visible");
294 } else {
294 } else {
295 $('#{0} .inline-comments'.format(boxid)).each(function(index){
295 $('#{0} .inline-comments'.format(boxid)).each(function(index){
296 $(this).show();
296 $(this).show();
297 })
297 })
298 button.addClass("comments-visible");
298 button.addClass("comments-visible");
299 }
299 }
300 });
300 });
301
301
302
302
303 // next links
303 // next links
304 $('#child_link').on('click', function(e){
304 $('#child_link').on('click', function(e){
305 // fetch via ajax what is going to be the next link, if we have
305 // fetch via ajax what is going to be the next link, if we have
306 // >1 links show them to user to choose
306 // >1 links show them to user to choose
307 if(!$('#child_link').hasClass('disabled')){
307 if(!$('#child_link').hasClass('disabled')){
308 $.ajax({
308 $.ajax({
309 url: '${h.url('changeset_children',repo_name=c.repo_name, revision=c.commit.raw_id)}',
309 url: '${h.url('changeset_children',repo_name=c.repo_name, revision=c.commit.raw_id)}',
310 success: function(data) {
310 success: function(data) {
311 if(data.results.length === 0){
311 if(data.results.length === 0){
312 $('#child_link').html('${_('No Child Commits')}').addClass('disabled');
312 $('#child_link').html('${_('No Child Commits')}').addClass('disabled');
313 }
313 }
314 if(data.results.length === 1){
314 if(data.results.length === 1){
315 var commit = data.results[0];
315 var commit = data.results[0];
316 window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id});
316 window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id});
317 }
317 }
318 else if(data.results.length === 2){
318 else if(data.results.length === 2){
319 $('#child_link').addClass('disabled');
319 $('#child_link').addClass('disabled');
320 $('#child_link').addClass('double');
320 $('#child_link').addClass('double');
321 var _html = '';
321 var _html = '';
322 _html +='<a title="__title__" href="__url__">__rev__</a> '
322 _html +='<a title="__title__" href="__url__">__rev__</a> '
323 .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
323 .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
324 .replace('__title__', data.results[0].message)
324 .replace('__title__', data.results[0].message)
325 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id}));
325 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id}));
326 _html +=' | '
326 _html +=' | '
327 _html +='<a title="__title__" href="__url__">__rev__</a> '
327 _html +='<a title="__title__" href="__url__">__rev__</a> '
328 .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
328 .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
329 .replace('__title__', data.results[1].message)
329 .replace('__title__', data.results[1].message)
330 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id}));
330 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id}));
331 $('#child_link').html(_html);
331 $('#child_link').html(_html);
332 }
332 }
333 }
333 }
334 });
334 });
335 e.preventDefault();
335 e.preventDefault();
336 }
336 }
337 });
337 });
338
338
339 // prev links
339 // prev links
340 $('#parent_link').on('click', function(e){
340 $('#parent_link').on('click', function(e){
341 // fetch via ajax what is going to be the next link, if we have
341 // fetch via ajax what is going to be the next link, if we have
342 // >1 links show them to user to choose
342 // >1 links show them to user to choose
343 if(!$('#parent_link').hasClass('disabled')){
343 if(!$('#parent_link').hasClass('disabled')){
344 $.ajax({
344 $.ajax({
345 url: '${h.url('changeset_parents',repo_name=c.repo_name, revision=c.commit.raw_id)}',
345 url: '${h.url('changeset_parents',repo_name=c.repo_name, revision=c.commit.raw_id)}',
346 success: function(data) {
346 success: function(data) {
347 if(data.results.length === 0){
347 if(data.results.length === 0){
348 $('#parent_link').html('${_('No Parent Commits')}').addClass('disabled');
348 $('#parent_link').html('${_('No Parent Commits')}').addClass('disabled');
349 }
349 }
350 if(data.results.length === 1){
350 if(data.results.length === 1){
351 var commit = data.results[0];
351 var commit = data.results[0];
352 window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id});
352 window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id});
353 }
353 }
354 else if(data.results.length === 2){
354 else if(data.results.length === 2){
355 $('#parent_link').addClass('disabled');
355 $('#parent_link').addClass('disabled');
356 $('#parent_link').addClass('double');
356 $('#parent_link').addClass('double');
357 var _html = '';
357 var _html = '';
358 _html +='<a title="__title__" href="__url__">Parent __rev__</a>'
358 _html +='<a title="__title__" href="__url__">Parent __rev__</a>'
359 .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
359 .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
360 .replace('__title__', data.results[0].message)
360 .replace('__title__', data.results[0].message)
361 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id}));
361 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id}));
362 _html +=' | '
362 _html +=' | '
363 _html +='<a title="__title__" href="__url__">Parent __rev__</a>'
363 _html +='<a title="__title__" href="__url__">Parent __rev__</a>'
364 .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
364 .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
365 .replace('__title__', data.results[1].message)
365 .replace('__title__', data.results[1].message)
366 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id}));
366 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id}));
367 $('#parent_link').html(_html);
367 $('#parent_link').html(_html);
368 }
368 }
369 }
369 }
370 });
370 });
371 e.preventDefault();
371 e.preventDefault();
372 }
372 }
373 });
373 });
374
374
375 if (location.href.indexOf('#') != -1) {
375 if (location.hash) {
376 var id = '#'+location.href.substring(location.href.indexOf('#') + 1).split('#');
376 var result = splitDelimitedHash(location.hash);
377 var line = $('html').find(id);
377 var line = $('html').find(result.loc);
378 offsetScroll(line, 70);
378 offsetScroll(line, 70);
379 }
379 }
380
380
381 // browse tree @ revision
381 // browse tree @ revision
382 $('#files_link').on('click', function(e){
382 $('#files_link').on('click', function(e){
383 window.location = '${h.url('files_home',repo_name=c.repo_name, revision=c.commit.raw_id, f_path='')}';
383 window.location = '${h.url('files_home',repo_name=c.repo_name, revision=c.commit.raw_id, f_path='')}';
384 e.preventDefault();
384 e.preventDefault();
385 });
385 });
386
386
387 // inject comments into their proper positions
387 // inject comments into their proper positions
388 var file_comments = $('.inline-comment-placeholder');
388 var file_comments = $('.inline-comment-placeholder');
389 renderInlineComments(file_comments, true);
389 renderInlineComments(file_comments, true);
390 })
390 })
391 </script>
391 </script>
392
392
393 </%def>
393 </%def>
@@ -1,589 +1,589 b''
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${_('%s Pull Request #%s') % (c.repo_name, c.pull_request.pull_request_id)}
4 ${_('%s Pull Request #%s') % (c.repo_name, c.pull_request.pull_request_id)}
5 %if c.rhodecode_name:
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}
6 &middot; ${h.branding(c.rhodecode_name)}
7 %endif
7 %endif
8 </%def>
8 </%def>
9
9
10 <%def name="breadcrumbs_links()">
10 <%def name="breadcrumbs_links()">
11 <span id="pr-title">
11 <span id="pr-title">
12 ${c.pull_request.title}
12 ${c.pull_request.title}
13 %if c.pull_request.is_closed():
13 %if c.pull_request.is_closed():
14 (${_('Closed')})
14 (${_('Closed')})
15 %endif
15 %endif
16 </span>
16 </span>
17 <div id="pr-title-edit" class="input" style="display: none;">
17 <div id="pr-title-edit" class="input" style="display: none;">
18 ${h.text('pullrequest_title', id_="pr-title-input", class_="large", value=c.pull_request.title)}
18 ${h.text('pullrequest_title', id_="pr-title-input", class_="large", value=c.pull_request.title)}
19 </div>
19 </div>
20 </%def>
20 </%def>
21
21
22 <%def name="menu_bar_nav()">
22 <%def name="menu_bar_nav()">
23 ${self.menu_items(active='repositories')}
23 ${self.menu_items(active='repositories')}
24 </%def>
24 </%def>
25
25
26 <%def name="menu_bar_subnav()">
26 <%def name="menu_bar_subnav()">
27 ${self.repo_menu(active='showpullrequest')}
27 ${self.repo_menu(active='showpullrequest')}
28 </%def>
28 </%def>
29
29
30 <%def name="main()">
30 <%def name="main()">
31 <script type="text/javascript">
31 <script type="text/javascript">
32 // TODO: marcink switch this to pyroutes
32 // TODO: marcink switch this to pyroutes
33 AJAX_COMMENT_DELETE_URL = "${url('pullrequest_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}";
33 AJAX_COMMENT_DELETE_URL = "${url('pullrequest_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}";
34 templateContext.pull_request_data.pull_request_id = ${c.pull_request.pull_request_id};
34 templateContext.pull_request_data.pull_request_id = ${c.pull_request.pull_request_id};
35 </script>
35 </script>
36 <div class="box">
36 <div class="box">
37 <div class="title">
37 <div class="title">
38 ${self.repo_page_title(c.rhodecode_db_repo)}
38 ${self.repo_page_title(c.rhodecode_db_repo)}
39 </div>
39 </div>
40
40
41 ${self.breadcrumbs()}
41 ${self.breadcrumbs()}
42
42
43
43
44 <div class="box pr-summary">
44 <div class="box pr-summary">
45 <div class="summary-details block-left">
45 <div class="summary-details block-left">
46 <%summary = lambda n:{False:'summary-short'}.get(n)%>
46 <%summary = lambda n:{False:'summary-short'}.get(n)%>
47 <div class="pr-details-title">
47 <div class="pr-details-title">
48 ${_('Pull request #%s') % c.pull_request.pull_request_id} ${_('From')} ${h.format_date(c.pull_request.created_on)}
48 ${_('Pull request #%s') % c.pull_request.pull_request_id} ${_('From')} ${h.format_date(c.pull_request.created_on)}
49 %if c.allowed_to_update:
49 %if c.allowed_to_update:
50 <span id="open_edit_pullrequest" class="block-right action_button">${_('Edit')}</span>
50 <span id="open_edit_pullrequest" class="block-right action_button">${_('Edit')}</span>
51 <span id="close_edit_pullrequest" class="block-right action_button" style="display: none;">${_('Close')}</span>
51 <span id="close_edit_pullrequest" class="block-right action_button" style="display: none;">${_('Close')}</span>
52 %endif
52 %endif
53 </div>
53 </div>
54
54
55 <div id="summary" class="fields pr-details-content">
55 <div id="summary" class="fields pr-details-content">
56 <div class="field">
56 <div class="field">
57 <div class="label-summary">
57 <div class="label-summary">
58 <label>${_('Origin')}:</label>
58 <label>${_('Origin')}:</label>
59 </div>
59 </div>
60 <div class="input">
60 <div class="input">
61 <div class="pr-origininfo">
61 <div class="pr-origininfo">
62 ## branch link is only valid if it is a branch
62 ## branch link is only valid if it is a branch
63 <span class="tag">
63 <span class="tag">
64 %if c.pull_request.source_ref_parts.type == 'branch':
64 %if c.pull_request.source_ref_parts.type == 'branch':
65 <a href="${h.url('changelog_home', repo_name=c.pull_request.source_repo.repo_name, branch=c.pull_request.source_ref_parts.name)}">${c.pull_request.source_ref_parts.type}: ${c.pull_request.source_ref_parts.name}</a>
65 <a href="${h.url('changelog_home', repo_name=c.pull_request.source_repo.repo_name, branch=c.pull_request.source_ref_parts.name)}">${c.pull_request.source_ref_parts.type}: ${c.pull_request.source_ref_parts.name}</a>
66 %else:
66 %else:
67 ${c.pull_request.source_ref_parts.type}: ${c.pull_request.source_ref_parts.name}
67 ${c.pull_request.source_ref_parts.type}: ${c.pull_request.source_ref_parts.name}
68 %endif
68 %endif
69 </span>
69 </span>
70 <span class="clone-url">
70 <span class="clone-url">
71 <a href="${h.url('summary_home', repo_name=c.pull_request.source_repo.repo_name)}">${c.pull_request.source_repo.clone_url()}</a>
71 <a href="${h.url('summary_home', repo_name=c.pull_request.source_repo.repo_name)}">${c.pull_request.source_repo.clone_url()}</a>
72 </span>
72 </span>
73 </div>
73 </div>
74 <div class="pr-pullinfo">
74 <div class="pr-pullinfo">
75 %if h.is_hg(c.pull_request.source_repo):
75 %if h.is_hg(c.pull_request.source_repo):
76 <input type="text" value="hg pull -r ${h.short_id(c.source_ref)} ${c.pull_request.source_repo.clone_url()}" readonly="readonly">
76 <input type="text" value="hg pull -r ${h.short_id(c.source_ref)} ${c.pull_request.source_repo.clone_url()}" readonly="readonly">
77 %elif h.is_git(c.pull_request.source_repo):
77 %elif h.is_git(c.pull_request.source_repo):
78 <input type="text" value="git pull ${c.pull_request.source_repo.clone_url()} ${c.pull_request.source_ref_parts.name}" readonly="readonly">
78 <input type="text" value="git pull ${c.pull_request.source_repo.clone_url()} ${c.pull_request.source_ref_parts.name}" readonly="readonly">
79 %endif
79 %endif
80 </div>
80 </div>
81 </div>
81 </div>
82 </div>
82 </div>
83 <div class="field">
83 <div class="field">
84 <div class="label-summary">
84 <div class="label-summary">
85 <label>${_('Target')}:</label>
85 <label>${_('Target')}:</label>
86 </div>
86 </div>
87 <div class="input">
87 <div class="input">
88 <div class="pr-targetinfo">
88 <div class="pr-targetinfo">
89 ## branch link is only valid if it is a branch
89 ## branch link is only valid if it is a branch
90 <span class="tag">
90 <span class="tag">
91 %if c.pull_request.target_ref_parts.type == 'branch':
91 %if c.pull_request.target_ref_parts.type == 'branch':
92 <a href="${h.url('changelog_home', repo_name=c.pull_request.target_repo.repo_name, branch=c.pull_request.target_ref_parts.name)}">${c.pull_request.target_ref_parts.type}: ${c.pull_request.target_ref_parts.name}</a>
92 <a href="${h.url('changelog_home', repo_name=c.pull_request.target_repo.repo_name, branch=c.pull_request.target_ref_parts.name)}">${c.pull_request.target_ref_parts.type}: ${c.pull_request.target_ref_parts.name}</a>
93 %else:
93 %else:
94 ${c.pull_request.target_ref_parts.type}: ${c.pull_request.target_ref_parts.name}
94 ${c.pull_request.target_ref_parts.type}: ${c.pull_request.target_ref_parts.name}
95 %endif
95 %endif
96 </span>
96 </span>
97 <span class="clone-url">
97 <span class="clone-url">
98 <a href="${h.url('summary_home', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.clone_url()}</a>
98 <a href="${h.url('summary_home', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.clone_url()}</a>
99 </span>
99 </span>
100 </div>
100 </div>
101 </div>
101 </div>
102 </div>
102 </div>
103 <div class="field">
103 <div class="field">
104 <div class="label-summary">
104 <div class="label-summary">
105 <label>${_('Review')}:</label>
105 <label>${_('Review')}:</label>
106 </div>
106 </div>
107 <div class="input">
107 <div class="input">
108 %if c.pull_request_review_status:
108 %if c.pull_request_review_status:
109 <div class="${'flag_status %s' % c.pull_request_review_status} tooltip pull-left"></div>
109 <div class="${'flag_status %s' % c.pull_request_review_status} tooltip pull-left"></div>
110 <span class="changeset-status-lbl tooltip">
110 <span class="changeset-status-lbl tooltip">
111 %if c.pull_request.is_closed():
111 %if c.pull_request.is_closed():
112 ${_('Closed')},
112 ${_('Closed')},
113 %endif
113 %endif
114 ${h.commit_status_lbl(c.pull_request_review_status)}
114 ${h.commit_status_lbl(c.pull_request_review_status)}
115 </span>
115 </span>
116 - ${ungettext('calculated based on %s reviewer vote', 'calculated based on %s reviewers votes', len(c.pull_request_reviewers)) % len(c.pull_request_reviewers)}
116 - ${ungettext('calculated based on %s reviewer vote', 'calculated based on %s reviewers votes', len(c.pull_request_reviewers)) % len(c.pull_request_reviewers)}
117 %endif
117 %endif
118 </div>
118 </div>
119 </div>
119 </div>
120 <div class="field">
120 <div class="field">
121 <div class="pr-description-label label-summary">
121 <div class="pr-description-label label-summary">
122 <label>${_('Description')}:</label>
122 <label>${_('Description')}:</label>
123 </div>
123 </div>
124 <div id="pr-desc" class="input">
124 <div id="pr-desc" class="input">
125 <div class="pr-description">${h.urlify_commit_message(c.pull_request.description, c.repo_name)}</div>
125 <div class="pr-description">${h.urlify_commit_message(c.pull_request.description, c.repo_name)}</div>
126 </div>
126 </div>
127 <div id="pr-desc-edit" class="input textarea editor" style="display: none;">
127 <div id="pr-desc-edit" class="input textarea editor" style="display: none;">
128 <textarea id="pr-description-input" size="30">${c.pull_request.description}</textarea>
128 <textarea id="pr-description-input" size="30">${c.pull_request.description}</textarea>
129 </div>
129 </div>
130 </div>
130 </div>
131 <div class="field">
131 <div class="field">
132 <div class="label-summary">
132 <div class="label-summary">
133 <label>${_('Comments')}:</label>
133 <label>${_('Comments')}:</label>
134 </div>
134 </div>
135 <div class="input">
135 <div class="input">
136 <div>
136 <div>
137 <div class="comments-number">
137 <div class="comments-number">
138 %if c.comments:
138 %if c.comments:
139 <a href="#comments">${ungettext("%d Pull request comment", "%d Pull request comments", len(c.comments)) % len(c.comments)}</a>,
139 <a href="#comments">${ungettext("%d Pull request comment", "%d Pull request comments", len(c.comments)) % len(c.comments)}</a>,
140 %else:
140 %else:
141 ${ungettext("%d Pull request comment", "%d Pull request comments", len(c.comments)) % len(c.comments)}
141 ${ungettext("%d Pull request comment", "%d Pull request comments", len(c.comments)) % len(c.comments)}
142 %endif
142 %endif
143 %if c.inline_cnt:
143 %if c.inline_cnt:
144 ## this is replaced with a proper link to first comment via JS linkifyComments() func
144 ## this is replaced with a proper link to first comment via JS linkifyComments() func
145 <a href="#inline-comments" id="inline-comments-counter">${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}</a>
145 <a href="#inline-comments" id="inline-comments-counter">${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}</a>
146 %else:
146 %else:
147 ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}
147 ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}
148 %endif
148 %endif
149
149
150 % if c.outdated_cnt:
150 % if c.outdated_cnt:
151 ,${ungettext("%d Outdated Comment", "%d Outdated Comments", c.outdated_cnt) % c.outdated_cnt} <span id="show-outdated-comments" class="btn btn-link">${_('(Show)')}</span>
151 ,${ungettext("%d Outdated Comment", "%d Outdated Comments", c.outdated_cnt) % c.outdated_cnt} <span id="show-outdated-comments" class="btn btn-link">${_('(Show)')}</span>
152 % endif
152 % endif
153 </div>
153 </div>
154 </div>
154 </div>
155 </div>
155 </div>
156 </div>
156 </div>
157 <div id="pr-save" class="field" style="display: none;">
157 <div id="pr-save" class="field" style="display: none;">
158 <div class="label-summary"></div>
158 <div class="label-summary"></div>
159 <div class="input">
159 <div class="input">
160 <span id="edit_pull_request" class="btn btn-small">${_('Save Changes')}</span>
160 <span id="edit_pull_request" class="btn btn-small">${_('Save Changes')}</span>
161 </div>
161 </div>
162 </div>
162 </div>
163 </div>
163 </div>
164 </div>
164 </div>
165 <div>
165 <div>
166 ## AUTHOR
166 ## AUTHOR
167 <div class="reviewers-title block-right">
167 <div class="reviewers-title block-right">
168 <div class="pr-details-title">
168 <div class="pr-details-title">
169 ${_('Author')}
169 ${_('Author')}
170 </div>
170 </div>
171 </div>
171 </div>
172 <div class="block-right pr-details-content reviewers">
172 <div class="block-right pr-details-content reviewers">
173 <ul class="group_members">
173 <ul class="group_members">
174 <li>
174 <li>
175 ${self.gravatar_with_user(c.pull_request.author.email, 16)}
175 ${self.gravatar_with_user(c.pull_request.author.email, 16)}
176 </li>
176 </li>
177 </ul>
177 </ul>
178 </div>
178 </div>
179 ## REVIEWERS
179 ## REVIEWERS
180 <div class="reviewers-title block-right">
180 <div class="reviewers-title block-right">
181 <div class="pr-details-title">
181 <div class="pr-details-title">
182 ${_('Pull request reviewers')}
182 ${_('Pull request reviewers')}
183 %if c.allowed_to_update:
183 %if c.allowed_to_update:
184 <span id="open_edit_reviewers" class="block-right action_button">${_('Edit')}</span>
184 <span id="open_edit_reviewers" class="block-right action_button">${_('Edit')}</span>
185 <span id="close_edit_reviewers" class="block-right action_button" style="display: none;">${_('Close')}</span>
185 <span id="close_edit_reviewers" class="block-right action_button" style="display: none;">${_('Close')}</span>
186 %endif
186 %endif
187 </div>
187 </div>
188 </div>
188 </div>
189 <div id="reviewers" class="block-right pr-details-content reviewers">
189 <div id="reviewers" class="block-right pr-details-content reviewers">
190 ## members goes here !
190 ## members goes here !
191 <ul id="review_members" class="group_members">
191 <ul id="review_members" class="group_members">
192 %for member,status in c.pull_request_reviewers:
192 %for member,status in c.pull_request_reviewers:
193 <li id="reviewer_${member.user_id}">
193 <li id="reviewer_${member.user_id}">
194 <div class="reviewers_member">
194 <div class="reviewers_member">
195 <div class="reviewer_status tooltip" title="${h.tooltip(h.commit_status_lbl(status[0][1].status if status else 'not_reviewed'))}">
195 <div class="reviewer_status tooltip" title="${h.tooltip(h.commit_status_lbl(status[0][1].status if status else 'not_reviewed'))}">
196 <div class="${'flag_status %s' % (status[0][1].status if status else 'not_reviewed')} pull-left reviewer_member_status"></div>
196 <div class="${'flag_status %s' % (status[0][1].status if status else 'not_reviewed')} pull-left reviewer_member_status"></div>
197 </div>
197 </div>
198 <div id="reviewer_${member.user_id}_name" class="reviewer_name">
198 <div id="reviewer_${member.user_id}_name" class="reviewer_name">
199 ${self.gravatar_with_user(member.email, 16)} <div class="reviewer">(${_('owner') if c.pull_request.user_id == member.user_id else _('reviewer')})</div>
199 ${self.gravatar_with_user(member.email, 16)} <div class="reviewer">(${_('owner') if c.pull_request.user_id == member.user_id else _('reviewer')})</div>
200 </div>
200 </div>
201 <input id="reviewer_${member.user_id}_input" type="hidden" value="${member.user_id}" name="review_members" />
201 <input id="reviewer_${member.user_id}_input" type="hidden" value="${member.user_id}" name="review_members" />
202 %if c.allowed_to_update:
202 %if c.allowed_to_update:
203 <div class="reviewer_member_remove action_button" onclick="removeReviewMember(${member.user_id}, true)" style="visibility: hidden;">
203 <div class="reviewer_member_remove action_button" onclick="removeReviewMember(${member.user_id}, true)" style="visibility: hidden;">
204 <i class="icon-remove-sign" ></i>
204 <i class="icon-remove-sign" ></i>
205 </div>
205 </div>
206 %endif
206 %endif
207 </div>
207 </div>
208 </li>
208 </li>
209 %endfor
209 %endfor
210 </ul>
210 </ul>
211 %if not c.pull_request.is_closed():
211 %if not c.pull_request.is_closed():
212 <div id="add_reviewer_input" class='ac' style="display: none;">
212 <div id="add_reviewer_input" class='ac' style="display: none;">
213 %if c.allowed_to_update:
213 %if c.allowed_to_update:
214 <div class="reviewer_ac">
214 <div class="reviewer_ac">
215 ${h.text('user', class_='ac-input', placeholder=_('Add reviewer'))}
215 ${h.text('user', class_='ac-input', placeholder=_('Add reviewer'))}
216 <div id="reviewers_container"></div>
216 <div id="reviewers_container"></div>
217 </div>
217 </div>
218 <div>
218 <div>
219 <span id="update_pull_request" class="btn btn-small">${_('Save Changes')}</span>
219 <span id="update_pull_request" class="btn btn-small">${_('Save Changes')}</span>
220 </div>
220 </div>
221 %endif
221 %endif
222 </div>
222 </div>
223 %endif
223 %endif
224 </div>
224 </div>
225 </div>
225 </div>
226 </div>
226 </div>
227 <div class="box">
227 <div class="box">
228 ##DIFF
228 ##DIFF
229 <div class="table" >
229 <div class="table" >
230 <div id="changeset_compare_view_content">
230 <div id="changeset_compare_view_content">
231 ##CS
231 ##CS
232 % if c.missing_requirements:
232 % if c.missing_requirements:
233 <div class="box">
233 <div class="box">
234 <div class="alert alert-warning">
234 <div class="alert alert-warning">
235 <div>
235 <div>
236 <strong>${_('Missing requirements:')}</strong>
236 <strong>${_('Missing requirements:')}</strong>
237 ${_('These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled.')}
237 ${_('These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled.')}
238 </div>
238 </div>
239 </div>
239 </div>
240 </div>
240 </div>
241 % elif c.missing_commits:
241 % elif c.missing_commits:
242 <div class="box">
242 <div class="box">
243 <div class="alert alert-warning">
243 <div class="alert alert-warning">
244 <div>
244 <div>
245 <strong>${_('Missing commits')}:</strong>
245 <strong>${_('Missing commits')}:</strong>
246 ${_('This pull request cannot be displayed, because one or more commits no longer exist in the source repository.')}
246 ${_('This pull request cannot be displayed, because one or more commits no longer exist in the source repository.')}
247 ${_('Please update this pull request, push the commits back into the source repository, or consider closing this pull request.')}
247 ${_('Please update this pull request, push the commits back into the source repository, or consider closing this pull request.')}
248 </div>
248 </div>
249 </div>
249 </div>
250 </div>
250 </div>
251 % endif
251 % endif
252 <div class="compare_view_commits_title">
252 <div class="compare_view_commits_title">
253 % if c.allowed_to_update and not c.pull_request.is_closed():
253 % if c.allowed_to_update and not c.pull_request.is_closed():
254 <button id="update_commits" class="btn btn-small">${_('Update commits')}</button>
254 <button id="update_commits" class="btn btn-small">${_('Update commits')}</button>
255 % endif
255 % endif
256 % if len(c.commit_ranges):
256 % if len(c.commit_ranges):
257 <h2>${ungettext('Compare View: %s commit','Compare View: %s commits', len(c.commit_ranges)) % len(c.commit_ranges)}</h2>
257 <h2>${ungettext('Compare View: %s commit','Compare View: %s commits', len(c.commit_ranges)) % len(c.commit_ranges)}</h2>
258 % endif
258 % endif
259 </div>
259 </div>
260 % if not c.missing_commits:
260 % if not c.missing_commits:
261 <%include file="/compare/compare_commits.html" />
261 <%include file="/compare/compare_commits.html" />
262 ## FILES
262 ## FILES
263 <div class="cs_files_title">
263 <div class="cs_files_title">
264 <span class="cs_files_expand">
264 <span class="cs_files_expand">
265 <span id="expand_all_files">${_('Expand All')}</span> | <span id="collapse_all_files">${_('Collapse All')}</span>
265 <span id="expand_all_files">${_('Expand All')}</span> | <span id="collapse_all_files">${_('Collapse All')}</span>
266 </span>
266 </span>
267 <h2>
267 <h2>
268 ${diff_block.diff_summary_text(len(c.files), c.lines_added, c.lines_deleted, c.limited_diff)}
268 ${diff_block.diff_summary_text(len(c.files), c.lines_added, c.lines_deleted, c.limited_diff)}
269 </h2>
269 </h2>
270 </div>
270 </div>
271 % endif
271 % endif
272 <div class="cs_files">
272 <div class="cs_files">
273 %if not c.files and not c.missing_commits:
273 %if not c.files and not c.missing_commits:
274 <span class="empty_data">${_('No files')}</span>
274 <span class="empty_data">${_('No files')}</span>
275 %endif
275 %endif
276 <table class="compare_view_files">
276 <table class="compare_view_files">
277 <%namespace name="diff_block" file="/changeset/diff_block.html"/>
277 <%namespace name="diff_block" file="/changeset/diff_block.html"/>
278 %for FID, change, path, stats in c.files:
278 %for FID, change, path, stats in c.files:
279 <tr class="cs_${change} collapse_file" fid="${FID}">
279 <tr class="cs_${change} collapse_file" fid="${FID}">
280 <td class="cs_icon_td">
280 <td class="cs_icon_td">
281 <span class="collapse_file_icon" fid="${FID}"></span>
281 <span class="collapse_file_icon" fid="${FID}"></span>
282 </td>
282 </td>
283 <td class="cs_icon_td">
283 <td class="cs_icon_td">
284 <div class="flag_status not_reviewed hidden"></div>
284 <div class="flag_status not_reviewed hidden"></div>
285 </td>
285 </td>
286 <td class="cs_${change}" id="a_${FID}">
286 <td class="cs_${change}" id="a_${FID}">
287 <div class="node">
287 <div class="node">
288 <a href="#a_${FID}">
288 <a href="#a_${FID}">
289 <i class="icon-file-${change.lower()}"></i>
289 <i class="icon-file-${change.lower()}"></i>
290 ${h.safe_unicode(path)}
290 ${h.safe_unicode(path)}
291 </a>
291 </a>
292 </div>
292 </div>
293 </td>
293 </td>
294 <td>
294 <td>
295 <div class="changes pull-right">${h.fancy_file_stats(stats)}</div>
295 <div class="changes pull-right">${h.fancy_file_stats(stats)}</div>
296 <div class="comment-bubble pull-right" data-path="${path}">
296 <div class="comment-bubble pull-right" data-path="${path}">
297 <i class="icon-comment"></i>
297 <i class="icon-comment"></i>
298 </div>
298 </div>
299 </td>
299 </td>
300 </tr>
300 </tr>
301 <tr fid="${FID}" id="diff_${FID}" class="diff_links">
301 <tr fid="${FID}" id="diff_${FID}" class="diff_links">
302 <td></td>
302 <td></td>
303 <td></td>
303 <td></td>
304 <td class="cs_${change}">
304 <td class="cs_${change}">
305 %if c.target_repo.repo_name == c.repo_name:
305 %if c.target_repo.repo_name == c.repo_name:
306 ${diff_block.diff_menu(c.repo_name, h.safe_unicode(path), c.target_ref, c.source_ref, change)}
306 ${diff_block.diff_menu(c.repo_name, h.safe_unicode(path), c.target_ref, c.source_ref, change)}
307 %else:
307 %else:
308 ## this is slightly different case later, since the other repo can have this
308 ## this is slightly different case later, since the other repo can have this
309 ## file in other state than the origin repo
309 ## file in other state than the origin repo
310 ${diff_block.diff_menu(c.target_repo.repo_name, h.safe_unicode(path), c.target_ref, c.source_ref, change)}
310 ${diff_block.diff_menu(c.target_repo.repo_name, h.safe_unicode(path), c.target_ref, c.source_ref, change)}
311 %endif
311 %endif
312 </td>
312 </td>
313 <td class="td-actions rc-form">
313 <td class="td-actions rc-form">
314 <div data-comment-id="${FID}" class="btn-link show-inline-comments comments-visible">
314 <div data-comment-id="${FID}" class="btn-link show-inline-comments comments-visible">
315 <span class="comments-show">${_('Show comments')}</span>
315 <span class="comments-show">${_('Show comments')}</span>
316 <span class="comments-hide">${_('Hide comments')}</span>
316 <span class="comments-hide">${_('Hide comments')}</span>
317 </div>
317 </div>
318 </td>
318 </td>
319 </tr>
319 </tr>
320 <tr id="tr_${FID}">
320 <tr id="tr_${FID}">
321 <td></td>
321 <td></td>
322 <td></td>
322 <td></td>
323 <td class="injected_diff" colspan="2">
323 <td class="injected_diff" colspan="2">
324 ${diff_block.diff_block_simple([c.changes[FID]])}
324 ${diff_block.diff_block_simple([c.changes[FID]])}
325 </td>
325 </td>
326 </tr>
326 </tr>
327
327
328 ## Loop through inline comments
328 ## Loop through inline comments
329 % if c.outdated_comments.get(path,False):
329 % if c.outdated_comments.get(path,False):
330 <tr class="outdated">
330 <tr class="outdated">
331 <td></td>
331 <td></td>
332 <td></td>
332 <td></td>
333 <td colspan="2">
333 <td colspan="2">
334 <p>${_('Outdated Inline Comments')}:</p>
334 <p>${_('Outdated Inline Comments')}:</p>
335 </td>
335 </td>
336 </tr>
336 </tr>
337 <tr class="outdated">
337 <tr class="outdated">
338 <td></td>
338 <td></td>
339 <td></td>
339 <td></td>
340 <td colspan="2" class="outdated_comment_block">
340 <td colspan="2" class="outdated_comment_block">
341 % for line, comments in c.outdated_comments[path].iteritems():
341 % for line, comments in c.outdated_comments[path].iteritems():
342 <div class="inline-comment-placeholder" path="${path}" target_id="${h.safeid(h.safe_unicode(path))}">
342 <div class="inline-comment-placeholder" path="${path}" target_id="${h.safeid(h.safe_unicode(path))}">
343 % for co in comments:
343 % for co in comments:
344 ${comment.comment_block_outdated(co)}
344 ${comment.comment_block_outdated(co)}
345 % endfor
345 % endfor
346 </div>
346 </div>
347 % endfor
347 % endfor
348 </td>
348 </td>
349 </tr>
349 </tr>
350 % endif
350 % endif
351 %endfor
351 %endfor
352 ## Loop through inline comments for deleted files
352 ## Loop through inline comments for deleted files
353 %for path in c.deleted_files:
353 %for path in c.deleted_files:
354 <tr class="outdated deleted">
354 <tr class="outdated deleted">
355 <td></td>
355 <td></td>
356 <td></td>
356 <td></td>
357 <td>${path}</td>
357 <td>${path}</td>
358 </tr>
358 </tr>
359 <tr class="outdated deleted">
359 <tr class="outdated deleted">
360 <td></td>
360 <td></td>
361 <td></td>
361 <td></td>
362 <td>(${_('Removed')})</td>
362 <td>(${_('Removed')})</td>
363 </tr>
363 </tr>
364 % if path in c.outdated_comments:
364 % if path in c.outdated_comments:
365 <tr class="outdated deleted">
365 <tr class="outdated deleted">
366 <td></td>
366 <td></td>
367 <td></td>
367 <td></td>
368 <td colspan="2">
368 <td colspan="2">
369 <p>${_('Outdated Inline Comments')}:</p>
369 <p>${_('Outdated Inline Comments')}:</p>
370 </td>
370 </td>
371 </tr>
371 </tr>
372 <tr class="outdated">
372 <tr class="outdated">
373 <td></td>
373 <td></td>
374 <td></td>
374 <td></td>
375 <td colspan="2" class="outdated_comment_block">
375 <td colspan="2" class="outdated_comment_block">
376 % for line, comments in c.outdated_comments[path].iteritems():
376 % for line, comments in c.outdated_comments[path].iteritems():
377 <div class="inline-comment-placeholder" path="${path}" target_id="${h.safeid(h.safe_unicode(path))}">
377 <div class="inline-comment-placeholder" path="${path}" target_id="${h.safeid(h.safe_unicode(path))}">
378 % for co in comments:
378 % for co in comments:
379 ${comment.comment_block_outdated(co)}
379 ${comment.comment_block_outdated(co)}
380 % endfor
380 % endfor
381 </div>
381 </div>
382 % endfor
382 % endfor
383 </td>
383 </td>
384 </tr>
384 </tr>
385 % endif
385 % endif
386 %endfor
386 %endfor
387 </table>
387 </table>
388 </div>
388 </div>
389 % if c.limited_diff:
389 % if c.limited_diff:
390 <h5>${_('Commit was too big and was cut off...')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("Showing a huge diff might take some time and resources")}')">${_('Show full diff')}</a></h5>
390 <h5>${_('Commit was too big and was cut off...')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("Showing a huge diff might take some time and resources")}')">${_('Show full diff')}</a></h5>
391 % endif
391 % endif
392 </div>
392 </div>
393 </div>
393 </div>
394
394
395 % if c.limited_diff:
395 % if c.limited_diff:
396 <p>${_('Commit was too big and was cut off...')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("Showing a huge diff might take some time and resources")}')">${_('Show full diff')}</a></p>
396 <p>${_('Commit was too big and was cut off...')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("Showing a huge diff might take some time and resources")}')">${_('Show full diff')}</a></p>
397 % endif
397 % endif
398
398
399 ## template for inline comment form
399 ## template for inline comment form
400 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
400 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
401 ${comment.comment_inline_form()}
401 ${comment.comment_inline_form()}
402
402
403 ## render comments and inlines
403 ## render comments and inlines
404 ${comment.generate_comments(include_pull_request=True, is_pull_request=True)}
404 ${comment.generate_comments(include_pull_request=True, is_pull_request=True)}
405
405
406 % if not c.pull_request.is_closed():
406 % if not c.pull_request.is_closed():
407 ## main comment form and it status
407 ## main comment form and it status
408 ${comment.comments(h.url('pullrequest_comment', repo_name=c.repo_name,
408 ${comment.comments(h.url('pullrequest_comment', repo_name=c.repo_name,
409 pull_request_id=c.pull_request.pull_request_id),
409 pull_request_id=c.pull_request.pull_request_id),
410 c.pull_request_review_status,
410 c.pull_request_review_status,
411 is_pull_request=True, change_status=c.allowed_to_change_status)}
411 is_pull_request=True, change_status=c.allowed_to_change_status)}
412 %endif
412 %endif
413
413
414 <script type="text/javascript">
414 <script type="text/javascript">
415 if (location.href.indexOf('#') != -1) {
415 if (location.hash) {
416 var id = '#'+location.href.substring(location.href.indexOf('#') + 1).split('#');
416 var result = splitDelimitedHash(location.hash);
417 var line = $('html').find(id);
417 var line = $('html').find(result.loc);
418 offsetScroll(line, 70);
418 offsetScroll(line, 70);
419 }
419 }
420 $(function(){
420 $(function(){
421 ReviewerAutoComplete('user');
421 ReviewerAutoComplete('user');
422 // custom code mirror
422 // custom code mirror
423 var codeMirrorInstance = initPullRequestsCodeMirror('#pr-description-input');
423 var codeMirrorInstance = initPullRequestsCodeMirror('#pr-description-input');
424
424
425 var PRDetails = {
425 var PRDetails = {
426 editButton: $('#open_edit_pullrequest'),
426 editButton: $('#open_edit_pullrequest'),
427 closeButton: $('#close_edit_pullrequest'),
427 closeButton: $('#close_edit_pullrequest'),
428 viewFields: $('#pr-desc, #pr-title'),
428 viewFields: $('#pr-desc, #pr-title'),
429 editFields: $('#pr-desc-edit, #pr-title-edit, #pr-save'),
429 editFields: $('#pr-desc-edit, #pr-title-edit, #pr-save'),
430
430
431 init: function() {
431 init: function() {
432 var that = this;
432 var that = this;
433 this.editButton.on('click', function(e) { that.edit(); });
433 this.editButton.on('click', function(e) { that.edit(); });
434 this.closeButton.on('click', function(e) { that.view(); });
434 this.closeButton.on('click', function(e) { that.view(); });
435 },
435 },
436
436
437 edit: function(event) {
437 edit: function(event) {
438 this.viewFields.hide();
438 this.viewFields.hide();
439 this.editButton.hide();
439 this.editButton.hide();
440 this.editFields.show();
440 this.editFields.show();
441 codeMirrorInstance.refresh();
441 codeMirrorInstance.refresh();
442 },
442 },
443
443
444 view: function(event) {
444 view: function(event) {
445 this.editFields.hide();
445 this.editFields.hide();
446 this.closeButton.hide();
446 this.closeButton.hide();
447 this.viewFields.show();
447 this.viewFields.show();
448 }
448 }
449 };
449 };
450
450
451 var ReviewersPanel = {
451 var ReviewersPanel = {
452 editButton: $('#open_edit_reviewers'),
452 editButton: $('#open_edit_reviewers'),
453 closeButton: $('#close_edit_reviewers'),
453 closeButton: $('#close_edit_reviewers'),
454 addButton: $('#add_reviewer_input'),
454 addButton: $('#add_reviewer_input'),
455 removeButtons: $('.reviewer_member_remove'),
455 removeButtons: $('.reviewer_member_remove'),
456
456
457 init: function() {
457 init: function() {
458 var that = this;
458 var that = this;
459 this.editButton.on('click', function(e) { that.edit(); });
459 this.editButton.on('click', function(e) { that.edit(); });
460 this.closeButton.on('click', function(e) { that.close(); });
460 this.closeButton.on('click', function(e) { that.close(); });
461 },
461 },
462
462
463 edit: function(event) {
463 edit: function(event) {
464 this.editButton.hide();
464 this.editButton.hide();
465 this.closeButton.show();
465 this.closeButton.show();
466 this.addButton.show();
466 this.addButton.show();
467 this.removeButtons.css('visibility', 'visible');
467 this.removeButtons.css('visibility', 'visible');
468 },
468 },
469
469
470 close: function(event) {
470 close: function(event) {
471 this.editButton.show();
471 this.editButton.show();
472 this.closeButton.hide();
472 this.closeButton.hide();
473 this.addButton.hide();
473 this.addButton.hide();
474 this.removeButtons.css('visibility', 'hidden');
474 this.removeButtons.css('visibility', 'hidden');
475 }
475 }
476 };
476 };
477
477
478 PRDetails.init();
478 PRDetails.init();
479 ReviewersPanel.init();
479 ReviewersPanel.init();
480
480
481 $('#show-outdated-comments').on('click', function(e){
481 $('#show-outdated-comments').on('click', function(e){
482 var button = $(this);
482 var button = $(this);
483 var outdated = $('.outdated');
483 var outdated = $('.outdated');
484 if (button.html() === "(Show)") {
484 if (button.html() === "(Show)") {
485 button.html("(Hide)");
485 button.html("(Hide)");
486 outdated.show();
486 outdated.show();
487 } else {
487 } else {
488 button.html("(Show)");
488 button.html("(Show)");
489 outdated.hide();
489 outdated.hide();
490 }
490 }
491 });
491 });
492
492
493 $('.show-inline-comments').on('change', function(e){
493 $('.show-inline-comments').on('change', function(e){
494 var show = 'none';
494 var show = 'none';
495 var target = e.currentTarget;
495 var target = e.currentTarget;
496 if(target.checked){
496 if(target.checked){
497 show = ''
497 show = ''
498 }
498 }
499 var boxid = $(target).attr('id_for');
499 var boxid = $(target).attr('id_for');
500 var comments = $('#{0} .inline-comments'.format(boxid));
500 var comments = $('#{0} .inline-comments'.format(boxid));
501 var fn_display = function(idx){
501 var fn_display = function(idx){
502 $(this).css('display', show);
502 $(this).css('display', show);
503 };
503 };
504 $(comments).each(fn_display);
504 $(comments).each(fn_display);
505 var btns = $('#{0} .inline-comments-button'.format(boxid));
505 var btns = $('#{0} .inline-comments-button'.format(boxid));
506 $(btns).each(fn_display);
506 $(btns).each(fn_display);
507 });
507 });
508
508
509 // inject comments into their proper positions
509 // inject comments into their proper positions
510 var file_comments = $('.inline-comment-placeholder');
510 var file_comments = $('.inline-comment-placeholder');
511 %if c.pull_request.is_closed():
511 %if c.pull_request.is_closed():
512 renderInlineComments(file_comments, false);
512 renderInlineComments(file_comments, false);
513 %else:
513 %else:
514 renderInlineComments(file_comments, true);
514 renderInlineComments(file_comments, true);
515 %endif
515 %endif
516 var commentTotals = {};
516 var commentTotals = {};
517 $.each(file_comments, function(i, comment) {
517 $.each(file_comments, function(i, comment) {
518 var path = $(comment).attr('path');
518 var path = $(comment).attr('path');
519 var comms = $(comment).children().length;
519 var comms = $(comment).children().length;
520 if (path in commentTotals) {
520 if (path in commentTotals) {
521 commentTotals[path] += comms;
521 commentTotals[path] += comms;
522 } else {
522 } else {
523 commentTotals[path] = comms;
523 commentTotals[path] = comms;
524 }
524 }
525 });
525 });
526 $.each(commentTotals, function(path, total) {
526 $.each(commentTotals, function(path, total) {
527 var elem = $('.comment-bubble[data-path="'+ path +'"]');
527 var elem = $('.comment-bubble[data-path="'+ path +'"]');
528 elem.css('visibility', 'visible');
528 elem.css('visibility', 'visible');
529 elem.html(elem.html() + ' ' + total );
529 elem.html(elem.html() + ' ' + total );
530 });
530 });
531
531
532 $('#merge_pull_request_form').submit(function() {
532 $('#merge_pull_request_form').submit(function() {
533 if (!$('#merge_pull_request').attr('disabled')) {
533 if (!$('#merge_pull_request').attr('disabled')) {
534 $('#merge_pull_request').attr('disabled', 'disabled');
534 $('#merge_pull_request').attr('disabled', 'disabled');
535 }
535 }
536 return true;
536 return true;
537 });
537 });
538
538
539 $('#edit_pull_request').on('click', function(e){
539 $('#edit_pull_request').on('click', function(e){
540 var title = $('#pr-title-input').val();
540 var title = $('#pr-title-input').val();
541 var description = codeMirrorInstance.getValue();
541 var description = codeMirrorInstance.getValue();
542 editPullRequest(
542 editPullRequest(
543 "${c.repo_name}", "${c.pull_request.pull_request_id}",
543 "${c.repo_name}", "${c.pull_request.pull_request_id}",
544 title, description);
544 title, description);
545 });
545 });
546
546
547 $('#update_pull_request').on('click', function(e){
547 $('#update_pull_request').on('click', function(e){
548 updateReviewers(undefined, "${c.repo_name}", "${c.pull_request.pull_request_id}");
548 updateReviewers(undefined, "${c.repo_name}", "${c.pull_request.pull_request_id}");
549 });
549 });
550
550
551 $('#update_commits').on('click', function(e){
551 $('#update_commits').on('click', function(e){
552 var isDisabled = !$(e.currentTarget).attr('disabled');
552 var isDisabled = !$(e.currentTarget).attr('disabled');
553 $(e.currentTarget).text(_gettext('Updating...'));
553 $(e.currentTarget).text(_gettext('Updating...'));
554 $(e.currentTarget).attr('disabled', 'disabled');
554 $(e.currentTarget).attr('disabled', 'disabled');
555 if(isDisabled){
555 if(isDisabled){
556 updateCommits("${c.repo_name}", "${c.pull_request.pull_request_id}");
556 updateCommits("${c.repo_name}", "${c.pull_request.pull_request_id}");
557 }
557 }
558
558
559 });
559 });
560 // fixing issue with caches on firefox
560 // fixing issue with caches on firefox
561 $('#update_commits').removeAttr("disabled");
561 $('#update_commits').removeAttr("disabled");
562
562
563 $('#close_pull_request').on('click', function(e){
563 $('#close_pull_request').on('click', function(e){
564 closePullRequest("${c.repo_name}", "${c.pull_request.pull_request_id}");
564 closePullRequest("${c.repo_name}", "${c.pull_request.pull_request_id}");
565 });
565 });
566
566
567 $('.show-inline-comments').on('click', function(e){
567 $('.show-inline-comments').on('click', function(e){
568 var boxid = $(this).attr('data-comment-id');
568 var boxid = $(this).attr('data-comment-id');
569 var button = $(this);
569 var button = $(this);
570
570
571 if(button.hasClass("comments-visible")) {
571 if(button.hasClass("comments-visible")) {
572 $('#{0} .inline-comments'.format(boxid)).each(function(index){
572 $('#{0} .inline-comments'.format(boxid)).each(function(index){
573 $(this).hide();
573 $(this).hide();
574 })
574 })
575 button.removeClass("comments-visible");
575 button.removeClass("comments-visible");
576 } else {
576 } else {
577 $('#{0} .inline-comments'.format(boxid)).each(function(index){
577 $('#{0} .inline-comments'.format(boxid)).each(function(index){
578 $(this).show();
578 $(this).show();
579 })
579 })
580 button.addClass("comments-visible");
580 button.addClass("comments-visible");
581 }
581 }
582 });
582 });
583 })
583 })
584 </script>
584 </script>
585
585
586 </div>
586 </div>
587 </div>
587 </div>
588
588
589 </%def>
589 </%def>
General Comments 0
You need to be logged in to leave comments. Login now