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