##// END OF EJS Templates
ux: add hidden comments indicators plus style tweaks...
dan -
r1157:ac063abc default
parent child Browse files
Show More
@@ -1,1142 +1,1167 b''
1 // Default styles
1 // Default styles
2
2
3 .diff-collapse {
3 .diff-collapse {
4 margin: @padding 0;
4 margin: @padding 0;
5 text-align: right;
5 text-align: right;
6 }
6 }
7
7
8 .diff-container {
8 .diff-container {
9 margin-bottom: @space;
9 margin-bottom: @space;
10
10
11 .diffblock {
11 .diffblock {
12 margin-bottom: @space;
12 margin-bottom: @space;
13 }
13 }
14
14
15 &.hidden {
15 &.hidden {
16 display: none;
16 display: none;
17 overflow: hidden;
17 overflow: hidden;
18 }
18 }
19 }
19 }
20
20
21 .compare_view_files {
21 .compare_view_files {
22
22
23 .diff-container {
23 .diff-container {
24
24
25 .diffblock {
25 .diffblock {
26 margin-bottom: 0;
26 margin-bottom: 0;
27 }
27 }
28 }
28 }
29 }
29 }
30
30
31 div.diffblock .sidebyside {
31 div.diffblock .sidebyside {
32 background: #ffffff;
32 background: #ffffff;
33 }
33 }
34
34
35 div.diffblock {
35 div.diffblock {
36 overflow-x: auto;
36 overflow-x: auto;
37 overflow-y: hidden;
37 overflow-y: hidden;
38 clear: both;
38 clear: both;
39 padding: 0px;
39 padding: 0px;
40 background: @grey6;
40 background: @grey6;
41 border: @border-thickness solid @grey5;
41 border: @border-thickness solid @grey5;
42 -webkit-border-radius: @border-radius @border-radius 0px 0px;
42 -webkit-border-radius: @border-radius @border-radius 0px 0px;
43 border-radius: @border-radius @border-radius 0px 0px;
43 border-radius: @border-radius @border-radius 0px 0px;
44
44
45
45
46 .comments-number {
46 .comments-number {
47 float: right;
47 float: right;
48 }
48 }
49
49
50 // BEGIN CODE-HEADER STYLES
50 // BEGIN CODE-HEADER STYLES
51
51
52 .code-header {
52 .code-header {
53 background: @grey6;
53 background: @grey6;
54 padding: 10px 0 10px 0;
54 padding: 10px 0 10px 0;
55 height: auto;
55 height: auto;
56 width: 100%;
56 width: 100%;
57
57
58 .hash {
58 .hash {
59 float: left;
59 float: left;
60 padding: 2px 0 0 2px;
60 padding: 2px 0 0 2px;
61 }
61 }
62
62
63 .date {
63 .date {
64 float: left;
64 float: left;
65 text-transform: uppercase;
65 text-transform: uppercase;
66 padding: 4px 0px 0px 2px;
66 padding: 4px 0px 0px 2px;
67 }
67 }
68
68
69 div {
69 div {
70 margin-left: 4px;
70 margin-left: 4px;
71 }
71 }
72
72
73 div.compare_header {
73 div.compare_header {
74 min-height: 40px;
74 min-height: 40px;
75 margin: 0;
75 margin: 0;
76 padding: 0 @padding;
76 padding: 0 @padding;
77
77
78 .drop-menu {
78 .drop-menu {
79 float:left;
79 float:left;
80 display: block;
80 display: block;
81 margin:0 0 @padding 0;
81 margin:0 0 @padding 0;
82 }
82 }
83
83
84 .compare-label {
84 .compare-label {
85 float: left;
85 float: left;
86 clear: both;
86 clear: both;
87 display: inline-block;
87 display: inline-block;
88 min-width: 5em;
88 min-width: 5em;
89 margin: 0;
89 margin: 0;
90 padding: @button-padding @button-padding @button-padding 0;
90 padding: @button-padding @button-padding @button-padding 0;
91 font-family: @text-semibold;
91 font-family: @text-semibold;
92 }
92 }
93
93
94 .compare-buttons {
94 .compare-buttons {
95 float: left;
95 float: left;
96 margin: 0;
96 margin: 0;
97 padding: 0 0 @padding;
97 padding: 0 0 @padding;
98
98
99 .btn {
99 .btn {
100 margin: 0 @padding 0 0;
100 margin: 0 @padding 0 0;
101 }
101 }
102 }
102 }
103 }
103 }
104
104
105 }
105 }
106
106
107 .parents {
107 .parents {
108 float: left;
108 float: left;
109 width: 100px;
109 width: 100px;
110 font-weight: 400;
110 font-weight: 400;
111 vertical-align: middle;
111 vertical-align: middle;
112 padding: 0px 2px 0px 2px;
112 padding: 0px 2px 0px 2px;
113 background-color: @grey6;
113 background-color: @grey6;
114
114
115 #parent_link {
115 #parent_link {
116 margin: 00px 2px;
116 margin: 00px 2px;
117
117
118 &.double {
118 &.double {
119 margin: 0px 2px;
119 margin: 0px 2px;
120 }
120 }
121
121
122 &.disabled{
122 &.disabled{
123 margin-right: @padding;
123 margin-right: @padding;
124 }
124 }
125 }
125 }
126 }
126 }
127
127
128 .children {
128 .children {
129 float: right;
129 float: right;
130 width: 100px;
130 width: 100px;
131 font-weight: 400;
131 font-weight: 400;
132 vertical-align: middle;
132 vertical-align: middle;
133 text-align: right;
133 text-align: right;
134 padding: 0px 2px 0px 2px;
134 padding: 0px 2px 0px 2px;
135 background-color: @grey6;
135 background-color: @grey6;
136
136
137 #child_link {
137 #child_link {
138 margin: 0px 2px;
138 margin: 0px 2px;
139
139
140 &.double {
140 &.double {
141 margin: 0px 2px;
141 margin: 0px 2px;
142 }
142 }
143
143
144 &.disabled{
144 &.disabled{
145 margin-right: @padding;
145 margin-right: @padding;
146 }
146 }
147 }
147 }
148 }
148 }
149
149
150 .changeset_header {
150 .changeset_header {
151 height: 16px;
151 height: 16px;
152
152
153 & > div{
153 & > div{
154 margin-right: @padding;
154 margin-right: @padding;
155 }
155 }
156 }
156 }
157
157
158 .changeset_file {
158 .changeset_file {
159 text-align: left;
159 text-align: left;
160 float: left;
160 float: left;
161 padding: 0;
161 padding: 0;
162
162
163 a{
163 a{
164 display: inline-block;
164 display: inline-block;
165 margin-right: 0.5em;
165 margin-right: 0.5em;
166 }
166 }
167
167
168 #selected_mode{
168 #selected_mode{
169 margin-left: 0;
169 margin-left: 0;
170 }
170 }
171 }
171 }
172
172
173 .diff-menu-wrapper {
173 .diff-menu-wrapper {
174 float: left;
174 float: left;
175 }
175 }
176
176
177 .diff-menu {
177 .diff-menu {
178 position: absolute;
178 position: absolute;
179 background: none repeat scroll 0 0 #FFFFFF;
179 background: none repeat scroll 0 0 #FFFFFF;
180 border-color: #003367 @grey3 @grey3;
180 border-color: #003367 @grey3 @grey3;
181 border-right: 1px solid @grey3;
181 border-right: 1px solid @grey3;
182 border-style: solid solid solid;
182 border-style: solid solid solid;
183 border-width: @border-thickness;
183 border-width: @border-thickness;
184 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
184 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
185 margin-top: 5px;
185 margin-top: 5px;
186 margin-left: 1px;
186 margin-left: 1px;
187 }
187 }
188
188
189 .diff-actions, .editor-actions {
189 .diff-actions, .editor-actions {
190 float: left;
190 float: left;
191
191
192 input{
192 input{
193 margin: 0 0.5em 0 0;
193 margin: 0 0.5em 0 0;
194 }
194 }
195 }
195 }
196
196
197 // END CODE-HEADER STYLES
197 // END CODE-HEADER STYLES
198
198
199 // BEGIN CODE-BODY STYLES
199 // BEGIN CODE-BODY STYLES
200
200
201 .code-body {
201 .code-body {
202 background: white;
202 background: white;
203 padding: 0;
203 padding: 0;
204 background-color: #ffffff;
204 background-color: #ffffff;
205 position: relative;
205 position: relative;
206 max-width: none;
206 max-width: none;
207 box-sizing: border-box;
207 box-sizing: border-box;
208 // TODO: johbo: Parent has overflow: auto, this forces the child here
208 // TODO: johbo: Parent has overflow: auto, this forces the child here
209 // to have the intended size and to scroll. Should be simplified.
209 // to have the intended size and to scroll. Should be simplified.
210 width: 100%;
210 width: 100%;
211 overflow-x: auto;
211 overflow-x: auto;
212 }
212 }
213
213
214 pre.raw {
214 pre.raw {
215 background: white;
215 background: white;
216 color: @grey1;
216 color: @grey1;
217 }
217 }
218 // END CODE-BODY STYLES
218 // END CODE-BODY STYLES
219
219
220 }
220 }
221
221
222
222
223 table.code-difftable {
223 table.code-difftable {
224 border-collapse: collapse;
224 border-collapse: collapse;
225 width: 99%;
225 width: 99%;
226 border-radius: 0px !important;
226 border-radius: 0px !important;
227
227
228 td {
228 td {
229 padding: 0 !important;
229 padding: 0 !important;
230 background: none !important;
230 background: none !important;
231 border: 0 !important;
231 border: 0 !important;
232 }
232 }
233
233
234 .context {
234 .context {
235 background: none repeat scroll 0 0 #DDE7EF;
235 background: none repeat scroll 0 0 #DDE7EF;
236 }
236 }
237
237
238 .add {
238 .add {
239 background: none repeat scroll 0 0 #DDFFDD;
239 background: none repeat scroll 0 0 #DDFFDD;
240
240
241 ins {
241 ins {
242 background: none repeat scroll 0 0 #AAFFAA;
242 background: none repeat scroll 0 0 #AAFFAA;
243 text-decoration: none;
243 text-decoration: none;
244 }
244 }
245 }
245 }
246
246
247 .del {
247 .del {
248 background: none repeat scroll 0 0 #FFDDDD;
248 background: none repeat scroll 0 0 #FFDDDD;
249
249
250 del {
250 del {
251 background: none repeat scroll 0 0 #FFAAAA;
251 background: none repeat scroll 0 0 #FFAAAA;
252 text-decoration: none;
252 text-decoration: none;
253 }
253 }
254 }
254 }
255
255
256 /** LINE NUMBERS **/
256 /** LINE NUMBERS **/
257 .lineno {
257 .lineno {
258 padding-left: 2px !important;
258 padding-left: 2px !important;
259 padding-right: 2px;
259 padding-right: 2px;
260 text-align: right;
260 text-align: right;
261 width: 32px;
261 width: 32px;
262 -moz-user-select: none;
262 -moz-user-select: none;
263 -webkit-user-select: none;
263 -webkit-user-select: none;
264 border-right: @border-thickness solid @grey5 !important;
264 border-right: @border-thickness solid @grey5 !important;
265 border-left: 0px solid #CCC !important;
265 border-left: 0px solid #CCC !important;
266 border-top: 0px solid #CCC !important;
266 border-top: 0px solid #CCC !important;
267 border-bottom: none !important;
267 border-bottom: none !important;
268
268
269 a {
269 a {
270 &:extend(pre);
270 &:extend(pre);
271 text-align: right;
271 text-align: right;
272 padding-right: 2px;
272 padding-right: 2px;
273 cursor: pointer;
273 cursor: pointer;
274 display: block;
274 display: block;
275 width: 32px;
275 width: 32px;
276 }
276 }
277 }
277 }
278
278
279 .context {
279 .context {
280 cursor: auto;
280 cursor: auto;
281 &:extend(pre);
281 &:extend(pre);
282 }
282 }
283
283
284 .lineno-inline {
284 .lineno-inline {
285 background: none repeat scroll 0 0 #FFF !important;
285 background: none repeat scroll 0 0 #FFF !important;
286 padding-left: 2px;
286 padding-left: 2px;
287 padding-right: 2px;
287 padding-right: 2px;
288 text-align: right;
288 text-align: right;
289 width: 30px;
289 width: 30px;
290 -moz-user-select: none;
290 -moz-user-select: none;
291 -webkit-user-select: none;
291 -webkit-user-select: none;
292 }
292 }
293
293
294 /** CODE **/
294 /** CODE **/
295 .code {
295 .code {
296 display: block;
296 display: block;
297 width: 100%;
297 width: 100%;
298
298
299 td {
299 td {
300 margin: 0;
300 margin: 0;
301 padding: 0;
301 padding: 0;
302 }
302 }
303
303
304 pre {
304 pre {
305 margin: 0;
305 margin: 0;
306 padding: 0;
306 padding: 0;
307 margin-left: .5em;
307 margin-left: .5em;
308 }
308 }
309 }
309 }
310 }
310 }
311
311
312
312
313 // Comments
313 // Comments
314
314
315 div.comment:target {
315 div.comment:target {
316 border-left: 6px solid @comment-highlight-color;
316 border-left: 6px solid @comment-highlight-color;
317 padding-left: 3px;
317 padding-left: 3px;
318 margin-left: -9px;
318 margin-left: -9px;
319 }
319 }
320
320
321 //TODO: anderson: can't get an absolute number out of anything, so had to put the
321 //TODO: anderson: can't get an absolute number out of anything, so had to put the
322 //current values that might change. But to make it clear I put as a calculation
322 //current values that might change. But to make it clear I put as a calculation
323 @comment-max-width: 1065px;
323 @comment-max-width: 1065px;
324 @pr-extra-margin: 34px;
324 @pr-extra-margin: 34px;
325 @pr-border-spacing: 4px;
325 @pr-border-spacing: 4px;
326 @pr-comment-width: @comment-max-width - @pr-extra-margin - @pr-border-spacing;
326 @pr-comment-width: @comment-max-width - @pr-extra-margin - @pr-border-spacing;
327
327
328 // Pull Request
328 // Pull Request
329 .cs_files .code-difftable {
329 .cs_files .code-difftable {
330 border: @border-thickness solid @grey5; //borders only on PRs
330 border: @border-thickness solid @grey5; //borders only on PRs
331
331
332 .comment-inline-form,
332 .comment-inline-form,
333 div.comment {
333 div.comment {
334 width: @pr-comment-width;
334 width: @pr-comment-width;
335 }
335 }
336 }
336 }
337
337
338 // Changeset
338 // Changeset
339 .code-difftable {
339 .code-difftable {
340 .comment-inline-form,
340 .comment-inline-form,
341 div.comment {
341 div.comment {
342 width: @comment-max-width;
342 width: @comment-max-width;
343 }
343 }
344 }
344 }
345
345
346 //Style page
346 //Style page
347 @style-extra-margin: @sidebar-width + (@sidebarpadding * 3) + @padding;
347 @style-extra-margin: @sidebar-width + (@sidebarpadding * 3) + @padding;
348 #style-page .code-difftable{
348 #style-page .code-difftable{
349 .comment-inline-form,
349 .comment-inline-form,
350 div.comment {
350 div.comment {
351 width: @comment-max-width - @style-extra-margin;
351 width: @comment-max-width - @style-extra-margin;
352 }
352 }
353 }
353 }
354
354
355 #context-bar > h2 {
355 #context-bar > h2 {
356 font-size: 20px;
356 font-size: 20px;
357 }
357 }
358
358
359 #context-bar > h2> a {
359 #context-bar > h2> a {
360 font-size: 20px;
360 font-size: 20px;
361 }
361 }
362 // end of defaults
362 // end of defaults
363
363
364 .file_diff_buttons {
364 .file_diff_buttons {
365 padding: 0 0 @padding;
365 padding: 0 0 @padding;
366
366
367 .drop-menu {
367 .drop-menu {
368 float: left;
368 float: left;
369 margin: 0 @padding 0 0;
369 margin: 0 @padding 0 0;
370 }
370 }
371 .btn {
371 .btn {
372 margin: 0 @padding 0 0;
372 margin: 0 @padding 0 0;
373 }
373 }
374 }
374 }
375
375
376 .code-body.textarea.editor {
376 .code-body.textarea.editor {
377 max-width: none;
377 max-width: none;
378 padding: 15px;
378 padding: 15px;
379 }
379 }
380
380
381 td.injected_diff{
381 td.injected_diff{
382 max-width: 1178px;
382 max-width: 1178px;
383 overflow-x: auto;
383 overflow-x: auto;
384 overflow-y: hidden;
384 overflow-y: hidden;
385
385
386 div.diff-container,
386 div.diff-container,
387 div.diffblock{
387 div.diffblock{
388 max-width: 100%;
388 max-width: 100%;
389 }
389 }
390
390
391 div.code-body {
391 div.code-body {
392 max-width: 1124px;
392 max-width: 1124px;
393 overflow-x: auto;
393 overflow-x: auto;
394 overflow-y: hidden;
394 overflow-y: hidden;
395 padding: 0;
395 padding: 0;
396 }
396 }
397 div.diffblock {
397 div.diffblock {
398 border: none;
398 border: none;
399 }
399 }
400
400
401 &.inline-form {
401 &.inline-form {
402 width: 99%
402 width: 99%
403 }
403 }
404 }
404 }
405
405
406
406
407 table.code-difftable {
407 table.code-difftable {
408 width: 100%;
408 width: 100%;
409 }
409 }
410
410
411 /** PYGMENTS COLORING **/
411 /** PYGMENTS COLORING **/
412 div.codeblock {
412 div.codeblock {
413
413
414 // TODO: johbo: Added interim to get rid of the margin around
414 // TODO: johbo: Added interim to get rid of the margin around
415 // Select2 widgets. This needs further cleanup.
415 // Select2 widgets. This needs further cleanup.
416 margin-top: @padding;
416 margin-top: @padding;
417
417
418 overflow: auto;
418 overflow: auto;
419 padding: 0px;
419 padding: 0px;
420 border: @border-thickness solid @grey5;
420 border: @border-thickness solid @grey5;
421 background: @grey6;
421 background: @grey6;
422 .border-radius(@border-radius);
422 .border-radius(@border-radius);
423
423
424 #remove_gist {
424 #remove_gist {
425 float: right;
425 float: right;
426 }
426 }
427
427
428 .author {
428 .author {
429 clear: both;
429 clear: both;
430 vertical-align: middle;
430 vertical-align: middle;
431 font-family: @text-bold;
431 font-family: @text-bold;
432 }
432 }
433
433
434 .btn-mini {
434 .btn-mini {
435 float: left;
435 float: left;
436 margin: 0 5px 0 0;
436 margin: 0 5px 0 0;
437 }
437 }
438
438
439 .code-header {
439 .code-header {
440 padding: @padding;
440 padding: @padding;
441 border-bottom: @border-thickness solid @grey5;
441 border-bottom: @border-thickness solid @grey5;
442
442
443 .rc-user {
443 .rc-user {
444 min-width: 0;
444 min-width: 0;
445 margin-right: .5em;
445 margin-right: .5em;
446 }
446 }
447
447
448 .stats {
448 .stats {
449 clear: both;
449 clear: both;
450 margin: 0 0 @padding 0;
450 margin: 0 0 @padding 0;
451 padding: 0;
451 padding: 0;
452 .left {
452 .left {
453 float: left;
453 float: left;
454 clear: left;
454 clear: left;
455 max-width: 75%;
455 max-width: 75%;
456 margin: 0 0 @padding 0;
456 margin: 0 0 @padding 0;
457
457
458 &.item {
458 &.item {
459 margin-right: @padding;
459 margin-right: @padding;
460 &.last { border-right: none; }
460 &.last { border-right: none; }
461 }
461 }
462 }
462 }
463 .buttons { float: right; }
463 .buttons { float: right; }
464 .author {
464 .author {
465 height: 25px; margin-left: 15px; font-weight: bold;
465 height: 25px; margin-left: 15px; font-weight: bold;
466 }
466 }
467 }
467 }
468
468
469 .commit {
469 .commit {
470 margin: 5px 0 0 26px;
470 margin: 5px 0 0 26px;
471 font-weight: normal;
471 font-weight: normal;
472 white-space: pre-wrap;
472 white-space: pre-wrap;
473 }
473 }
474 }
474 }
475
475
476 .message {
476 .message {
477 position: relative;
477 position: relative;
478 margin: @padding;
478 margin: @padding;
479
479
480 .codeblock-label {
480 .codeblock-label {
481 margin: 0 0 1em 0;
481 margin: 0 0 1em 0;
482 }
482 }
483 }
483 }
484
484
485 .code-body {
485 .code-body {
486 padding: @padding;
486 padding: @padding;
487 background-color: #ffffff;
487 background-color: #ffffff;
488 min-width: 100%;
488 min-width: 100%;
489 box-sizing: border-box;
489 box-sizing: border-box;
490 // TODO: johbo: Parent has overflow: auto, this forces the child here
490 // TODO: johbo: Parent has overflow: auto, this forces the child here
491 // to have the intended size and to scroll. Should be simplified.
491 // to have the intended size and to scroll. Should be simplified.
492 width: 100%;
492 width: 100%;
493 overflow-x: auto;
493 overflow-x: auto;
494 }
494 }
495 }
495 }
496
496
497 .code-highlighttable,
497 .code-highlighttable,
498 div.codeblock {
498 div.codeblock {
499
499
500 &.readme {
500 &.readme {
501 background-color: white;
501 background-color: white;
502 }
502 }
503
503
504 .markdown-block table {
504 .markdown-block table {
505 border-collapse: collapse;
505 border-collapse: collapse;
506
506
507 th,
507 th,
508 td {
508 td {
509 padding: .5em;
509 padding: .5em;
510 border: @border-thickness solid @border-default-color;
510 border: @border-thickness solid @border-default-color;
511 }
511 }
512 }
512 }
513
513
514 table {
514 table {
515 border: 0px;
515 border: 0px;
516 margin: 0;
516 margin: 0;
517 letter-spacing: normal;
517 letter-spacing: normal;
518
518
519
519
520 td {
520 td {
521 border: 0px;
521 border: 0px;
522 vertical-align: top;
522 vertical-align: top;
523 }
523 }
524 }
524 }
525 }
525 }
526
526
527 div.codeblock .code-header .search-path { padding: 0 0 0 10px; }
527 div.codeblock .code-header .search-path { padding: 0 0 0 10px; }
528 div.search-code-body {
528 div.search-code-body {
529 background-color: #ffffff; padding: 5px 0 5px 10px;
529 background-color: #ffffff; padding: 5px 0 5px 10px;
530 pre {
530 pre {
531 .match { background-color: #faffa6;}
531 .match { background-color: #faffa6;}
532 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
532 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
533 }
533 }
534 .code-highlighttable {
534 .code-highlighttable {
535 border-collapse: collapse;
535 border-collapse: collapse;
536
536
537 tr:hover {
537 tr:hover {
538 background: #fafafa;
538 background: #fafafa;
539 }
539 }
540 td.code {
540 td.code {
541 padding-left: 10px;
541 padding-left: 10px;
542 }
542 }
543 td.line {
543 td.line {
544 border-right: 1px solid #ccc !important;
544 border-right: 1px solid #ccc !important;
545 padding-right: 10px;
545 padding-right: 10px;
546 text-align: right;
546 text-align: right;
547 font-family: "Lucida Console",Monaco,monospace;
547 font-family: "Lucida Console",Monaco,monospace;
548 span {
548 span {
549 white-space: pre-wrap;
549 white-space: pre-wrap;
550 color: #666666;
550 color: #666666;
551 }
551 }
552 }
552 }
553 }
553 }
554 }
554 }
555
555
556 div.annotatediv { margin-left: 2px; margin-right: 4px; }
556 div.annotatediv { margin-left: 2px; margin-right: 4px; }
557 .code-highlight {
557 .code-highlight {
558 margin: 0; padding: 0; border-left: @border-thickness solid @grey5;
558 margin: 0; padding: 0; border-left: @border-thickness solid @grey5;
559 pre, .linenodiv pre { padding: 0 5px; margin: 0; }
559 pre, .linenodiv pre { padding: 0 5px; margin: 0; }
560 pre div:target {background-color: @comment-highlight-color !important;}
560 pre div:target {background-color: @comment-highlight-color !important;}
561 }
561 }
562
562
563 .linenos a { text-decoration: none; }
563 .linenos a { text-decoration: none; }
564
564
565 .CodeMirror-selected { background: @rchighlightblue; }
565 .CodeMirror-selected { background: @rchighlightblue; }
566 .CodeMirror-focused .CodeMirror-selected { background: @rchighlightblue; }
566 .CodeMirror-focused .CodeMirror-selected { background: @rchighlightblue; }
567 .CodeMirror ::selection { background: @rchighlightblue; }
567 .CodeMirror ::selection { background: @rchighlightblue; }
568 .CodeMirror ::-moz-selection { background: @rchighlightblue; }
568 .CodeMirror ::-moz-selection { background: @rchighlightblue; }
569
569
570 .code { display: block; border:0px !important; }
570 .code { display: block; border:0px !important; }
571 .code-highlight, /* TODO: dan: merge codehilite into code-highlight */
571 .code-highlight, /* TODO: dan: merge codehilite into code-highlight */
572 .codehilite {
572 .codehilite {
573 .hll { background-color: #ffffcc }
573 .hll { background-color: #ffffcc }
574 .c { color: #408080; font-style: italic } /* Comment */
574 .c { color: #408080; font-style: italic } /* Comment */
575 .err, .codehilite .err { border: @border-thickness solid #FF0000 } /* Error */
575 .err, .codehilite .err { border: @border-thickness solid #FF0000 } /* Error */
576 .k { color: #008000; font-weight: bold } /* Keyword */
576 .k { color: #008000; font-weight: bold } /* Keyword */
577 .o { color: #666666 } /* Operator */
577 .o { color: #666666 } /* Operator */
578 .cm { color: #408080; font-style: italic } /* Comment.Multiline */
578 .cm { color: #408080; font-style: italic } /* Comment.Multiline */
579 .cp { color: #BC7A00 } /* Comment.Preproc */
579 .cp { color: #BC7A00 } /* Comment.Preproc */
580 .c1 { color: #408080; font-style: italic } /* Comment.Single */
580 .c1 { color: #408080; font-style: italic } /* Comment.Single */
581 .cs { color: #408080; font-style: italic } /* Comment.Special */
581 .cs { color: #408080; font-style: italic } /* Comment.Special */
582 .gd { color: #A00000 } /* Generic.Deleted */
582 .gd { color: #A00000 } /* Generic.Deleted */
583 .ge { font-style: italic } /* Generic.Emph */
583 .ge { font-style: italic } /* Generic.Emph */
584 .gr { color: #FF0000 } /* Generic.Error */
584 .gr { color: #FF0000 } /* Generic.Error */
585 .gh { color: #000080; font-weight: bold } /* Generic.Heading */
585 .gh { color: #000080; font-weight: bold } /* Generic.Heading */
586 .gi { color: #00A000 } /* Generic.Inserted */
586 .gi { color: #00A000 } /* Generic.Inserted */
587 .go { color: #808080 } /* Generic.Output */
587 .go { color: #808080 } /* Generic.Output */
588 .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
588 .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
589 .gs { font-weight: bold } /* Generic.Strong */
589 .gs { font-weight: bold } /* Generic.Strong */
590 .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
590 .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
591 .gt { color: #0040D0 } /* Generic.Traceback */
591 .gt { color: #0040D0 } /* Generic.Traceback */
592 .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
592 .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
593 .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
593 .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
594 .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
594 .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
595 .kp { color: #008000 } /* Keyword.Pseudo */
595 .kp { color: #008000 } /* Keyword.Pseudo */
596 .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
596 .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
597 .kt { color: #B00040 } /* Keyword.Type */
597 .kt { color: #B00040 } /* Keyword.Type */
598 .m { color: #666666 } /* Literal.Number */
598 .m { color: #666666 } /* Literal.Number */
599 .s { color: #BA2121 } /* Literal.String */
599 .s { color: #BA2121 } /* Literal.String */
600 .na { color: #7D9029 } /* Name.Attribute */
600 .na { color: #7D9029 } /* Name.Attribute */
601 .nb { color: #008000 } /* Name.Builtin */
601 .nb { color: #008000 } /* Name.Builtin */
602 .nc { color: #0000FF; font-weight: bold } /* Name.Class */
602 .nc { color: #0000FF; font-weight: bold } /* Name.Class */
603 .no { color: #880000 } /* Name.Constant */
603 .no { color: #880000 } /* Name.Constant */
604 .nd { color: #AA22FF } /* Name.Decorator */
604 .nd { color: #AA22FF } /* Name.Decorator */
605 .ni { color: #999999; font-weight: bold } /* Name.Entity */
605 .ni { color: #999999; font-weight: bold } /* Name.Entity */
606 .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
606 .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
607 .nf { color: #0000FF } /* Name.Function */
607 .nf { color: #0000FF } /* Name.Function */
608 .nl { color: #A0A000 } /* Name.Label */
608 .nl { color: #A0A000 } /* Name.Label */
609 .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
609 .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
610 .nt { color: #008000; font-weight: bold } /* Name.Tag */
610 .nt { color: #008000; font-weight: bold } /* Name.Tag */
611 .nv { color: #19177C } /* Name.Variable */
611 .nv { color: #19177C } /* Name.Variable */
612 .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
612 .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
613 .w { color: #bbbbbb } /* Text.Whitespace */
613 .w { color: #bbbbbb } /* Text.Whitespace */
614 .mf { color: #666666 } /* Literal.Number.Float */
614 .mf { color: #666666 } /* Literal.Number.Float */
615 .mh { color: #666666 } /* Literal.Number.Hex */
615 .mh { color: #666666 } /* Literal.Number.Hex */
616 .mi { color: #666666 } /* Literal.Number.Integer */
616 .mi { color: #666666 } /* Literal.Number.Integer */
617 .mo { color: #666666 } /* Literal.Number.Oct */
617 .mo { color: #666666 } /* Literal.Number.Oct */
618 .sb { color: #BA2121 } /* Literal.String.Backtick */
618 .sb { color: #BA2121 } /* Literal.String.Backtick */
619 .sc { color: #BA2121 } /* Literal.String.Char */
619 .sc { color: #BA2121 } /* Literal.String.Char */
620 .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
620 .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
621 .s2 { color: #BA2121 } /* Literal.String.Double */
621 .s2 { color: #BA2121 } /* Literal.String.Double */
622 .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
622 .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
623 .sh { color: #BA2121 } /* Literal.String.Heredoc */
623 .sh { color: #BA2121 } /* Literal.String.Heredoc */
624 .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
624 .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
625 .sx { color: #008000 } /* Literal.String.Other */
625 .sx { color: #008000 } /* Literal.String.Other */
626 .sr { color: #BB6688 } /* Literal.String.Regex */
626 .sr { color: #BB6688 } /* Literal.String.Regex */
627 .s1 { color: #BA2121 } /* Literal.String.Single */
627 .s1 { color: #BA2121 } /* Literal.String.Single */
628 .ss { color: #19177C } /* Literal.String.Symbol */
628 .ss { color: #19177C } /* Literal.String.Symbol */
629 .bp { color: #008000 } /* Name.Builtin.Pseudo */
629 .bp { color: #008000 } /* Name.Builtin.Pseudo */
630 .vc { color: #19177C } /* Name.Variable.Class */
630 .vc { color: #19177C } /* Name.Variable.Class */
631 .vg { color: #19177C } /* Name.Variable.Global */
631 .vg { color: #19177C } /* Name.Variable.Global */
632 .vi { color: #19177C } /* Name.Variable.Instance */
632 .vi { color: #19177C } /* Name.Variable.Instance */
633 .il { color: #666666 } /* Literal.Number.Integer.Long */
633 .il { color: #666666 } /* Literal.Number.Integer.Long */
634 }
634 }
635
635
636 /* customized pre blocks for markdown/rst */
636 /* customized pre blocks for markdown/rst */
637 pre.literal-block, .codehilite pre{
637 pre.literal-block, .codehilite pre{
638 padding: @padding;
638 padding: @padding;
639 border: 1px solid @grey6;
639 border: 1px solid @grey6;
640 .border-radius(@border-radius);
640 .border-radius(@border-radius);
641 background-color: @grey7;
641 background-color: @grey7;
642 }
642 }
643
643
644
644
645 /* START NEW CODE BLOCK CSS */
645 /* START NEW CODE BLOCK CSS */
646
646
647 @cb-line-height: 18px;
647 @cb-line-height: 18px;
648 @cb-line-code-padding: 10px;
648 @cb-line-code-padding: 10px;
649 @cb-text-padding: 5px;
649 @cb-text-padding: 5px;
650
650
651 @pill-padding: 2px 7px;
651 @pill-padding: 2px 7px;
652
652
653 input.filediff-collapse-state {
653 input.filediff-collapse-state {
654 display: none;
654 display: none;
655
655
656 &:checked + .filediff { /* file diff is collapsed */
656 &:checked + .filediff { /* file diff is collapsed */
657 .cb {
657 .cb {
658 display: none
658 display: none
659 }
659 }
660 .filediff-collapse-indicator {
660 .filediff-collapse-indicator {
661 border-width: 9px 0 9px 15.6px;
661 border-width: 9px 0 9px 15.6px;
662 border-color: transparent transparent transparent #ccc;
662 border-color: transparent transparent transparent #ccc;
663 }
663 }
664 .filediff-menu {
664 .filediff-menu {
665 display: none;
665 display: none;
666 }
666 }
667 margin: -1px 0 0 0;
667 margin: -1px 0 0 0;
668 }
668 }
669
669
670 &+ .filediff { /* file diff is expanded */
670 &+ .filediff { /* file diff is expanded */
671 .filediff-collapse-indicator {
671 .filediff-collapse-indicator {
672 border-width: 15.6px 9px 0 9px;
672 border-width: 15.6px 9px 0 9px;
673 border-color: #ccc transparent transparent transparent;
673 border-color: #ccc transparent transparent transparent;
674 }
674 }
675 .filediff-menu {
675 .filediff-menu {
676 display: block;
676 display: block;
677 }
677 }
678 margin: 20px 0;
678 margin: 20px 0;
679 &:nth-child(2) {
679 &:nth-child(2) {
680 margin: 0;
680 margin: 0;
681 }
681 }
682 }
682 }
683 }
683 }
684 .cs_files {
684 .cs_files {
685 clear: both;
685 clear: both;
686 }
686 }
687
687
688 .diffset-menu {
688 .diffset-menu {
689 margin-bottom: 20px;
689 margin-bottom: 20px;
690 }
690 }
691 .diffset {
691 .diffset {
692 margin: 20px auto;
692 margin: 20px auto;
693 .diffset-heading {
693 .diffset-heading {
694 border: 1px solid @grey5;
694 border: 1px solid @grey5;
695 margin-bottom: -1px;
695 margin-bottom: -1px;
696 // margin-top: 20px;
696 // margin-top: 20px;
697 h2 {
697 h2 {
698 margin: 0;
698 margin: 0;
699 line-height: 38px;
699 line-height: 38px;
700 padding-left: 10px;
700 padding-left: 10px;
701 }
701 }
702 .btn {
702 .btn {
703 margin: 0;
703 margin: 0;
704 }
704 }
705 background: @grey6;
705 background: @grey6;
706 display: block;
706 display: block;
707 padding: 5px;
707 padding: 5px;
708 }
708 }
709 .diffset-heading-warning {
709 .diffset-heading-warning {
710 background: @alert3-inner;
710 background: @alert3-inner;
711 border: 1px solid @alert3;
711 border: 1px solid @alert3;
712 }
712 }
713 }
713 }
714 .pill {
714 .pill {
715 display: block;
715 display: block;
716 float: left;
716 float: left;
717 padding: @pill-padding;
717 padding: @pill-padding;
718 }
718 }
719 .pill-group {
719 .pill-group {
720 .pill {
720 .pill {
721 opacity: .8;
721 opacity: .8;
722 &:first-child {
722 &:first-child {
723 border-radius: @border-radius 0 0 @border-radius;
723 border-radius: @border-radius 0 0 @border-radius;
724 }
724 }
725 &:last-child {
725 &:last-child {
726 border-radius: 0 @border-radius @border-radius 0;
726 border-radius: 0 @border-radius @border-radius 0;
727 }
727 }
728 &:only-child {
728 &:only-child {
729 border-radius: @border-radius;
729 border-radius: @border-radius;
730 }
730 }
731 }
731 }
732 }
732 }
733
733
734 .filediff {
734 .filediff {
735 border: 1px solid @grey5;
735 border: 1px solid @grey5;
736
736
737 /* START OVERRIDES */
737 /* START OVERRIDES */
738 .code-highlight {
738 .code-highlight {
739 border: none; // TODO: remove this border from the global
739 border: none; // TODO: remove this border from the global
740 // .code-highlight, it doesn't belong there
740 // .code-highlight, it doesn't belong there
741 }
741 }
742 label {
742 label {
743 margin: 0; // TODO: remove this margin definition from global label
743 margin: 0; // TODO: remove this margin definition from global label
744 // it doesn't belong there - if margin on labels
744 // it doesn't belong there - if margin on labels
745 // are needed for a form they should be defined
745 // are needed for a form they should be defined
746 // in the form's class
746 // in the form's class
747 }
747 }
748 /* END OVERRIDES */
748 /* END OVERRIDES */
749
749
750 * {
750 * {
751 box-sizing: border-box;
751 box-sizing: border-box;
752 }
752 }
753 .filediff-anchor {
753 .filediff-anchor {
754 visibility: hidden;
754 visibility: hidden;
755 }
755 }
756 &:hover {
756 &:hover {
757 .filediff-anchor {
757 .filediff-anchor {
758 visibility: visible;
758 visibility: visible;
759 }
759 }
760 }
760 }
761
761
762 .filediff-collapse-indicator {
762 .filediff-collapse-indicator {
763 width: 0;
763 width: 0;
764 height: 0;
764 height: 0;
765 border-style: solid;
765 border-style: solid;
766 float: left;
766 float: left;
767 margin: 2px 2px 0 0;
767 margin: 2px 2px 0 0;
768 cursor: pointer;
768 cursor: pointer;
769 }
769 }
770
770
771 .filediff-heading {
771 .filediff-heading {
772 background: @grey7;
772 background: @grey7;
773 cursor: pointer;
773 cursor: pointer;
774 display: block;
774 display: block;
775 padding: 5px 10px;
775 padding: 5px 10px;
776 }
776 }
777 .filediff-heading:after {
777 .filediff-heading:after {
778 content: "";
778 content: "";
779 display: table;
779 display: table;
780 clear: both;
780 clear: both;
781 }
781 }
782 .filediff-heading:hover {
782 .filediff-heading:hover {
783 background: #e1e9f4 !important;
783 background: #e1e9f4 !important;
784 }
784 }
785
785
786 .filediff-menu {
786 .filediff-menu {
787 float: right;
787 float: right;
788
788
789 &> a, &> span {
789 &> a, &> span {
790 padding: 5px;
790 padding: 5px;
791 display: block;
791 display: block;
792 float: left
792 float: left
793 }
793 }
794 }
794 }
795
795
796 .pill {
796 .pill {
797 &[op="name"] {
797 &[op="name"] {
798 background: none;
798 background: none;
799 color: @grey2;
799 color: @grey2;
800 opacity: 1;
800 opacity: 1;
801 color: white;
801 color: white;
802 }
802 }
803 &[op="limited"] {
803 &[op="limited"] {
804 background: @grey2;
804 background: @grey2;
805 color: white;
805 color: white;
806 }
806 }
807 &[op="binary"] {
807 &[op="binary"] {
808 background: @color7;
808 background: @color7;
809 color: white;
809 color: white;
810 }
810 }
811 &[op="modified"] {
811 &[op="modified"] {
812 background: @alert1;
812 background: @alert1;
813 color: white;
813 color: white;
814 }
814 }
815 &[op="renamed"] {
815 &[op="renamed"] {
816 background: @color4;
816 background: @color4;
817 color: white;
817 color: white;
818 }
818 }
819 &[op="mode"] {
819 &[op="mode"] {
820 background: @grey3;
820 background: @grey3;
821 color: white;
821 color: white;
822 }
822 }
823 &[op="symlink"] {
823 &[op="symlink"] {
824 background: @color8;
824 background: @color8;
825 color: white;
825 color: white;
826 }
826 }
827
827
828 &[op="added"] { /* added lines */
828 &[op="added"] { /* added lines */
829 background: @alert1;
829 background: @alert1;
830 color: white;
830 color: white;
831 }
831 }
832 &[op="deleted"] { /* deleted lines */
832 &[op="deleted"] { /* deleted lines */
833 background: @alert2;
833 background: @alert2;
834 color: white;
834 color: white;
835 }
835 }
836
836
837 &[op="created"] { /* created file */
837 &[op="created"] { /* created file */
838 background: @alert1;
838 background: @alert1;
839 color: white;
839 color: white;
840 }
840 }
841 &[op="removed"] { /* deleted file */
841 &[op="removed"] { /* deleted file */
842 background: @color5;
842 background: @color5;
843 color: white;
843 color: white;
844 }
844 }
845 }
845 }
846
846
847 .filediff-collapse-button, .filediff-expand-button {
847 .filediff-collapse-button, .filediff-expand-button {
848 cursor: pointer;
848 cursor: pointer;
849 }
849 }
850 .filediff-collapse-button {
850 .filediff-collapse-button {
851 display: inline;
851 display: inline;
852 }
852 }
853 .filediff-expand-button {
853 .filediff-expand-button {
854 display: none;
854 display: none;
855 }
855 }
856 .filediff-collapsed .filediff-collapse-button {
856 .filediff-collapsed .filediff-collapse-button {
857 display: none;
857 display: none;
858 }
858 }
859 .filediff-collapsed .filediff-expand-button {
859 .filediff-collapsed .filediff-expand-button {
860 display: inline;
860 display: inline;
861 }
861 }
862
862
863 @comment-padding: 5px;
863 @comment-padding: 5px;
864
864
865 /**** COMMENTS ****/
865 /**** COMMENTS ****/
866
866
867 .filediff-menu {
867 .filediff-menu {
868 .show-comment-button {
868 .show-comment-button {
869 display: none;
869 display: none;
870 }
870 }
871 }
871 }
872 &.hide-comments {
872 &.hide-comments {
873 .inline-comments {
873 .inline-comments {
874 display: none;
874 display: none;
875 }
875 }
876 .filediff-menu {
876 .filediff-menu {
877 .show-comment-button {
877 .show-comment-button {
878 display: inline;
878 display: inline;
879 }
879 }
880 .show-comment-button {
880 .hide-comment-button {
881 display: none;
881 display: none;
882 }
882 }
883 }
883 }
884 }
884 }
885
886 .hide-line-comments {
887 .inline-comments {
888 display: none;
889 }
890 }
885 .inline-comments {
891 .inline-comments {
886 border-radius: @border-radius;
892 border-radius: @border-radius;
887 background: @grey6;
893 background: @grey6;
888 .comment {
894 .comment {
889 margin: 0;
895 margin: 0;
890 border-radius: @border-radius;
896 border-radius: @border-radius;
891 }
897 }
892 .comment-outdated {
898 .comment-outdated {
893 opacity: 0.5;
899 opacity: 0.5;
894 }
900 }
895 .comment-inline {
901 .comment-inline {
896 background: white;
902 background: white;
897 padding: (@comment-padding + 3px) @comment-padding;
903 padding: (@comment-padding + 3px) @comment-padding;
898 border: @comment-padding solid @grey6;
904 border: @comment-padding solid @grey6;
899
905
900 .text {
906 .text {
901 border: none;
907 border: none;
902 }
908 }
903 .meta {
909 .meta {
904 border-bottom: 1px solid @grey6;
910 border-bottom: 1px solid @grey6;
905 padding-bottom: 10px;
911 padding-bottom: 10px;
906 }
912 }
907 }
913 }
908 .comment-selected {
914 .comment-selected {
909 border-left: 6px solid @comment-highlight-color;
915 border-left: 6px solid @comment-highlight-color;
910 }
916 }
911 .comment-inline-form {
917 .comment-inline-form {
912 padding: @comment-padding;
918 padding: @comment-padding;
913 display: none;
919 display: none;
914 }
920 }
915 .cb-comment-add-button {
921 .cb-comment-add-button {
916 margin: @comment-padding;
922 margin: @comment-padding;
917 }
923 }
918 /* hide add comment button when form is open */
924 /* hide add comment button when form is open */
919 .comment-inline-form-open + .cb-comment-add-button {
925 .comment-inline-form-open + .cb-comment-add-button {
920 display: none;
926 display: none;
921 }
927 }
922 .comment-inline-form-open {
928 .comment-inline-form-open {
923 display: block;
929 display: block;
924 }
930 }
925 /* hide add comment button when form but no comments */
931 /* hide add comment button when form but no comments */
926 .comment-inline-form:first-child + .cb-comment-add-button {
932 .comment-inline-form:first-child + .cb-comment-add-button {
927 display: none;
933 display: none;
928 }
934 }
929 /* hide add comment button when no comments or form */
935 /* hide add comment button when no comments or form */
930 .cb-comment-add-button:first-child {
936 .cb-comment-add-button:first-child {
931 display: none;
937 display: none;
932 }
938 }
933 /* hide add comment button when only comment is being deleted */
939 /* hide add comment button when only comment is being deleted */
934 .comment-deleting:first-child + .cb-comment-add-button {
940 .comment-deleting:first-child + .cb-comment-add-button {
935 display: none;
941 display: none;
936 }
942 }
937 }
943 }
938 /**** END COMMENTS ****/
944 /**** END COMMENTS ****/
939
945
940 }
946 }
941
947
942
948
943 table.cb {
949 table.cb {
944 width: 100%;
950 width: 100%;
945 border-collapse: collapse;
951 border-collapse: collapse;
946
952
947 .cb-text {
953 .cb-text {
948 padding: @cb-text-padding;
954 padding: @cb-text-padding;
949 }
955 }
950 .cb-hunk {
956 .cb-hunk {
951 padding: @cb-text-padding;
957 padding: @cb-text-padding;
952 }
958 }
953 .cb-expand {
959 .cb-expand {
954 display: none;
960 display: none;
955 }
961 }
956 .cb-collapse {
962 .cb-collapse {
957 display: inline;
963 display: inline;
958 }
964 }
959 &.cb-collapsed {
965 &.cb-collapsed {
960 .cb-line {
966 .cb-line {
961 display: none;
967 display: none;
962 }
968 }
963 .cb-expand {
969 .cb-expand {
964 display: inline;
970 display: inline;
965 }
971 }
966 .cb-collapse {
972 .cb-collapse {
967 display: none;
973 display: none;
968 }
974 }
969 }
975 }
970
976
971 /* intentionally general selector since .cb-line-selected must override it
977 /* intentionally general selector since .cb-line-selected must override it
972 and they both use !important since the td itself may have a random color
978 and they both use !important since the td itself may have a random color
973 generated by annotation blocks. TLDR: if you change it, make sure
979 generated by annotation blocks. TLDR: if you change it, make sure
974 annotated block selection and line selection in file view still work */
980 annotated block selection and line selection in file view still work */
975 .cb-line-fresh .cb-content {
981 .cb-line-fresh .cb-content {
976 background: white !important;
982 background: white !important;
977 }
983 }
978 .cb-warning {
984 .cb-warning {
979 background: #fff4dd;
985 background: #fff4dd;
980 }
986 }
981
987
982 &.cb-diff-sideside {
988 &.cb-diff-sideside {
983 td {
989 td {
984 &.cb-content {
990 &.cb-content {
985 width: 50%;
991 width: 50%;
986 }
992 }
987 }
993 }
988 }
994 }
989
995
990 tr {
996 tr {
991 &.cb-annotate {
997 &.cb-annotate {
992 border-top: 1px solid #eee;
998 border-top: 1px solid #eee;
993
999
994 &+ .cb-line {
1000 &+ .cb-line {
995 border-top: 1px solid #eee;
1001 border-top: 1px solid #eee;
996 }
1002 }
997
1003
998 &:first-child {
1004 &:first-child {
999 border-top: none;
1005 border-top: none;
1000 &+ .cb-line {
1006 &+ .cb-line {
1001 border-top: none;
1007 border-top: none;
1002 }
1008 }
1003 }
1009 }
1004 }
1010 }
1005
1011
1006 &.cb-hunk {
1012 &.cb-hunk {
1007 font-family: @font-family-monospace;
1013 font-family: @font-family-monospace;
1008 color: rgba(0, 0, 0, 0.3);
1014 color: rgba(0, 0, 0, 0.3);
1009
1015
1010 td {
1016 td {
1011 &:first-child {
1017 &:first-child {
1012 background: #edf2f9;
1018 background: #edf2f9;
1013 }
1019 }
1014 &:last-child {
1020 &:last-child {
1015 background: #f4f7fb;
1021 background: #f4f7fb;
1016 }
1022 }
1017 }
1023 }
1018 }
1024 }
1019 }
1025 }
1020
1026
1021 td {
1027 td {
1022 vertical-align: top;
1028 vertical-align: top;
1023 padding: 0;
1029 padding: 0;
1024
1030
1025 &.cb-content {
1031 &.cb-content {
1026 font-size: 12.35px;
1032 font-size: 12.35px;
1027
1033
1028 &.cb-line-selected .cb-code {
1034 &.cb-line-selected .cb-code {
1029 background: @comment-highlight-color !important;
1035 background: @comment-highlight-color !important;
1030 }
1036 }
1031
1037
1032 span.cb-code {
1038 span.cb-code {
1033 line-height: @cb-line-height;
1039 line-height: @cb-line-height;
1034 padding-left: @cb-line-code-padding;
1040 padding-left: @cb-line-code-padding;
1035 padding-right: @cb-line-code-padding;
1041 padding-right: @cb-line-code-padding;
1036 display: block;
1042 display: block;
1037 white-space: pre-wrap;
1043 white-space: pre-wrap;
1038 font-family: @font-family-monospace;
1044 font-family: @font-family-monospace;
1039 word-break: break-word;
1045 word-break: break-word;
1046 .nonl {
1047 color: @color5;
1048 }
1040 }
1049 }
1041
1050
1042 &> button.cb-comment-box-opener {
1051 &> button.cb-comment-box-opener {
1043 padding: 2px 6px 2px 6px;
1052 padding: 2px 6px 2px 6px;
1044 margin-left: -20px;
1053 margin-left: -20px;
1045 margin-top: -2px;
1054 margin-top: -2px;
1046 border-radius: @border-radius;
1055 border-radius: @border-radius;
1047 position: absolute;
1056 position: absolute;
1048 display: none;
1057 display: none;
1049 }
1058 }
1050 .cb-comment {
1059 .cb-comment {
1051 margin-top: 10px;
1060 margin-top: 10px;
1052 white-space: normal;
1061 white-space: normal;
1053 }
1062 }
1054 }
1063 }
1055 &:hover {
1064 &:hover {
1056 button.cb-comment-box-opener {
1065 button.cb-comment-box-opener {
1057 display: block;
1066 display: block;
1058 }
1067 }
1059 &+ td button.cb-comment-box-opener {
1068 &+ td button.cb-comment-box-opener {
1060 display: block
1069 display: block
1061 }
1070 }
1062 }
1071 }
1063
1072
1073 &.cb-data {
1074 text-align: right;
1075 width: 30px;
1076 font-family: @font-family-monospace;
1077
1078 .icon-comment {
1079 cursor: pointer;
1080 }
1081 &.cb-line-selected > div {
1082 display: block;
1083 background: @comment-highlight-color !important;
1084 line-height: @cb-line-height;
1085 color: rgba(0, 0, 0, 0.3);
1086 }
1087 }
1088
1064 &.cb-lineno {
1089 &.cb-lineno {
1065 padding: 0;
1090 padding: 0;
1066 width: 50px;
1091 width: 50px;
1067 color: rgba(0, 0, 0, 0.3);
1092 color: rgba(0, 0, 0, 0.3);
1068 text-align: right;
1093 text-align: right;
1069 border-right: 1px solid #eee;
1094 border-right: 1px solid #eee;
1070 font-family: @font-family-monospace;
1095 font-family: @font-family-monospace;
1071
1096
1072 a::before {
1097 a::before {
1073 content: attr(data-line-no);
1098 content: attr(data-line-no);
1074 }
1099 }
1075 &.cb-line-selected a {
1100 &.cb-line-selected a {
1076 background: @comment-highlight-color !important;
1101 background: @comment-highlight-color !important;
1077 }
1102 }
1078
1103
1079 a {
1104 a {
1080 display: block;
1105 display: block;
1081 padding-right: @cb-line-code-padding;
1106 padding-right: @cb-line-code-padding;
1082 padding-left: @cb-line-code-padding;
1107 padding-left: @cb-line-code-padding;
1083 line-height: @cb-line-height;
1108 line-height: @cb-line-height;
1084 color: rgba(0, 0, 0, 0.3);
1109 color: rgba(0, 0, 0, 0.3);
1085 }
1110 }
1086 }
1111 }
1087
1112
1088 &.cb-empty {
1113 &.cb-empty {
1089 background: @grey7;
1114 background: @grey7;
1090 }
1115 }
1091
1116
1092 ins {
1117 ins {
1093 color: black;
1118 color: black;
1094 background: #a6f3a6;
1119 background: #a6f3a6;
1095 text-decoration: none;
1120 text-decoration: none;
1096 }
1121 }
1097 del {
1122 del {
1098 color: black;
1123 color: black;
1099 background: #f8cbcb;
1124 background: #f8cbcb;
1100 text-decoration: none;
1125 text-decoration: none;
1101 }
1126 }
1102 &.cb-addition {
1127 &.cb-addition {
1103 background: #ecffec;
1128 background: #ecffec;
1104
1129
1105 &.blob-lineno {
1130 &.blob-lineno {
1106 background: #ddffdd;
1131 background: #ddffdd;
1107 }
1132 }
1108 }
1133 }
1109 &.cb-deletion {
1134 &.cb-deletion {
1110 background: #ffecec;
1135 background: #ffecec;
1111
1136
1112 &.blob-lineno {
1137 &.blob-lineno {
1113 background: #ffdddd;
1138 background: #ffdddd;
1114 }
1139 }
1115 }
1140 }
1116
1141
1117 &.cb-annotate-info {
1142 &.cb-annotate-info {
1118 width: 320px;
1143 width: 320px;
1119 min-width: 320px;
1144 min-width: 320px;
1120 max-width: 320px;
1145 max-width: 320px;
1121 padding: 5px 2px;
1146 padding: 5px 2px;
1122 font-size: 13px;
1147 font-size: 13px;
1123
1148
1124 strong.cb-annotate-message {
1149 strong.cb-annotate-message {
1125 padding: 5px 0;
1150 padding: 5px 0;
1126 white-space: pre-line;
1151 white-space: pre-line;
1127 display: inline-block;
1152 display: inline-block;
1128 }
1153 }
1129 .rc-user {
1154 .rc-user {
1130 float: none;
1155 float: none;
1131 padding: 0 6px 0 17px;
1156 padding: 0 6px 0 17px;
1132 min-width: auto;
1157 min-width: auto;
1133 min-height: auto;
1158 min-height: auto;
1134 }
1159 }
1135 }
1160 }
1136
1161
1137 &.cb-annotate-revision {
1162 &.cb-annotate-revision {
1138 cursor: pointer;
1163 cursor: pointer;
1139 text-align: right;
1164 text-align: right;
1140 }
1165 }
1141 }
1166 }
1142 }
1167 }
@@ -1,492 +1,494 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 // scroll an element `percent`% from the top of page in `time` ms
232 // scroll an element `percent`% from the top of page in `time` ms
233 function scrollToElement(element, percent, time) {
233 function scrollToElement(element, percent, time) {
234 percent = (percent === undefined ? 25 : percent);
234 percent = (percent === undefined ? 25 : percent);
235 time = (time === undefined ? 100 : time);
235 time = (time === undefined ? 100 : time);
236
236
237 var $element = $(element);
237 var $element = $(element);
238 var elOffset = $element.offset().top;
238 var elOffset = $element.offset().top;
239 var elHeight = $element.height();
239 var elHeight = $element.height();
240 var windowHeight = $(window).height();
240 var windowHeight = $(window).height();
241 var offset = elOffset;
241 var offset = elOffset;
242 if (elHeight < windowHeight) {
242 if (elHeight < windowHeight) {
243 offset = elOffset - ((windowHeight / (100 / percent)) - (elHeight / 2));
243 offset = elOffset - ((windowHeight / (100 / percent)) - (elHeight / 2));
244 }
244 }
245 setTimeout(function() {
245 setTimeout(function() {
246 $('html, body').animate({ scrollTop: offset});
246 $('html, body').animate({ scrollTop: offset});
247 }, time);
247 }, time);
248 }
248 }
249
249
250 /**
250 /**
251 * global hooks after DOM is loaded
251 * global hooks after DOM is loaded
252 */
252 */
253 $(document).ready(function() {
253 $(document).ready(function() {
254 firefoxAnchorFix();
254 firefoxAnchorFix();
255
255
256 $('.navigation a.menulink').on('click', function(e){
256 $('.navigation a.menulink').on('click', function(e){
257 var menuitem = $(this).parent('li');
257 var menuitem = $(this).parent('li');
258 if (menuitem.hasClass('open')) {
258 if (menuitem.hasClass('open')) {
259 menuitem.removeClass('open');
259 menuitem.removeClass('open');
260 } else {
260 } else {
261 menuitem.addClass('open');
261 menuitem.addClass('open');
262 $(document).on('click', function(event) {
262 $(document).on('click', function(event) {
263 if (!$(event.target).closest(menuitem).length) {
263 if (!$(event.target).closest(menuitem).length) {
264 menuitem.removeClass('open');
264 menuitem.removeClass('open');
265 }
265 }
266 });
266 });
267 }
267 }
268 });
268 });
269 $('.compare_view_files').on(
269 $('.compare_view_files').on(
270 'mouseenter mouseleave', 'tr.line .lineno a',function(event) {
270 'mouseenter mouseleave', 'tr.line .lineno a',function(event) {
271 if (event.type === "mouseenter") {
271 if (event.type === "mouseenter") {
272 $(this).parents('tr.line').addClass('hover');
272 $(this).parents('tr.line').addClass('hover');
273 } else {
273 } else {
274 $(this).parents('tr.line').removeClass('hover');
274 $(this).parents('tr.line').removeClass('hover');
275 }
275 }
276 });
276 });
277
277
278 $('.compare_view_files').on(
278 $('.compare_view_files').on(
279 'mouseenter mouseleave', 'tr.line .add-comment-line a',function(event){
279 'mouseenter mouseleave', 'tr.line .add-comment-line a',function(event){
280 if (event.type === "mouseenter") {
280 if (event.type === "mouseenter") {
281 $(this).parents('tr.line').addClass('commenting');
281 $(this).parents('tr.line').addClass('commenting');
282 } else {
282 } else {
283 $(this).parents('tr.line').removeClass('commenting');
283 $(this).parents('tr.line').removeClass('commenting');
284 }
284 }
285 });
285 });
286
286
287 $('body').on( /* TODO: replace the $('.compare_view_files').on('click') below
287 $('body').on( /* TODO: replace the $('.compare_view_files').on('click') below
288 when new diffs are integrated */
288 when new diffs are integrated */
289 'click', '.cb-lineno a', function(event) {
289 'click', '.cb-lineno a', function(event) {
290
290
291 if ($(this).attr('data-line-no') !== ""){
291 if ($(this).attr('data-line-no') !== ""){
292 $('.cb-line-selected').removeClass('cb-line-selected');
292 $('.cb-line-selected').removeClass('cb-line-selected');
293 var td = $(this).parent();
293 var td = $(this).parent();
294 td.addClass('cb-line-selected'); // line number td
294 td.addClass('cb-line-selected'); // line number td
295 td.prev().addClass('cb-line-selected'); // line data td
295 td.next().addClass('cb-line-selected'); // line content td
296 td.next().addClass('cb-line-selected'); // line content td
296
297
297 // Replace URL without jumping to it if browser supports.
298 // Replace URL without jumping to it if browser supports.
298 // Default otherwise
299 // Default otherwise
299 if (history.pushState) {
300 if (history.pushState) {
300 var new_location = location.href.rstrip('#');
301 var new_location = location.href.rstrip('#');
301 if (location.hash) {
302 if (location.hash) {
302 new_location = new_location.replace(location.hash, "");
303 new_location = new_location.replace(location.hash, "");
303 }
304 }
304
305
305 // Make new anchor url
306 // Make new anchor url
306 new_location = new_location + $(this).attr('href');
307 new_location = new_location + $(this).attr('href');
307 history.pushState(true, document.title, new_location);
308 history.pushState(true, document.title, new_location);
308
309
309 return false;
310 return false;
310 }
311 }
311 }
312 }
312 });
313 });
313
314
314 $('.compare_view_files').on( /* TODO: replace this with .cb function above
315 $('.compare_view_files').on( /* TODO: replace this with .cb function above
315 when new diffs are integrated */
316 when new diffs are integrated */
316 'click', 'tr.line .lineno a',function(event) {
317 'click', 'tr.line .lineno a',function(event) {
317 if ($(this).text() != ""){
318 if ($(this).text() != ""){
318 $('tr.line').removeClass('selected');
319 $('tr.line').removeClass('selected');
319 $(this).parents("tr.line").addClass('selected');
320 $(this).parents("tr.line").addClass('selected');
320
321
321 // Replace URL without jumping to it if browser supports.
322 // Replace URL without jumping to it if browser supports.
322 // Default otherwise
323 // Default otherwise
323 if (history.pushState) {
324 if (history.pushState) {
324 var new_location = location.href;
325 var new_location = location.href;
325 if (location.hash){
326 if (location.hash){
326 new_location = new_location.replace(location.hash, "");
327 new_location = new_location.replace(location.hash, "");
327 }
328 }
328
329
329 // Make new anchor url
330 // Make new anchor url
330 var new_location = new_location+$(this).attr('href');
331 var new_location = new_location+$(this).attr('href');
331 history.pushState(true, document.title, new_location);
332 history.pushState(true, document.title, new_location);
332
333
333 return false;
334 return false;
334 }
335 }
335 }
336 }
336 });
337 });
337
338
338 $('.compare_view_files').on(
339 $('.compare_view_files').on(
339 'click', 'tr.line .add-comment-line a',function(event) {
340 'click', 'tr.line .add-comment-line a',function(event) {
340 var tr = $(event.currentTarget).parents('tr.line')[0];
341 var tr = $(event.currentTarget).parents('tr.line')[0];
341 injectInlineForm(tr);
342 injectInlineForm(tr);
342 return false;
343 return false;
343 });
344 });
344
345
345 $('.collapse_file').on('click', function(e) {
346 $('.collapse_file').on('click', function(e) {
346 e.stopPropagation();
347 e.stopPropagation();
347 if ($(e.target).is('a')) { return; }
348 if ($(e.target).is('a')) { return; }
348 var node = $(e.delegateTarget).first();
349 var node = $(e.delegateTarget).first();
349 var icon = $($(node.children().first()).children().first());
350 var icon = $($(node.children().first()).children().first());
350 var id = node.attr('fid');
351 var id = node.attr('fid');
351 var target = $('#'+id);
352 var target = $('#'+id);
352 var tr = $('#tr_'+id);
353 var tr = $('#tr_'+id);
353 var diff = $('#diff_'+id);
354 var diff = $('#diff_'+id);
354 if(node.hasClass('expand_file')){
355 if(node.hasClass('expand_file')){
355 node.removeClass('expand_file');
356 node.removeClass('expand_file');
356 icon.removeClass('expand_file_icon');
357 icon.removeClass('expand_file_icon');
357 node.addClass('collapse_file');
358 node.addClass('collapse_file');
358 icon.addClass('collapse_file_icon');
359 icon.addClass('collapse_file_icon');
359 diff.show();
360 diff.show();
360 tr.show();
361 tr.show();
361 target.show();
362 target.show();
362 } else {
363 } else {
363 node.removeClass('collapse_file');
364 node.removeClass('collapse_file');
364 icon.removeClass('collapse_file_icon');
365 icon.removeClass('collapse_file_icon');
365 node.addClass('expand_file');
366 node.addClass('expand_file');
366 icon.addClass('expand_file_icon');
367 icon.addClass('expand_file_icon');
367 diff.hide();
368 diff.hide();
368 tr.hide();
369 tr.hide();
369 target.hide();
370 target.hide();
370 }
371 }
371 });
372 });
372
373
373 $('#expand_all_files').click(function() {
374 $('#expand_all_files').click(function() {
374 $('.expand_file').each(function() {
375 $('.expand_file').each(function() {
375 var node = $(this);
376 var node = $(this);
376 var icon = $($(node.children().first()).children().first());
377 var icon = $($(node.children().first()).children().first());
377 var id = $(this).attr('fid');
378 var id = $(this).attr('fid');
378 var target = $('#'+id);
379 var target = $('#'+id);
379 var tr = $('#tr_'+id);
380 var tr = $('#tr_'+id);
380 var diff = $('#diff_'+id);
381 var diff = $('#diff_'+id);
381 node.removeClass('expand_file');
382 node.removeClass('expand_file');
382 icon.removeClass('expand_file_icon');
383 icon.removeClass('expand_file_icon');
383 node.addClass('collapse_file');
384 node.addClass('collapse_file');
384 icon.addClass('collapse_file_icon');
385 icon.addClass('collapse_file_icon');
385 diff.show();
386 diff.show();
386 tr.show();
387 tr.show();
387 target.show();
388 target.show();
388 });
389 });
389 });
390 });
390
391
391 $('#collapse_all_files').click(function() {
392 $('#collapse_all_files').click(function() {
392 $('.collapse_file').each(function() {
393 $('.collapse_file').each(function() {
393 var node = $(this);
394 var node = $(this);
394 var icon = $($(node.children().first()).children().first());
395 var icon = $($(node.children().first()).children().first());
395 var id = $(this).attr('fid');
396 var id = $(this).attr('fid');
396 var target = $('#'+id);
397 var target = $('#'+id);
397 var tr = $('#tr_'+id);
398 var tr = $('#tr_'+id);
398 var diff = $('#diff_'+id);
399 var diff = $('#diff_'+id);
399 node.removeClass('collapse_file');
400 node.removeClass('collapse_file');
400 icon.removeClass('collapse_file_icon');
401 icon.removeClass('collapse_file_icon');
401 node.addClass('expand_file');
402 node.addClass('expand_file');
402 icon.addClass('expand_file_icon');
403 icon.addClass('expand_file_icon');
403 diff.hide();
404 diff.hide();
404 tr.hide();
405 tr.hide();
405 target.hide();
406 target.hide();
406 });
407 });
407 });
408 });
408
409
409 // Mouse over behavior for comments and line selection
410 // Mouse over behavior for comments and line selection
410
411
411 // Select the line that comes from the url anchor
412 // Select the line that comes from the url anchor
412 // At the time of development, Chrome didn't seem to support jquery's :target
413 // At the time of development, Chrome didn't seem to support jquery's :target
413 // element, so I had to scroll manually
414 // element, so I had to scroll manually
414
415
415 if (location.hash) { /* TODO: dan: remove this and replace with code block
416 if (location.hash) { /* TODO: dan: remove this and replace with code block
416 below when new diffs are ready */
417 below when new diffs are ready */
417 var result = splitDelimitedHash(location.hash);
418 var result = splitDelimitedHash(location.hash);
418 var loc = result.loc;
419 var loc = result.loc;
419 if (loc.length > 1){
420 if (loc.length > 1){
420 var lineno = $(loc+'.lineno');
421 var lineno = $(loc+'.lineno');
421 if (lineno.length > 0){
422 if (lineno.length > 0){
422 var tr = lineno.parents('tr.line');
423 var tr = lineno.parents('tr.line');
423 tr.addClass('selected');
424 tr.addClass('selected');
424
425
425 tr[0].scrollIntoView();
426 tr[0].scrollIntoView();
426
427
427 $.Topic('/ui/plugins/code/anchor_focus').prepareOrPublish({
428 $.Topic('/ui/plugins/code/anchor_focus').prepareOrPublish({
428 tr: tr,
429 tr: tr,
429 remainder: result.remainder});
430 remainder: result.remainder});
430 }
431 }
431 }
432 }
432 }
433 }
433
434
434 if (location.hash) { /* TODO: dan: use this to replace the code block above
435 if (location.hash) { /* TODO: dan: use this to replace the code block above
435 when new diffs are ready */
436 when new diffs are ready */
436 var result = splitDelimitedHash(location.hash);
437 var result = splitDelimitedHash(location.hash);
437 var loc = result.loc;
438 var loc = result.loc;
438 if (loc.length > 1) {
439 if (loc.length > 1) {
439
440
440 var highlightable_line_tds = [];
441 var highlightable_line_tds = [];
441
442
442 // source code line format
443 // source code line format
443 var page_highlights = loc.substring(
444 var page_highlights = loc.substring(
444 loc.indexOf('#') + 1).split('L');
445 loc.indexOf('#') + 1).split('L');
445
446
446 if (page_highlights.length > 1) {
447 if (page_highlights.length > 1) {
447 var highlight_ranges = page_highlights[1].split(",");
448 var highlight_ranges = page_highlights[1].split(",");
448 var h_lines = [];
449 var h_lines = [];
449 for (var pos in highlight_ranges) {
450 for (var pos in highlight_ranges) {
450 var _range = highlight_ranges[pos].split('-');
451 var _range = highlight_ranges[pos].split('-');
451 if (_range.length === 2) {
452 if (_range.length === 2) {
452 var start = parseInt(_range[0]);
453 var start = parseInt(_range[0]);
453 var end = parseInt(_range[1]);
454 var end = parseInt(_range[1]);
454 if (start < end) {
455 if (start < end) {
455 for (var i = start; i <= end; i++) {
456 for (var i = start; i <= end; i++) {
456 h_lines.push(i);
457 h_lines.push(i);
457 }
458 }
458 }
459 }
459 }
460 }
460 else {
461 else {
461 h_lines.push(parseInt(highlight_ranges[pos]));
462 h_lines.push(parseInt(highlight_ranges[pos]));
462 }
463 }
463 }
464 }
464 for (pos in h_lines) {
465 for (pos in h_lines) {
465 var line_td = $('td.cb-lineno#L' + h_lines[pos]);
466 var line_td = $('td.cb-lineno#L' + h_lines[pos]);
466 if (line_td.length) {
467 if (line_td.length) {
467 highlightable_line_tds.push(line_td);
468 highlightable_line_tds.push(line_td);
468 }
469 }
469 }
470 }
470 }
471 }
471
472
472 // now check a direct id reference (diff page)
473 // now check a direct id reference (diff page)
473 if ($(loc).length && $(loc).hasClass('cb-lineno')) {
474 if ($(loc).length && $(loc).hasClass('cb-lineno')) {
474 highlightable_line_tds.push($(loc));
475 highlightable_line_tds.push($(loc));
475 }
476 }
476 $.each(highlightable_line_tds, function (i, $td) {
477 $.each(highlightable_line_tds, function (i, $td) {
477 $td.addClass('cb-line-selected'); // line number td
478 $td.addClass('cb-line-selected'); // line number td
479 $td.prev().addClass('cb-line-selected'); // line data
478 $td.next().addClass('cb-line-selected'); // line content
480 $td.next().addClass('cb-line-selected'); // line content
479 });
481 });
480
482
481 if (highlightable_line_tds.length) {
483 if (highlightable_line_tds.length) {
482 var $first_line_td = highlightable_line_tds[0];
484 var $first_line_td = highlightable_line_tds[0];
483 scrollToElement($first_line_td);
485 scrollToElement($first_line_td);
484 $.Topic('/ui/plugins/code/anchor_focus').prepareOrPublish({
486 $.Topic('/ui/plugins/code/anchor_focus').prepareOrPublish({
485 lineno: $first_line_td,
487 lineno: $first_line_td,
486 remainder: result.remainder
488 remainder: result.remainder
487 });
489 });
488 }
490 }
489 }
491 }
490 }
492 }
491 collapsableContent();
493 collapsableContent();
492 });
494 });
@@ -1,672 +1,897 b''
1 // # Copyright (C) 2010-2016 RhodeCode GmbH
1 // # Copyright (C) 2010-2016 RhodeCode GmbH
2 // #
2 // #
3 // # This program is free software: you can redistribute it and/or modify
3 // # This program is free software: you can redistribute it and/or modify
4 // # it under the terms of the GNU Affero General Public License, version 3
4 // # it under the terms of the GNU Affero General Public License, version 3
5 // # (only), as published by the Free Software Foundation.
5 // # (only), as published by the Free Software Foundation.
6 // #
6 // #
7 // # This program is distributed in the hope that it will be useful,
7 // # This program is distributed in the hope that it will be useful,
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // # GNU General Public License for more details.
10 // # GNU General Public License for more details.
11 // #
11 // #
12 // # You should have received a copy of the GNU Affero General Public License
12 // # You should have received a copy of the GNU Affero General Public License
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 // #
14 // #
15 // # This program is dual-licensed. If you wish to learn more about the
15 // # This program is dual-licensed. If you wish to learn more about the
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 var firefoxAnchorFix = function() {
19 var firefoxAnchorFix = function() {
20 // hack to make anchor links behave properly on firefox, in our inline
20 // hack to make anchor links behave properly on firefox, in our inline
21 // comments generation when comments are injected firefox is misbehaving
21 // comments generation when comments are injected firefox is misbehaving
22 // when jumping to anchor links
22 // when jumping to anchor links
23 if (location.href.indexOf('#') > -1) {
23 if (location.href.indexOf('#') > -1) {
24 location.href += '';
24 location.href += '';
25 }
25 }
26 };
26 };
27
27
28 // returns a node from given html;
28 // returns a node from given html;
29 var fromHTML = function(html){
29 var fromHTML = function(html){
30 var _html = document.createElement('element');
30 var _html = document.createElement('element');
31 _html.innerHTML = html;
31 _html.innerHTML = html;
32 return _html;
32 return _html;
33 };
33 };
34
34
35 var tableTr = function(cls, body){
35 var tableTr = function(cls, body){
36 var _el = document.createElement('div');
36 var _el = document.createElement('div');
37 var _body = $(body).attr('id');
37 var _body = $(body).attr('id');
38 var comment_id = fromHTML(body).children[0].id.split('comment-')[1];
38 var comment_id = fromHTML(body).children[0].id.split('comment-')[1];
39 var id = 'comment-tr-{0}'.format(comment_id);
39 var id = 'comment-tr-{0}'.format(comment_id);
40 var _html = ('<table><tbody><tr id="{0}" class="{1}">'+
40 var _html = ('<table><tbody><tr id="{0}" class="{1}">'+
41 '<td class="add-comment-line tooltip tooltip" title="Add Comment"><span class="add-comment-content"></span></td>'+
41 '<td class="add-comment-line tooltip tooltip" title="Add Comment"><span class="add-comment-content"></span></td>'+
42 '<td></td>'+
42 '<td></td>'+
43 '<td></td>'+
43 '<td></td>'+
44 '<td></td>'+
44 '<td></td>'+
45 '<td>{2}</td>'+
45 '<td>{2}</td>'+
46 '</tr></tbody></table>').format(id, cls, body);
46 '</tr></tbody></table>').format(id, cls, body);
47 $(_el).html(_html);
47 $(_el).html(_html);
48 return _el.children[0].children[0].children[0];
48 return _el.children[0].children[0].children[0];
49 };
49 };
50
50
51 var removeInlineForm = function(form) {
51 var removeInlineForm = function(form) {
52 form.parentNode.removeChild(form);
52 form.parentNode.removeChild(form);
53 };
53 };
54
54
55 var createInlineForm = function(parent_tr, f_path, line) {
55 var createInlineForm = function(parent_tr, f_path, line) {
56 var tmpl = $('#comment-inline-form-template').html();
56 var tmpl = $('#comment-inline-form-template').html();
57 tmpl = tmpl.format(f_path, line);
57 tmpl = tmpl.format(f_path, line);
58 var form = tableTr('comment-form-inline', tmpl);
58 var form = tableTr('comment-form-inline', tmpl);
59 var form_hide_button = $(form).find('.hide-inline-form');
59 var form_hide_button = $(form).find('.hide-inline-form');
60
60
61 $(form_hide_button).click(function(e) {
61 $(form_hide_button).click(function(e) {
62 $('.inline-comments').removeClass('hide-comment-button');
62 $('.inline-comments').removeClass('hide-comment-button');
63 var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode;
63 var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode;
64 if ($(newtr.nextElementSibling).hasClass('inline-comments-button')) {
64 if ($(newtr.nextElementSibling).hasClass('inline-comments-button')) {
65 $(newtr.nextElementSibling).show();
65 $(newtr.nextElementSibling).show();
66 }
66 }
67 $(newtr).parents('.comment-form-inline').remove();
67 $(newtr).parents('.comment-form-inline').remove();
68 $(parent_tr).removeClass('form-open');
68 $(parent_tr).removeClass('form-open');
69 $(parent_tr).removeClass('hl-comment');
69 $(parent_tr).removeClass('hl-comment');
70 });
70 });
71
71
72 return form;
72 return form;
73 };
73 };
74
74
75 var getLineNo = function(tr) {
75 var getLineNo = function(tr) {
76 var line;
76 var line;
77 // Try to get the id and return "" (empty string) if it doesn't exist
77 // Try to get the id and return "" (empty string) if it doesn't exist
78 var o = ($(tr).find('.lineno.old').attr('id')||"").split('_');
78 var o = ($(tr).find('.lineno.old').attr('id')||"").split('_');
79 var n = ($(tr).find('.lineno.new').attr('id')||"").split('_');
79 var n = ($(tr).find('.lineno.new').attr('id')||"").split('_');
80 if (n.length >= 2) {
80 if (n.length >= 2) {
81 line = n[n.length-1];
81 line = n[n.length-1];
82 } else if (o.length >= 2) {
82 } else if (o.length >= 2) {
83 line = o[o.length-1];
83 line = o[o.length-1];
84 }
84 }
85 return line;
85 return line;
86 };
86 };
87
87
88 /**
88 /**
89 * make a single inline comment and place it inside
89 * make a single inline comment and place it inside
90 */
90 */
91 var renderInlineComment = function(json_data, show_add_button) {
91 var renderInlineComment = function(json_data, show_add_button) {
92 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
92 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
93 try {
93 try {
94 var html = json_data.rendered_text;
94 var html = json_data.rendered_text;
95 var lineno = json_data.line_no;
95 var lineno = json_data.line_no;
96 var target_id = json_data.target_id;
96 var target_id = json_data.target_id;
97 placeInline(target_id, lineno, html, show_add_button);
97 placeInline(target_id, lineno, html, show_add_button);
98 } catch (e) {
98 } catch (e) {
99 console.error(e);
99 console.error(e);
100 }
100 }
101 };
101 };
102
102
103 function bindDeleteCommentButtons() {
103 function bindDeleteCommentButtons() {
104 $('.delete-comment').one('click', function() {
104 $('.delete-comment').one('click', function() {
105 var comment_id = $(this).data("comment-id");
105 var comment_id = $(this).data("comment-id");
106
106
107 if (comment_id){
107 if (comment_id){
108 deleteComment(comment_id);
108 deleteComment(comment_id);
109 }
109 }
110 });
110 });
111 }
111 }
112
112
113 /**
113 /**
114 * Inject inline comment for on given TR this tr should be always an .line
114 * Inject inline comment for on given TR this tr should be always an .line
115 * tr containing the line. Code will detect comment, and always put the comment
115 * tr containing the line. Code will detect comment, and always put the comment
116 * block at the very bottom
116 * block at the very bottom
117 */
117 */
118 var injectInlineForm = function(tr){
118 var injectInlineForm = function(tr){
119 if (!$(tr).hasClass('line')) {
119 if (!$(tr).hasClass('line')) {
120 return;
120 return;
121 }
121 }
122
122
123 var _td = $(tr).find('.code').get(0);
123 var _td = $(tr).find('.code').get(0);
124 if ($(tr).hasClass('form-open') ||
124 if ($(tr).hasClass('form-open') ||
125 $(tr).hasClass('context') ||
125 $(tr).hasClass('context') ||
126 $(_td).hasClass('no-comment')) {
126 $(_td).hasClass('no-comment')) {
127 return;
127 return;
128 }
128 }
129 $(tr).addClass('form-open');
129 $(tr).addClass('form-open');
130 $(tr).addClass('hl-comment');
130 $(tr).addClass('hl-comment');
131 var node = $(tr.parentNode.parentNode.parentNode).find('.full_f_path').get(0);
131 var node = $(tr.parentNode.parentNode.parentNode).find('.full_f_path').get(0);
132 var f_path = $(node).attr('path');
132 var f_path = $(node).attr('path');
133 var lineno = getLineNo(tr);
133 var lineno = getLineNo(tr);
134 var form = createInlineForm(tr, f_path, lineno);
134 var form = createInlineForm(tr, f_path, lineno);
135
135
136 var parent = tr;
136 var parent = tr;
137 while (1) {
137 while (1) {
138 var n = parent.nextElementSibling;
138 var n = parent.nextElementSibling;
139 // next element are comments !
139 // next element are comments !
140 if ($(n).hasClass('inline-comments')) {
140 if ($(n).hasClass('inline-comments')) {
141 parent = n;
141 parent = n;
142 }
142 }
143 else {
143 else {
144 break;
144 break;
145 }
145 }
146 }
146 }
147 var _parent = $(parent).get(0);
147 var _parent = $(parent).get(0);
148 $(_parent).after(form);
148 $(_parent).after(form);
149 $('.comment-form-inline').prev('.inline-comments').addClass('hide-comment-button');
149 $('.comment-form-inline').prev('.inline-comments').addClass('hide-comment-button');
150 var f = $(form).get(0);
150 var f = $(form).get(0);
151
151
152 var _form = $(f).find('.inline-form').get(0);
152 var _form = $(f).find('.inline-form').get(0);
153
153
154 var pullRequestId = templateContext.pull_request_data.pull_request_id;
154 var pullRequestId = templateContext.pull_request_data.pull_request_id;
155 var commitId = templateContext.commit_data.commit_id;
155 var commitId = templateContext.commit_data.commit_id;
156
156
157 var commentForm = new CommentForm(_form, commitId, pullRequestId, lineno, false);
157 var commentForm = new CommentForm(_form, commitId, pullRequestId, lineno, false);
158 var cm = commentForm.getCmInstance();
158 var cm = commentForm.getCmInstance();
159
159
160 // set a CUSTOM submit handler for inline comments.
160 // set a CUSTOM submit handler for inline comments.
161 commentForm.setHandleFormSubmit(function(o) {
161 commentForm.setHandleFormSubmit(function(o) {
162 var text = commentForm.cm.getValue();
162 var text = commentForm.cm.getValue();
163
163
164 if (text === "") {
164 if (text === "") {
165 return;
165 return;
166 }
166 }
167
167
168 if (lineno === undefined) {
168 if (lineno === undefined) {
169 alert('missing line !');
169 alert('missing line !');
170 return;
170 return;
171 }
171 }
172 if (f_path === undefined) {
172 if (f_path === undefined) {
173 alert('missing file path !');
173 alert('missing file path !');
174 return;
174 return;
175 }
175 }
176
176
177 var excludeCancelBtn = false;
177 var excludeCancelBtn = false;
178 var submitEvent = true;
178 var submitEvent = true;
179 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
179 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
180 commentForm.cm.setOption("readOnly", true);
180 commentForm.cm.setOption("readOnly", true);
181 var postData = {
181 var postData = {
182 'text': text,
182 'text': text,
183 'f_path': f_path,
183 'f_path': f_path,
184 'line': lineno,
184 'line': lineno,
185 'csrf_token': CSRF_TOKEN
185 'csrf_token': CSRF_TOKEN
186 };
186 };
187 var submitSuccessCallback = function(o) {
187 var submitSuccessCallback = function(o) {
188 $(tr).removeClass('form-open');
188 $(tr).removeClass('form-open');
189 removeInlineForm(f);
189 removeInlineForm(f);
190 renderInlineComment(o);
190 renderInlineComment(o);
191 $('.inline-comments').removeClass('hide-comment-button');
191 $('.inline-comments').removeClass('hide-comment-button');
192
192
193 // re trigger the linkification of next/prev navigation
193 // re trigger the linkification of next/prev navigation
194 linkifyComments($('.inline-comment-injected'));
194 linkifyComments($('.inline-comment-injected'));
195 timeagoActivate();
195 timeagoActivate();
196 bindDeleteCommentButtons();
196 bindDeleteCommentButtons();
197 commentForm.setActionButtonsDisabled(false);
197 commentForm.setActionButtonsDisabled(false);
198
198
199 };
199 };
200 var submitFailCallback = function(){
200 var submitFailCallback = function(){
201 commentForm.resetCommentFormState(text)
201 commentForm.resetCommentFormState(text)
202 };
202 };
203 commentForm.submitAjaxPOST(
203 commentForm.submitAjaxPOST(
204 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
204 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
205 });
205 });
206
206
207 setTimeout(function() {
207 setTimeout(function() {
208 // callbacks
208 // callbacks
209 if (cm !== undefined) {
209 if (cm !== undefined) {
210 cm.focus();
210 cm.focus();
211 }
211 }
212 }, 10);
212 }, 10);
213
213
214 $.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({
214 $.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({
215 form:_form,
215 form:_form,
216 parent:_parent,
216 parent:_parent,
217 lineno: lineno,
217 lineno: lineno,
218 f_path: f_path}
218 f_path: f_path}
219 );
219 );
220 };
220 };
221
221
222 var deleteComment = function(comment_id) {
222 var deleteComment = function(comment_id) {
223 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id);
223 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id);
224 var postData = {
224 var postData = {
225 '_method': 'delete',
225 '_method': 'delete',
226 'csrf_token': CSRF_TOKEN
226 'csrf_token': CSRF_TOKEN
227 };
227 };
228
228
229 var success = function(o) {
229 var success = function(o) {
230 window.location.reload();
230 window.location.reload();
231 };
231 };
232 ajaxPOST(url, postData, success);
232 ajaxPOST(url, postData, success);
233 };
233 };
234
234
235 var createInlineAddButton = function(tr){
235 var createInlineAddButton = function(tr){
236 var label = _gettext('Add another comment');
236 var label = _gettext('Add another comment');
237 var html_el = document.createElement('div');
237 var html_el = document.createElement('div');
238 $(html_el).addClass('add-comment');
238 $(html_el).addClass('add-comment');
239 html_el.innerHTML = '<span class="btn btn-secondary">{0}</span>'.format(label);
239 html_el.innerHTML = '<span class="btn btn-secondary">{0}</span>'.format(label);
240 var add = new $(html_el);
240 var add = new $(html_el);
241 add.on('click', function(e) {
241 add.on('click', function(e) {
242 injectInlineForm(tr);
242 injectInlineForm(tr);
243 });
243 });
244 return add;
244 return add;
245 };
245 };
246
246
247 var placeAddButton = function(target_tr){
247 var placeAddButton = function(target_tr){
248 if(!target_tr){
248 if(!target_tr){
249 return;
249 return;
250 }
250 }
251 var last_node = target_tr;
251 var last_node = target_tr;
252 // scan
252 // scan
253 while (1){
253 while (1){
254 var n = last_node.nextElementSibling;
254 var n = last_node.nextElementSibling;
255 // next element are comments !
255 // next element are comments !
256 if($(n).hasClass('inline-comments')){
256 if($(n).hasClass('inline-comments')){
257 last_node = n;
257 last_node = n;
258 // also remove the comment button from previous
258 // also remove the comment button from previous
259 var comment_add_buttons = $(last_node).find('.add-comment');
259 var comment_add_buttons = $(last_node).find('.add-comment');
260 for(var i=0; i<comment_add_buttons.length; i++){
260 for(var i=0; i<comment_add_buttons.length; i++){
261 var b = comment_add_buttons[i];
261 var b = comment_add_buttons[i];
262 b.parentNode.removeChild(b);
262 b.parentNode.removeChild(b);
263 }
263 }
264 }
264 }
265 else{
265 else{
266 break;
266 break;
267 }
267 }
268 }
268 }
269 var add = createInlineAddButton(target_tr);
269 var add = createInlineAddButton(target_tr);
270 // get the comment div
270 // get the comment div
271 var comment_block = $(last_node).find('.comment')[0];
271 var comment_block = $(last_node).find('.comment')[0];
272 // attach add button
272 // attach add button
273 $(add).insertAfter(comment_block);
273 $(add).insertAfter(comment_block);
274 };
274 };
275
275
276 /**
276 /**
277 * Places the inline comment into the changeset block in proper line position
277 * Places the inline comment into the changeset block in proper line position
278 */
278 */
279 var placeInline = function(target_container, lineno, html, show_add_button) {
279 var placeInline = function(target_container, lineno, html, show_add_button) {
280 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
280 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
281
281
282 var lineid = "{0}_{1}".format(target_container, lineno);
282 var lineid = "{0}_{1}".format(target_container, lineno);
283 var target_line = $('#' + lineid).get(0);
283 var target_line = $('#' + lineid).get(0);
284 var comment = new $(tableTr('inline-comments', html));
284 var comment = new $(tableTr('inline-comments', html));
285 // check if there are comments already !
285 // check if there are comments already !
286 if (target_line) {
286 if (target_line) {
287 var parent_node = target_line.parentNode;
287 var parent_node = target_line.parentNode;
288 var root_parent = parent_node;
288 var root_parent = parent_node;
289
289
290 while (1) {
290 while (1) {
291 var n = parent_node.nextElementSibling;
291 var n = parent_node.nextElementSibling;
292 // next element are comments !
292 // next element are comments !
293 if ($(n).hasClass('inline-comments')) {
293 if ($(n).hasClass('inline-comments')) {
294 parent_node = n;
294 parent_node = n;
295 }
295 }
296 else {
296 else {
297 break;
297 break;
298 }
298 }
299 }
299 }
300 // put in the comment at the bottom
300 // put in the comment at the bottom
301 $(comment).insertAfter(parent_node);
301 $(comment).insertAfter(parent_node);
302 $(comment).find('.comment-inline').addClass('inline-comment-injected');
302 $(comment).find('.comment-inline').addClass('inline-comment-injected');
303 // scan nodes, and attach add button to last one
303 // scan nodes, and attach add button to last one
304 if (show_add_button) {
304 if (show_add_button) {
305 placeAddButton(root_parent);
305 placeAddButton(root_parent);
306 }
306 }
307 addCommentToggle(target_line);
307 addCommentToggle(target_line);
308 }
308 }
309
309
310 return target_line;
310 return target_line;
311 };
311 };
312
312
313 var addCommentToggle = function(target_line) {
313 var addCommentToggle = function(target_line) {
314 // exposes comment toggle button
314 // exposes comment toggle button
315 $(target_line).siblings('.comment-toggle').addClass('active');
315 $(target_line).siblings('.comment-toggle').addClass('active');
316 return;
316 return;
317 };
317 };
318
318
319 var bindToggleButtons = function() {
319 var bindToggleButtons = function() {
320 $('.comment-toggle').on('click', function() {
320 $('.comment-toggle').on('click', function() {
321 $(this).parent().nextUntil('tr.line').toggle('inline-comments');
321 $(this).parent().nextUntil('tr.line').toggle('inline-comments');
322 });
322 });
323 };
323 };
324
324
325 var linkifyComments = function(comments) {
325 var linkifyComments = function(comments) {
326 /* TODO: dan: remove this - it should no longer needed */
326 /* TODO: dan: remove this - it should no longer needed */
327 for (var i = 0; i < comments.length; i++) {
327 for (var i = 0; i < comments.length; i++) {
328 var comment_id = $(comments[i]).data('comment-id');
328 var comment_id = $(comments[i]).data('comment-id');
329 var prev_comment_id = $(comments[i - 1]).data('comment-id');
329 var prev_comment_id = $(comments[i - 1]).data('comment-id');
330 var next_comment_id = $(comments[i + 1]).data('comment-id');
330 var next_comment_id = $(comments[i + 1]).data('comment-id');
331
331
332 // place next/prev links
332 // place next/prev links
333 if (prev_comment_id) {
333 if (prev_comment_id) {
334 $('#prev_c_' + comment_id).show();
334 $('#prev_c_' + comment_id).show();
335 $('#prev_c_' + comment_id + " a.arrow_comment_link").attr(
335 $('#prev_c_' + comment_id + " a.arrow_comment_link").attr(
336 'href', '#comment-' + prev_comment_id).removeClass('disabled');
336 'href', '#comment-' + prev_comment_id).removeClass('disabled');
337 }
337 }
338 if (next_comment_id) {
338 if (next_comment_id) {
339 $('#next_c_' + comment_id).show();
339 $('#next_c_' + comment_id).show();
340 $('#next_c_' + comment_id + " a.arrow_comment_link").attr(
340 $('#next_c_' + comment_id + " a.arrow_comment_link").attr(
341 'href', '#comment-' + next_comment_id).removeClass('disabled');
341 'href', '#comment-' + next_comment_id).removeClass('disabled');
342 }
342 }
343 // place a first link to the total counter
343 // place a first link to the total counter
344 if (i === 0) {
344 if (i === 0) {
345 $('#inline-comments-counter').attr('href', '#comment-' + comment_id);
345 $('#inline-comments-counter').attr('href', '#comment-' + comment_id);
346 }
346 }
347 }
347 }
348
348
349 };
349 };
350
350
351 /**
351 /**
352 * Iterates over all the inlines, and places them inside proper blocks of data
352 * Iterates over all the inlines, and places them inside proper blocks of data
353 */
353 */
354 var renderInlineComments = function(file_comments, show_add_button) {
354 var renderInlineComments = function(file_comments, show_add_button) {
355 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
355 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
356
356
357 for (var i = 0; i < file_comments.length; i++) {
357 for (var i = 0; i < file_comments.length; i++) {
358 var box = file_comments[i];
358 var box = file_comments[i];
359
359
360 var target_id = $(box).attr('target_id');
360 var target_id = $(box).attr('target_id');
361
361
362 // actually comments with line numbers
362 // actually comments with line numbers
363 var comments = box.children;
363 var comments = box.children;
364
364
365 for (var j = 0; j < comments.length; j++) {
365 for (var j = 0; j < comments.length; j++) {
366 var data = {
366 var data = {
367 'rendered_text': comments[j].outerHTML,
367 'rendered_text': comments[j].outerHTML,
368 'line_no': $(comments[j]).attr('line'),
368 'line_no': $(comments[j]).attr('line'),
369 'target_id': target_id
369 'target_id': target_id
370 };
370 };
371 renderInlineComment(data, show_add_button);
371 renderInlineComment(data, show_add_button);
372 }
372 }
373 }
373 }
374
374
375 // since order of injection is random, we're now re-iterating
375 // since order of injection is random, we're now re-iterating
376 // from correct order and filling in links
376 // from correct order and filling in links
377 linkifyComments($('.inline-comment-injected'));
377 linkifyComments($('.inline-comment-injected'));
378 bindDeleteCommentButtons();
378 bindDeleteCommentButtons();
379 firefoxAnchorFix();
379 firefoxAnchorFix();
380 };
380 };
381
381
382
382
383 /* Comment form for main and inline comments */
383 /* Comment form for main and inline comments */
384 var CommentForm = (function() {
384 var CommentForm = (function() {
385 "use strict";
385 "use strict";
386
386
387 function CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions) {
387 function CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions) {
388
388
389 this.withLineNo = function(selector) {
389 this.withLineNo = function(selector) {
390 var lineNo = this.lineNo;
390 var lineNo = this.lineNo;
391 if (lineNo === undefined) {
391 if (lineNo === undefined) {
392 return selector
392 return selector
393 } else {
393 } else {
394 return selector + '_' + lineNo;
394 return selector + '_' + lineNo;
395 }
395 }
396 };
396 };
397
397
398 this.commitId = commitId;
398 this.commitId = commitId;
399 this.pullRequestId = pullRequestId;
399 this.pullRequestId = pullRequestId;
400 this.lineNo = lineNo;
400 this.lineNo = lineNo;
401 this.initAutocompleteActions = initAutocompleteActions;
401 this.initAutocompleteActions = initAutocompleteActions;
402
402
403 this.previewButton = this.withLineNo('#preview-btn');
403 this.previewButton = this.withLineNo('#preview-btn');
404 this.previewContainer = this.withLineNo('#preview-container');
404 this.previewContainer = this.withLineNo('#preview-container');
405
405
406 this.previewBoxSelector = this.withLineNo('#preview-box');
406 this.previewBoxSelector = this.withLineNo('#preview-box');
407
407
408 this.editButton = this.withLineNo('#edit-btn');
408 this.editButton = this.withLineNo('#edit-btn');
409 this.editContainer = this.withLineNo('#edit-container');
409 this.editContainer = this.withLineNo('#edit-container');
410
410
411 this.cancelButton = this.withLineNo('#cancel-btn');
411 this.cancelButton = this.withLineNo('#cancel-btn');
412
412
413 this.statusChange = '#change_status';
413 this.statusChange = '#change_status';
414 this.cmBox = this.withLineNo('#text');
414 this.cmBox = this.withLineNo('#text');
415 this.cm = initCommentBoxCodeMirror(this.cmBox, this.initAutocompleteActions);
415 this.cm = initCommentBoxCodeMirror(this.cmBox, this.initAutocompleteActions);
416
416
417 this.submitForm = formElement;
417 this.submitForm = formElement;
418 this.submitButton = $(this.submitForm).find('input[type="submit"]');
418 this.submitButton = $(this.submitForm).find('input[type="submit"]');
419 this.submitButtonText = this.submitButton.val();
419 this.submitButtonText = this.submitButton.val();
420
420
421 this.previewUrl = pyroutes.url('changeset_comment_preview',
421 this.previewUrl = pyroutes.url('changeset_comment_preview',
422 {'repo_name': templateContext.repo_name});
422 {'repo_name': templateContext.repo_name});
423
423
424 // based on commitId, or pullReuqestId decide where do we submit
424 // based on commitId, or pullReuqestId decide where do we submit
425 // out data
425 // out data
426 if (this.commitId){
426 if (this.commitId){
427 this.submitUrl = pyroutes.url('changeset_comment',
427 this.submitUrl = pyroutes.url('changeset_comment',
428 {'repo_name': templateContext.repo_name,
428 {'repo_name': templateContext.repo_name,
429 'revision': this.commitId});
429 'revision': this.commitId});
430
430
431 } else if (this.pullRequestId) {
431 } else if (this.pullRequestId) {
432 this.submitUrl = pyroutes.url('pullrequest_comment',
432 this.submitUrl = pyroutes.url('pullrequest_comment',
433 {'repo_name': templateContext.repo_name,
433 {'repo_name': templateContext.repo_name,
434 'pull_request_id': this.pullRequestId});
434 'pull_request_id': this.pullRequestId});
435
435
436 } else {
436 } else {
437 throw new Error(
437 throw new Error(
438 'CommentForm requires pullRequestId, or commitId to be specified.')
438 'CommentForm requires pullRequestId, or commitId to be specified.')
439 }
439 }
440
440
441 this.getCmInstance = function(){
441 this.getCmInstance = function(){
442 return this.cm
442 return this.cm
443 };
443 };
444
444
445 var self = this;
445 var self = this;
446
446
447 this.getCommentStatus = function() {
447 this.getCommentStatus = function() {
448 return $(this.submitForm).find(this.statusChange).val();
448 return $(this.submitForm).find(this.statusChange).val();
449 };
449 };
450
450
451 this.isAllowedToSubmit = function() {
451 this.isAllowedToSubmit = function() {
452 return !$(this.submitButton).prop('disabled');
452 return !$(this.submitButton).prop('disabled');
453 };
453 };
454
454
455 this.initStatusChangeSelector = function(){
455 this.initStatusChangeSelector = function(){
456 var formatChangeStatus = function(state, escapeMarkup) {
456 var formatChangeStatus = function(state, escapeMarkup) {
457 var originalOption = state.element;
457 var originalOption = state.element;
458 return '<div class="flag_status ' + $(originalOption).data('status') + ' pull-left"></div>' +
458 return '<div class="flag_status ' + $(originalOption).data('status') + ' pull-left"></div>' +
459 '<span>' + escapeMarkup(state.text) + '</span>';
459 '<span>' + escapeMarkup(state.text) + '</span>';
460 };
460 };
461 var formatResult = function(result, container, query, escapeMarkup) {
461 var formatResult = function(result, container, query, escapeMarkup) {
462 return formatChangeStatus(result, escapeMarkup);
462 return formatChangeStatus(result, escapeMarkup);
463 };
463 };
464
464
465 var formatSelection = function(data, container, escapeMarkup) {
465 var formatSelection = function(data, container, escapeMarkup) {
466 return formatChangeStatus(data, escapeMarkup);
466 return formatChangeStatus(data, escapeMarkup);
467 };
467 };
468
468
469 $(this.submitForm).find(this.statusChange).select2({
469 $(this.submitForm).find(this.statusChange).select2({
470 placeholder: _gettext('Status Review'),
470 placeholder: _gettext('Status Review'),
471 formatResult: formatResult,
471 formatResult: formatResult,
472 formatSelection: formatSelection,
472 formatSelection: formatSelection,
473 containerCssClass: "drop-menu status_box_menu",
473 containerCssClass: "drop-menu status_box_menu",
474 dropdownCssClass: "drop-menu-dropdown",
474 dropdownCssClass: "drop-menu-dropdown",
475 dropdownAutoWidth: true,
475 dropdownAutoWidth: true,
476 minimumResultsForSearch: -1
476 minimumResultsForSearch: -1
477 });
477 });
478 $(this.submitForm).find(this.statusChange).on('change', function() {
478 $(this.submitForm).find(this.statusChange).on('change', function() {
479 var status = self.getCommentStatus();
479 var status = self.getCommentStatus();
480 if (status && !self.lineNo) {
480 if (status && !self.lineNo) {
481 $(self.submitButton).prop('disabled', false);
481 $(self.submitButton).prop('disabled', false);
482 }
482 }
483 //todo, fix this name
483 //todo, fix this name
484 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
484 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
485 self.cm.setOption('placeholder', placeholderText);
485 self.cm.setOption('placeholder', placeholderText);
486 })
486 })
487 };
487 };
488
488
489 // reset the comment form into it's original state
489 // reset the comment form into it's original state
490 this.resetCommentFormState = function(content) {
490 this.resetCommentFormState = function(content) {
491 content = content || '';
491 content = content || '';
492
492
493 $(this.editContainer).show();
493 $(this.editContainer).show();
494 $(this.editButton).hide();
494 $(this.editButton).hide();
495
495
496 $(this.previewContainer).hide();
496 $(this.previewContainer).hide();
497 $(this.previewButton).show();
497 $(this.previewButton).show();
498
498
499 this.setActionButtonsDisabled(true);
499 this.setActionButtonsDisabled(true);
500 self.cm.setValue(content);
500 self.cm.setValue(content);
501 self.cm.setOption("readOnly", false);
501 self.cm.setOption("readOnly", false);
502 };
502 };
503
503
504 this.submitAjaxPOST = function(url, postData, successHandler, failHandler) {
504 this.submitAjaxPOST = function(url, postData, successHandler, failHandler) {
505 failHandler = failHandler || function() {};
505 failHandler = failHandler || function() {};
506 var postData = toQueryString(postData);
506 var postData = toQueryString(postData);
507 var request = $.ajax({
507 var request = $.ajax({
508 url: url,
508 url: url,
509 type: 'POST',
509 type: 'POST',
510 data: postData,
510 data: postData,
511 headers: {'X-PARTIAL-XHR': true}
511 headers: {'X-PARTIAL-XHR': true}
512 })
512 })
513 .done(function(data) {
513 .done(function(data) {
514 successHandler(data);
514 successHandler(data);
515 })
515 })
516 .fail(function(data, textStatus, errorThrown){
516 .fail(function(data, textStatus, errorThrown){
517 alert(
517 alert(
518 "Error while submitting comment.\n" +
518 "Error while submitting comment.\n" +
519 "Error code {0} ({1}).".format(data.status, data.statusText));
519 "Error code {0} ({1}).".format(data.status, data.statusText));
520 failHandler()
520 failHandler()
521 });
521 });
522 return request;
522 return request;
523 };
523 };
524
524
525 // overwrite a submitHandler, we need to do it for inline comments
525 // overwrite a submitHandler, we need to do it for inline comments
526 this.setHandleFormSubmit = function(callback) {
526 this.setHandleFormSubmit = function(callback) {
527 this.handleFormSubmit = callback;
527 this.handleFormSubmit = callback;
528 };
528 };
529
529
530 // default handler for for submit for main comments
530 // default handler for for submit for main comments
531 this.handleFormSubmit = function() {
531 this.handleFormSubmit = function() {
532 var text = self.cm.getValue();
532 var text = self.cm.getValue();
533 var status = self.getCommentStatus();
533 var status = self.getCommentStatus();
534
534
535 if (text === "" && !status) {
535 if (text === "" && !status) {
536 return;
536 return;
537 }
537 }
538
538
539 var excludeCancelBtn = false;
539 var excludeCancelBtn = false;
540 var submitEvent = true;
540 var submitEvent = true;
541 self.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
541 self.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
542 self.cm.setOption("readOnly", true);
542 self.cm.setOption("readOnly", true);
543 var postData = {
543 var postData = {
544 'text': text,
544 'text': text,
545 'changeset_status': status,
545 'changeset_status': status,
546 'csrf_token': CSRF_TOKEN
546 'csrf_token': CSRF_TOKEN
547 };
547 };
548
548
549 var submitSuccessCallback = function(o) {
549 var submitSuccessCallback = function(o) {
550 if (status) {
550 if (status) {
551 location.reload(true);
551 location.reload(true);
552 } else {
552 } else {
553 $('#injected_page_comments').append(o.rendered_text);
553 $('#injected_page_comments').append(o.rendered_text);
554 self.resetCommentFormState();
554 self.resetCommentFormState();
555 bindDeleteCommentButtons();
555 bindDeleteCommentButtons();
556 timeagoActivate();
556 timeagoActivate();
557 }
557 }
558 };
558 };
559 var submitFailCallback = function(){
559 var submitFailCallback = function(){
560 self.resetCommentFormState(text)
560 self.resetCommentFormState(text)
561 };
561 };
562 self.submitAjaxPOST(
562 self.submitAjaxPOST(
563 self.submitUrl, postData, submitSuccessCallback, submitFailCallback);
563 self.submitUrl, postData, submitSuccessCallback, submitFailCallback);
564 };
564 };
565
565
566 this.previewSuccessCallback = function(o) {
566 this.previewSuccessCallback = function(o) {
567 $(self.previewBoxSelector).html(o);
567 $(self.previewBoxSelector).html(o);
568 $(self.previewBoxSelector).removeClass('unloaded');
568 $(self.previewBoxSelector).removeClass('unloaded');
569
569
570 // swap buttons
570 // swap buttons
571 $(self.previewButton).hide();
571 $(self.previewButton).hide();
572 $(self.editButton).show();
572 $(self.editButton).show();
573
573
574 // unlock buttons
574 // unlock buttons
575 self.setActionButtonsDisabled(false);
575 self.setActionButtonsDisabled(false);
576 };
576 };
577
577
578 this.setActionButtonsDisabled = function(state, excludeCancelBtn, submitEvent) {
578 this.setActionButtonsDisabled = function(state, excludeCancelBtn, submitEvent) {
579 excludeCancelBtn = excludeCancelBtn || false;
579 excludeCancelBtn = excludeCancelBtn || false;
580 submitEvent = submitEvent || false;
580 submitEvent = submitEvent || false;
581
581
582 $(this.editButton).prop('disabled', state);
582 $(this.editButton).prop('disabled', state);
583 $(this.previewButton).prop('disabled', state);
583 $(this.previewButton).prop('disabled', state);
584
584
585 if (!excludeCancelBtn) {
585 if (!excludeCancelBtn) {
586 $(this.cancelButton).prop('disabled', state);
586 $(this.cancelButton).prop('disabled', state);
587 }
587 }
588
588
589 var submitState = state;
589 var submitState = state;
590 if (!submitEvent && this.getCommentStatus() && !this.lineNo) {
590 if (!submitEvent && this.getCommentStatus() && !this.lineNo) {
591 // if the value of commit review status is set, we allow
591 // if the value of commit review status is set, we allow
592 // submit button, but only on Main form, lineNo means inline
592 // submit button, but only on Main form, lineNo means inline
593 submitState = false
593 submitState = false
594 }
594 }
595 $(this.submitButton).prop('disabled', submitState);
595 $(this.submitButton).prop('disabled', submitState);
596 if (submitEvent) {
596 if (submitEvent) {
597 $(this.submitButton).val(_gettext('Submitting...'));
597 $(this.submitButton).val(_gettext('Submitting...'));
598 } else {
598 } else {
599 $(this.submitButton).val(this.submitButtonText);
599 $(this.submitButton).val(this.submitButtonText);
600 }
600 }
601
601
602 };
602 };
603
603
604 // lock preview/edit/submit buttons on load, but exclude cancel button
604 // lock preview/edit/submit buttons on load, but exclude cancel button
605 var excludeCancelBtn = true;
605 var excludeCancelBtn = true;
606 this.setActionButtonsDisabled(true, excludeCancelBtn);
606 this.setActionButtonsDisabled(true, excludeCancelBtn);
607
607
608 // anonymous users don't have access to initialized CM instance
608 // anonymous users don't have access to initialized CM instance
609 if (this.cm !== undefined){
609 if (this.cm !== undefined){
610 this.cm.on('change', function(cMirror) {
610 this.cm.on('change', function(cMirror) {
611 if (cMirror.getValue() === "") {
611 if (cMirror.getValue() === "") {
612 self.setActionButtonsDisabled(true, excludeCancelBtn)
612 self.setActionButtonsDisabled(true, excludeCancelBtn)
613 } else {
613 } else {
614 self.setActionButtonsDisabled(false, excludeCancelBtn)
614 self.setActionButtonsDisabled(false, excludeCancelBtn)
615 }
615 }
616 });
616 });
617 }
617 }
618
618
619 $(this.editButton).on('click', function(e) {
619 $(this.editButton).on('click', function(e) {
620 e.preventDefault();
620 e.preventDefault();
621
621
622 $(self.previewButton).show();
622 $(self.previewButton).show();
623 $(self.previewContainer).hide();
623 $(self.previewContainer).hide();
624 $(self.editButton).hide();
624 $(self.editButton).hide();
625 $(self.editContainer).show();
625 $(self.editContainer).show();
626
626
627 });
627 });
628
628
629 $(this.previewButton).on('click', function(e) {
629 $(this.previewButton).on('click', function(e) {
630 e.preventDefault();
630 e.preventDefault();
631 var text = self.cm.getValue();
631 var text = self.cm.getValue();
632
632
633 if (text === "") {
633 if (text === "") {
634 return;
634 return;
635 }
635 }
636
636
637 var postData = {
637 var postData = {
638 'text': text,
638 'text': text,
639 'renderer': DEFAULT_RENDERER,
639 'renderer': DEFAULT_RENDERER,
640 'csrf_token': CSRF_TOKEN
640 'csrf_token': CSRF_TOKEN
641 };
641 };
642
642
643 // lock ALL buttons on preview
643 // lock ALL buttons on preview
644 self.setActionButtonsDisabled(true);
644 self.setActionButtonsDisabled(true);
645
645
646 $(self.previewBoxSelector).addClass('unloaded');
646 $(self.previewBoxSelector).addClass('unloaded');
647 $(self.previewBoxSelector).html(_gettext('Loading ...'));
647 $(self.previewBoxSelector).html(_gettext('Loading ...'));
648 $(self.editContainer).hide();
648 $(self.editContainer).hide();
649 $(self.previewContainer).show();
649 $(self.previewContainer).show();
650
650
651 // by default we reset state of comment preserving the text
651 // by default we reset state of comment preserving the text
652 var previewFailCallback = function(){
652 var previewFailCallback = function(){
653 self.resetCommentFormState(text)
653 self.resetCommentFormState(text)
654 };
654 };
655 self.submitAjaxPOST(
655 self.submitAjaxPOST(
656 self.previewUrl, postData, self.previewSuccessCallback, previewFailCallback);
656 self.previewUrl, postData, self.previewSuccessCallback, previewFailCallback);
657
657
658 });
658 });
659
659
660 $(this.submitForm).submit(function(e) {
660 $(this.submitForm).submit(function(e) {
661 e.preventDefault();
661 e.preventDefault();
662 var allowedToSubmit = self.isAllowedToSubmit();
662 var allowedToSubmit = self.isAllowedToSubmit();
663 if (!allowedToSubmit){
663 if (!allowedToSubmit){
664 return false;
664 return false;
665 }
665 }
666 self.handleFormSubmit();
666 self.handleFormSubmit();
667 });
667 });
668
668
669 }
669 }
670
670
671 return CommentForm;
671 return CommentForm;
672 })();
672 })();
673
674 var CommentsController = function() { /* comments controller */
675 var self = this;
676
677 this.cancelComment = function(node) {
678 var $node = $(node);
679 var $td = $node.closest('td');
680 $node.closest('.comment-inline-form').removeClass('comment-inline-form-open');
681 return false;
682 }
683 this.getLineNumber = function(node) {
684 var $node = $(node);
685 return $node.closest('td').attr('data-line-number');
686 }
687 this.scrollToComment = function(node, offset) {
688 if (!node) {
689 node = $('.comment-selected');
690 if (!node.length) {
691 node = $('comment-current')
692 }
693 }
694 $comment = $(node).closest('.comment-current');
695 $comments = $('.comment-current');
696
697 $('.comment-selected').removeClass('comment-selected');
698
699 var nextIdx = $('.comment-current').index($comment) + offset;
700 if (nextIdx >= $comments.length) {
701 nextIdx = 0;
702 }
703 var $next = $('.comment-current').eq(nextIdx);
704 var $cb = $next.closest('.cb');
705 $cb.removeClass('cb-collapsed')
706
707 var $filediffCollapseState = $cb.closest('.filediff').prev();
708 $filediffCollapseState.prop('checked', false);
709 $next.addClass('comment-selected');
710 scrollToElement($next);
711 return false;
712 }
713 this.nextComment = function(node) {
714 return self.scrollToComment(node, 1);
715 }
716 this.prevComment = function(node) {
717 return self.scrollToComment(node, -1);
718 }
719 this.deleteComment = function(node) {
720 if (!confirm(_gettext('Delete this comment?'))) {
721 return false;
722 }
723 var $node = $(node);
724 var $td = $node.closest('td');
725 var $comment = $node.closest('.comment');
726 var comment_id = $comment.attr('data-comment-id');
727 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id);
728 var postData = {
729 '_method': 'delete',
730 'csrf_token': CSRF_TOKEN
731 };
732
733 $comment.addClass('comment-deleting');
734 $comment.hide('fast');
735
736 var success = function(response) {
737 $comment.remove();
738 return false;
739 };
740 var failure = function(data, textStatus, xhr) {
741 alert("error processing request: " + textStatus);
742 $comment.show('fast');
743 $comment.removeClass('comment-deleting');
744 return false;
745 };
746 ajaxPOST(url, postData, success, failure);
747 }
748 this.toggleComments = function(node, show) {
749 var $filediff = $(node).closest('.filediff');
750 if (show === true) {
751 $filediff.removeClass('hide-comments');
752 } else if (show === false) {
753 $filediff.find('.hide-line-comments').removeClass('hide-line-comments');
754 $filediff.addClass('hide-comments');
755 } else {
756 $filediff.find('.hide-line-comments').removeClass('hide-line-comments');
757 $filediff.toggleClass('hide-comments');
758 }
759 return false;
760 }
761 this.toggleLineComments = function(node) {
762 self.toggleComments(node, true);
763 var $node = $(node);
764 $node.closest('tr').toggleClass('hide-line-comments');
765 }
766 this.createComment = function(node) {
767 var $node = $(node);
768 var $td = $node.closest('td');
769 var $form = $td.find('.comment-inline-form');
770
771 if (!$form.length) {
772 var tmpl = $('#cb-comment-inline-form-template').html();
773 var $filediff = $node.closest('.filediff');
774 $filediff.removeClass('hide-comments');
775 var f_path = $filediff.attr('data-f-path');
776 var lineno = self.getLineNumber(node);
777 tmpl = tmpl.format(f_path, lineno);
778 $form = $(tmpl);
779
780 var $comments = $td.find('.inline-comments');
781 if (!$comments.length) {
782 $comments = $(
783 $('#cb-comments-inline-container-template').html());
784 $td.append($comments);
785 }
786
787 $td.find('.cb-comment-add-button').before($form);
788
789 var pullRequestId = templateContext.pull_request_data.pull_request_id;
790 var commitId = templateContext.commit_data.commit_id;
791 var _form = $form[0];
792 var commentForm = new CommentForm(_form, commitId, pullRequestId, lineno, false);
793 var cm = commentForm.getCmInstance();
794
795 // set a CUSTOM submit handler for inline comments.
796 commentForm.setHandleFormSubmit(function(o) {
797 var text = commentForm.cm.getValue();
798
799 if (text === "") {
800 return;
801 }
802
803 if (lineno === undefined) {
804 alert('missing line !');
805 return;
806 }
807 if (f_path === undefined) {
808 alert('missing file path !');
809 return;
810 }
811
812 var excludeCancelBtn = false;
813 var submitEvent = true;
814 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
815 commentForm.cm.setOption("readOnly", true);
816 var postData = {
817 'text': text,
818 'f_path': f_path,
819 'line': lineno,
820 'csrf_token': CSRF_TOKEN
821 };
822 var submitSuccessCallback = function(json_data) {
823 $form.remove();
824 console.log(json_data)
825 try {
826 var html = json_data.rendered_text;
827 var lineno = json_data.line_no;
828 var target_id = json_data.target_id;
829
830 $comments.find('.cb-comment-add-button').before(html);
831 console.log(lineno, target_id, $comments);
832
833 } catch (e) {
834 console.error(e);
835 }
836
837
838 // re trigger the linkification of next/prev navigation
839 linkifyComments($('.inline-comment-injected'));
840 timeagoActivate();
841 bindDeleteCommentButtons();
842 commentForm.setActionButtonsDisabled(false);
843
844 };
845 var submitFailCallback = function(){
846 commentForm.resetCommentFormState(text)
847 };
848 commentForm.submitAjaxPOST(
849 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
850 });
851
852 setTimeout(function() {
853 // callbacks
854 if (cm !== undefined) {
855 cm.focus();
856 }
857 }, 10);
858
859 $.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({
860 form: _form,
861 parent: $td[0],
862 lineno: lineno,
863 f_path: f_path}
864 );
865 }
866
867 $form.addClass('comment-inline-form-open');
868 }
869
870 this.renderInlineComments = function(file_comments) {
871 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
872
873 for (var i = 0; i < file_comments.length; i++) {
874 var box = file_comments[i];
875
876 var target_id = $(box).attr('target_id');
877
878 // actually comments with line numbers
879 var comments = box.children;
880
881 for (var j = 0; j < comments.length; j++) {
882 var data = {
883 'rendered_text': comments[j].outerHTML,
884 'line_no': $(comments[j]).attr('line'),
885 'target_id': target_id
886 };
887 }
888 }
889
890 // since order of injection is random, we're now re-iterating
891 // from correct order and filling in links
892 linkifyComments($('.inline-comment-injected'));
893 bindDeleteCommentButtons();
894 firefoxAnchorFix();
895 };
896
897 } No newline at end of file
@@ -1,387 +1,183 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html>
2 <!DOCTYPE html>
3
3
4 <%
4 <%
5 c.template_context['repo_name'] = getattr(c, 'repo_name', '')
5 c.template_context['repo_name'] = getattr(c, 'repo_name', '')
6
6
7 if hasattr(c, 'rhodecode_db_repo'):
7 if hasattr(c, 'rhodecode_db_repo'):
8 c.template_context['repo_type'] = c.rhodecode_db_repo.repo_type
8 c.template_context['repo_type'] = c.rhodecode_db_repo.repo_type
9 c.template_context['repo_landing_commit'] = c.rhodecode_db_repo.landing_rev[1]
9 c.template_context['repo_landing_commit'] = c.rhodecode_db_repo.landing_rev[1]
10
10
11 if getattr(c, 'rhodecode_user', None) and c.rhodecode_user.user_id:
11 if getattr(c, 'rhodecode_user', None) and c.rhodecode_user.user_id:
12 c.template_context['rhodecode_user']['username'] = c.rhodecode_user.username
12 c.template_context['rhodecode_user']['username'] = c.rhodecode_user.username
13 c.template_context['rhodecode_user']['email'] = c.rhodecode_user.email
13 c.template_context['rhodecode_user']['email'] = c.rhodecode_user.email
14 c.template_context['rhodecode_user']['notification_status'] = c.rhodecode_user.get_instance().user_data.get('notification_status', True)
14 c.template_context['rhodecode_user']['notification_status'] = c.rhodecode_user.get_instance().user_data.get('notification_status', True)
15 c.template_context['rhodecode_user']['first_name'] = c.rhodecode_user.name
15 c.template_context['rhodecode_user']['first_name'] = c.rhodecode_user.name
16 c.template_context['rhodecode_user']['last_name'] = c.rhodecode_user.lastname
16 c.template_context['rhodecode_user']['last_name'] = c.rhodecode_user.lastname
17
17
18 c.template_context['visual']['default_renderer'] = h.get_visual_attr(c, 'default_renderer')
18 c.template_context['visual']['default_renderer'] = h.get_visual_attr(c, 'default_renderer')
19 %>
19 %>
20 <html xmlns="http://www.w3.org/1999/xhtml">
20 <html xmlns="http://www.w3.org/1999/xhtml">
21 <head>
21 <head>
22 <script src="${h.asset('js/vendors/webcomponentsjs/webcomponents-lite.min.js', ver=c.rhodecode_version_hash)}"></script>
22 <script src="${h.asset('js/vendors/webcomponentsjs/webcomponents-lite.min.js', ver=c.rhodecode_version_hash)}"></script>
23 <link rel="import" href="${h.asset('js/rhodecode-components.html', ver=c.rhodecode_version_hash)}">
23 <link rel="import" href="${h.asset('js/rhodecode-components.html', ver=c.rhodecode_version_hash)}">
24 <title>${self.title()}</title>
24 <title>${self.title()}</title>
25 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
25 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
26 <%def name="robots()">
26 <%def name="robots()">
27 <meta name="robots" content="index, nofollow"/>
27 <meta name="robots" content="index, nofollow"/>
28 </%def>
28 </%def>
29 ${self.robots()}
29 ${self.robots()}
30 <link rel="icon" href="${h.asset('images/favicon.ico', ver=c.rhodecode_version_hash)}" sizes="16x16 32x32" type="image/png" />
30 <link rel="icon" href="${h.asset('images/favicon.ico', ver=c.rhodecode_version_hash)}" sizes="16x16 32x32" type="image/png" />
31
31
32 ## CSS definitions
32 ## CSS definitions
33 <%def name="css()">
33 <%def name="css()">
34 <link rel="stylesheet" type="text/css" href="${h.asset('css/style.css', ver=c.rhodecode_version_hash)}" media="screen"/>
34 <link rel="stylesheet" type="text/css" href="${h.asset('css/style.css', ver=c.rhodecode_version_hash)}" media="screen"/>
35 <!--[if lt IE 9]>
35 <!--[if lt IE 9]>
36 <link rel="stylesheet" type="text/css" href="${h.asset('css/ie.css', ver=c.rhodecode_version_hash)}" media="screen"/>
36 <link rel="stylesheet" type="text/css" href="${h.asset('css/ie.css', ver=c.rhodecode_version_hash)}" media="screen"/>
37 <![endif]-->
37 <![endif]-->
38 ## EXTRA FOR CSS
38 ## EXTRA FOR CSS
39 ${self.css_extra()}
39 ${self.css_extra()}
40 </%def>
40 </%def>
41 ## CSS EXTRA - optionally inject some extra CSS stuff needed for specific websites
41 ## CSS EXTRA - optionally inject some extra CSS stuff needed for specific websites
42 <%def name="css_extra()">
42 <%def name="css_extra()">
43 </%def>
43 </%def>
44
44
45 ${self.css()}
45 ${self.css()}
46
46
47 ## JAVASCRIPT
47 ## JAVASCRIPT
48 <%def name="js()">
48 <%def name="js()">
49 <script>
49 <script>
50 // setup Polymer options
50 // setup Polymer options
51 window.Polymer = {lazyRegister: true, dom: 'shadow'};
51 window.Polymer = {lazyRegister: true, dom: 'shadow'};
52
52
53 // Load webcomponentsjs polyfill if browser does not support native Web Components
53 // Load webcomponentsjs polyfill if browser does not support native Web Components
54 (function() {
54 (function() {
55 'use strict';
55 'use strict';
56 var onload = function() {
56 var onload = function() {
57 // For native Imports, manually fire WebComponentsReady so user code
57 // For native Imports, manually fire WebComponentsReady so user code
58 // can use the same code path for native and polyfill'd imports.
58 // can use the same code path for native and polyfill'd imports.
59 if (!window.HTMLImports) {
59 if (!window.HTMLImports) {
60 document.dispatchEvent(
60 document.dispatchEvent(
61 new CustomEvent('WebComponentsReady', {bubbles: true})
61 new CustomEvent('WebComponentsReady', {bubbles: true})
62 );
62 );
63 }
63 }
64 };
64 };
65 var webComponentsSupported = (
65 var webComponentsSupported = (
66 'registerElement' in document
66 'registerElement' in document
67 && 'import' in document.createElement('link')
67 && 'import' in document.createElement('link')
68 && 'content' in document.createElement('template')
68 && 'content' in document.createElement('template')
69 );
69 );
70 if (!webComponentsSupported) {
70 if (!webComponentsSupported) {
71 } else {
71 } else {
72 onload();
72 onload();
73 }
73 }
74 })();
74 })();
75 </script>
75 </script>
76
76
77 <script src="${h.asset('js/rhodecode/i18n/%s.js' % c.language, ver=c.rhodecode_version_hash)}"></script>
77 <script src="${h.asset('js/rhodecode/i18n/%s.js' % c.language, ver=c.rhodecode_version_hash)}"></script>
78 <script type="text/javascript">
78 <script type="text/javascript">
79 // register templateContext to pass template variables to JS
79 // register templateContext to pass template variables to JS
80 var templateContext = ${h.json.dumps(c.template_context)|n};
80 var templateContext = ${h.json.dumps(c.template_context)|n};
81
81
82 var REPO_NAME = "${getattr(c, 'repo_name', '')}";
82 var REPO_NAME = "${getattr(c, 'repo_name', '')}";
83 %if hasattr(c, 'rhodecode_db_repo'):
83 %if hasattr(c, 'rhodecode_db_repo'):
84 var REPO_LANDING_REV = '${c.rhodecode_db_repo.landing_rev[1]}';
84 var REPO_LANDING_REV = '${c.rhodecode_db_repo.landing_rev[1]}';
85 var REPO_TYPE = '${c.rhodecode_db_repo.repo_type}';
85 var REPO_TYPE = '${c.rhodecode_db_repo.repo_type}';
86 %else:
86 %else:
87 var REPO_LANDING_REV = '';
87 var REPO_LANDING_REV = '';
88 var REPO_TYPE = '';
88 var REPO_TYPE = '';
89 %endif
89 %endif
90 var APPLICATION_URL = "${h.url('home').rstrip('/')}";
90 var APPLICATION_URL = "${h.url('home').rstrip('/')}";
91 var ASSET_URL = "${h.asset('')}";
91 var ASSET_URL = "${h.asset('')}";
92 var DEFAULT_RENDERER = "${h.get_visual_attr(c, 'default_renderer')}";
92 var DEFAULT_RENDERER = "${h.get_visual_attr(c, 'default_renderer')}";
93 var CSRF_TOKEN = "${getattr(c, 'csrf_token', '')}";
93 var CSRF_TOKEN = "${getattr(c, 'csrf_token', '')}";
94 % if getattr(c, 'rhodecode_user', None):
94 % if getattr(c, 'rhodecode_user', None):
95 var USER = {name:'${c.rhodecode_user.username}'};
95 var USER = {name:'${c.rhodecode_user.username}'};
96 % else:
96 % else:
97 var USER = {name:null};
97 var USER = {name:null};
98 % endif
98 % endif
99
99
100 var APPENLIGHT = {
100 var APPENLIGHT = {
101 enabled: ${'true' if getattr(c, 'appenlight_enabled', False) else 'false'},
101 enabled: ${'true' if getattr(c, 'appenlight_enabled', False) else 'false'},
102 key: '${getattr(c, "appenlight_api_public_key", "")}',
102 key: '${getattr(c, "appenlight_api_public_key", "")}',
103 % if getattr(c, 'appenlight_server_url', None):
103 % if getattr(c, 'appenlight_server_url', None):
104 serverUrl: '${getattr(c, "appenlight_server_url", "")}',
104 serverUrl: '${getattr(c, "appenlight_server_url", "")}',
105 % endif
105 % endif
106 requestInfo: {
106 requestInfo: {
107 % if getattr(c, 'rhodecode_user', None):
107 % if getattr(c, 'rhodecode_user', None):
108 ip: '${c.rhodecode_user.ip_addr}',
108 ip: '${c.rhodecode_user.ip_addr}',
109 username: '${c.rhodecode_user.username}'
109 username: '${c.rhodecode_user.username}'
110 % endif
110 % endif
111 },
111 },
112 tags: {
112 tags: {
113 rhodecode_version: '${c.rhodecode_version}',
113 rhodecode_version: '${c.rhodecode_version}',
114 rhodecode_edition: '${c.rhodecode_edition}'
114 rhodecode_edition: '${c.rhodecode_edition}'
115 }
115 }
116 };
116 };
117
117
118
119 Rhodecode = (function() {
120 function _Rhodecode() {
121 this.comments = new (function() { /* comments controller */
122 var self = this;
123
124 this.cancelComment = function(node) {
125 var $node = $(node);
126 var $td = $node.closest('td');
127 $node.closest('.comment-inline-form').removeClass('comment-inline-form-open');
128 return false;
129 }
130 this.getLineNumber = function(node) {
131 var $node = $(node);
132 return $node.closest('td').attr('data-line-number');
133 }
134 this.scrollToComment = function(node, offset) {
135 if (!node) {
136 node = $('.comment-selected');
137 if (!node.length) {
138 node = $('comment-current')
139 }
140 }
141 $comment = $(node).closest('.comment-current');
142 $comments = $('.comment-current');
143
144 $('.comment-selected').removeClass('comment-selected');
145
146 var nextIdx = $('.comment-current').index($comment) + offset;
147 if (nextIdx >= $comments.length) {
148 nextIdx = 0;
149 }
150 var $next = $('.comment-current').eq(nextIdx);
151 var $cb = $next.closest('.cb');
152 $cb.removeClass('cb-collapsed')
153
154 var $filediffCollapseState = $cb.closest('.filediff').prev();
155 $filediffCollapseState.prop('checked', false);
156 $next.addClass('comment-selected');
157 scrollToElement($next);
158 return false;
159 }
160 this.nextComment = function(node) {
161 return self.scrollToComment(node, 1);
162 }
163 this.prevComment = function(node) {
164 return self.scrollToComment(node, -1);
165 }
166 this.deleteComment = function(node) {
167 if (!confirm(_gettext('Delete this comment?'))) {
168 return false;
169 }
170 var $node = $(node);
171 var $td = $node.closest('td');
172 var $comment = $node.closest('.comment');
173 var comment_id = $comment.attr('data-comment-id');
174 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id);
175 var postData = {
176 '_method': 'delete',
177 'csrf_token': CSRF_TOKEN
178 };
179
180 $comment.addClass('comment-deleting');
181 $comment.hide('fast');
182
183 var success = function(response) {
184 $comment.remove();
185 return false;
186 };
187 var failure = function(data, textStatus, xhr) {
188 alert("error processing request: " + textStatus);
189 $comment.show('fast');
190 $comment.removeClass('comment-deleting');
191 return false;
192 };
193 ajaxPOST(url, postData, success, failure);
194 }
195 this.createComment = function(node) {
196 var $node = $(node);
197 var $td = $node.closest('td');
198 var $form = $td.find('.comment-inline-form');
199
200 if (!$form.length) {
201 var tmpl = $('#cb-comment-inline-form-template').html();
202 var f_path = $node.closest('.filediff').attr('data-f-path');
203 var lineno = self.getLineNumber(node);
204 tmpl = tmpl.format(f_path, lineno);
205 $form = $(tmpl);
206
207 var $comments = $td.find('.inline-comments');
208 if (!$comments.length) {
209 $comments = $(
210 $('#cb-comments-inline-container-template').html());
211 $td.append($comments);
212 }
213
214 $td.find('.cb-comment-add-button').before($form);
215
216 var pullRequestId = templateContext.pull_request_data.pull_request_id;
217 var commitId = templateContext.commit_data.commit_id;
218 var _form = $form[0];
219 var commentForm = new CommentForm(_form, commitId, pullRequestId, lineno, false);
220 var cm = commentForm.getCmInstance();
221
222 // set a CUSTOM submit handler for inline comments.
223 commentForm.setHandleFormSubmit(function(o) {
224 var text = commentForm.cm.getValue();
225
226 if (text === "") {
227 return;
228 }
229
230 if (lineno === undefined) {
231 alert('missing line !');
232 return;
233 }
234 if (f_path === undefined) {
235 alert('missing file path !');
236 return;
237 }
238
239 var excludeCancelBtn = false;
240 var submitEvent = true;
241 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
242 commentForm.cm.setOption("readOnly", true);
243 var postData = {
244 'text': text,
245 'f_path': f_path,
246 'line': lineno,
247 'csrf_token': CSRF_TOKEN
248 };
249 var submitSuccessCallback = function(json_data) {
250 $form.remove();
251 console.log(json_data)
252 try {
253 var html = json_data.rendered_text;
254 var lineno = json_data.line_no;
255 var target_id = json_data.target_id;
256
257 $comments.find('.cb-comment-add-button').before(html);
258 console.log(lineno, target_id, $comments);
259
260 } catch (e) {
261 console.error(e);
262 }
263
264
265 // re trigger the linkification of next/prev navigation
266 linkifyComments($('.inline-comment-injected'));
267 timeagoActivate();
268 bindDeleteCommentButtons();
269 commentForm.setActionButtonsDisabled(false);
270
271 };
272 var submitFailCallback = function(){
273 commentForm.resetCommentFormState(text)
274 };
275 commentForm.submitAjaxPOST(
276 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
277 });
278
279 setTimeout(function() {
280 // callbacks
281 if (cm !== undefined) {
282 cm.focus();
283 }
284 }, 10);
285
286 $.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({
287 form: _form,
288 parent: $td[0],
289 lineno: lineno,
290 f_path: f_path}
291 );
292 }
293
294 $form.addClass('comment-inline-form-open');
295 }
296
297 this.renderInlineComments = function(file_comments) {
298 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
299
300 for (var i = 0; i < file_comments.length; i++) {
301 var box = file_comments[i];
302
303 var target_id = $(box).attr('target_id');
304
305 // actually comments with line numbers
306 var comments = box.children;
307
308 for (var j = 0; j < comments.length; j++) {
309 var data = {
310 'rendered_text': comments[j].outerHTML,
311 'line_no': $(comments[j]).attr('line'),
312 'target_id': target_id
313 };
314 }
315 }
316
317 // since order of injection is random, we're now re-iterating
318 // from correct order and filling in links
319 linkifyComments($('.inline-comment-injected'));
320 bindDeleteCommentButtons();
321 firefoxAnchorFix();
322 };
323
324 })();
325 }
326 return new _Rhodecode();
327 })();
328
329 </script>
118 </script>
330 <%include file="/base/plugins_base.html"/>
119 <%include file="/base/plugins_base.html"/>
331 <!--[if lt IE 9]>
120 <!--[if lt IE 9]>
332 <script language="javascript" type="text/javascript" src="${h.asset('js/excanvas.min.js')}"></script>
121 <script language="javascript" type="text/javascript" src="${h.asset('js/excanvas.min.js')}"></script>
333 <![endif]-->
122 <![endif]-->
334 <script language="javascript" type="text/javascript" src="${h.asset('js/rhodecode/routes.js', ver=c.rhodecode_version_hash)}"></script>
123 <script language="javascript" type="text/javascript" src="${h.asset('js/rhodecode/routes.js', ver=c.rhodecode_version_hash)}"></script>
335 <script> var alertMessagePayloads = ${h.flash.json_alerts()|n}; </script>
124 <script> var alertMessagePayloads = ${h.flash.json_alerts()|n}; </script>
336 ## avoide escaping the %N
125 ## avoide escaping the %N
337 <script language="javascript" type="text/javascript" src="${h.asset('js/rhodecode-components.js', ver=c.rhodecode_version_hash)}"></script>
126 <script language="javascript" type="text/javascript" src="${h.asset('js/rhodecode-components.js', ver=c.rhodecode_version_hash)}"></script>
338 <script>CodeMirror.modeURL = "${h.asset('') + 'js/mode/%N/%N.js?ver='+c.rhodecode_version_hash}";</script>
127 <script>CodeMirror.modeURL = "${h.asset('') + 'js/mode/%N/%N.js?ver='+c.rhodecode_version_hash}";</script>
339
128
340
129
341 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
130 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
342 ${self.js_extra()}
131 ${self.js_extra()}
343
132
344 <script type="text/javascript">
133 <script type="text/javascript">
134 Rhodecode = (function() {
135 function _Rhodecode() {
136 this.comments = new CommentsController();
137 }
138 return new _Rhodecode();
139 })();
140
345 $(document).ready(function(){
141 $(document).ready(function(){
346 show_more_event();
142 show_more_event();
347 timeagoActivate();
143 timeagoActivate();
348 })
144 })
349 </script>
145 </script>
350
146
351 </%def>
147 </%def>
352
148
353 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
149 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
354 <%def name="js_extra()"></%def>
150 <%def name="js_extra()"></%def>
355 ${self.js()}
151 ${self.js()}
356
152
357 <%def name="head_extra()"></%def>
153 <%def name="head_extra()"></%def>
358 ${self.head_extra()}
154 ${self.head_extra()}
359 ## extra stuff
155 ## extra stuff
360 %if c.pre_code:
156 %if c.pre_code:
361 ${c.pre_code|n}
157 ${c.pre_code|n}
362 %endif
158 %endif
363 </head>
159 </head>
364 <body id="body">
160 <body id="body">
365 <noscript>
161 <noscript>
366 <div class="noscript-error">
162 <div class="noscript-error">
367 ${_('Please enable JavaScript to use RhodeCode Enterprise')}
163 ${_('Please enable JavaScript to use RhodeCode Enterprise')}
368 </div>
164 </div>
369 </noscript>
165 </noscript>
370 ## IE hacks
166 ## IE hacks
371 <!--[if IE 7]>
167 <!--[if IE 7]>
372 <script>$(document.body).addClass('ie7')</script>
168 <script>$(document.body).addClass('ie7')</script>
373 <![endif]-->
169 <![endif]-->
374 <!--[if IE 8]>
170 <!--[if IE 8]>
375 <script>$(document.body).addClass('ie8')</script>
171 <script>$(document.body).addClass('ie8')</script>
376 <![endif]-->
172 <![endif]-->
377 <!--[if IE 9]>
173 <!--[if IE 9]>
378 <script>$(document.body).addClass('ie9')</script>
174 <script>$(document.body).addClass('ie9')</script>
379 <![endif]-->
175 <![endif]-->
380
176
381 ${next.body()}
177 ${next.body()}
382 %if c.post_code:
178 %if c.post_code:
383 ${c.post_code|n}
179 ${c.post_code|n}
384 %endif
180 %endif
385 <rhodecode-app></rhodecode-app>
181 <rhodecode-app></rhodecode-app>
386 </body>
182 </body>
387 </html>
183 </html>
@@ -1,542 +1,567 b''
1 <%def name="diff_line_anchor(filename, line, type)"><%
1 <%def name="diff_line_anchor(filename, line, type)"><%
2 return '%s_%s_%i' % (h.safeid(filename), type, line)
2 return '%s_%s_%i' % (h.safeid(filename), type, line)
3 %></%def>
3 %></%def>
4
4
5 <%def name="action_class(action)"><%
5 <%def name="action_class(action)"><%
6 return {
6 return {
7 '-': 'cb-deletion',
7 '-': 'cb-deletion',
8 '+': 'cb-addition',
8 '+': 'cb-addition',
9 ' ': 'cb-context',
9 ' ': 'cb-context',
10 }.get(action, 'cb-empty')
10 }.get(action, 'cb-empty')
11 %></%def>
11 %></%def>
12
12
13 <%def name="op_class(op_id)"><%
13 <%def name="op_class(op_id)"><%
14 return {
14 return {
15 DEL_FILENODE: 'deletion', # file deleted
15 DEL_FILENODE: 'deletion', # file deleted
16 BIN_FILENODE: 'warning' # binary diff hidden
16 BIN_FILENODE: 'warning' # binary diff hidden
17 }.get(op_id, 'addition')
17 }.get(op_id, 'addition')
18 %></%def>
18 %></%def>
19
19
20 <%def name="link_for(**kw)"><%
20 <%def name="link_for(**kw)"><%
21 new_args = request.GET.mixed()
21 new_args = request.GET.mixed()
22 new_args.update(kw)
22 new_args.update(kw)
23 return h.url('', **new_args)
23 return h.url('', **new_args)
24 %></%def>
24 %></%def>
25
25
26 <%def name="render_diffset(diffset, commit=None,
26 <%def name="render_diffset(diffset, commit=None,
27
27
28 # collapse all file diff entries when there are more than this amount of files in the diff
28 # collapse all file diff entries when there are more than this amount of files in the diff
29 collapse_when_files_over=20,
29 collapse_when_files_over=20,
30
30
31 # collapse lines in the diff when more than this amount of lines changed in the file diff
31 # collapse lines in the diff when more than this amount of lines changed in the file diff
32 lines_changed_limit=500,
32 lines_changed_limit=500,
33
33
34 # add a ruler at to the output
34 # add a ruler at to the output
35 ruler_at_chars=0,
35 ruler_at_chars=0,
36
36
37 # turn on inline comments
37 # turn on inline comments
38 use_comments=False,
38 use_comments=False,
39
39
40 )">
40 )">
41
41
42 %if use_comments:
42 %if use_comments:
43 <div id="cb-comments-inline-container-template" class="js-template">
43 <div id="cb-comments-inline-container-template" class="js-template">
44 ${inline_comments_container([])}
44 ${inline_comments_container([])}
45 </div>
45 </div>
46 <div class="js-template" id="cb-comment-inline-form-template">
46 <div class="js-template" id="cb-comment-inline-form-template">
47 <div class="comment-inline-form ac">
47 <div class="comment-inline-form ac">
48 %if c.rhodecode_user.username != h.DEFAULT_USER:
48 %if c.rhodecode_user.username != h.DEFAULT_USER:
49 ${h.form('#', method='get')}
49 ${h.form('#', method='get')}
50 <div id="edit-container_{1}" class="clearfix">
50 <div id="edit-container_{1}" class="clearfix">
51 <div class="comment-title pull-left">
51 <div class="comment-title pull-left">
52 ${_('Create a comment on line {1}.')}
52 ${_('Create a comment on line {1}.')}
53 </div>
53 </div>
54 <div class="comment-help pull-right">
54 <div class="comment-help pull-right">
55 ${(_('Comments parsed using %s syntax with %s support.') % (
55 ${(_('Comments parsed using %s syntax with %s support.') % (
56 ('<a href="%s">%s</a>' % (h.url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper())),
56 ('<a href="%s">%s</a>' % (h.url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper())),
57 ('<span class="tooltip" title="%s">@mention</span>' % _('Use @username inside this text to send notification to this RhodeCode user'))
57 ('<span class="tooltip" title="%s">@mention</span>' % _('Use @username inside this text to send notification to this RhodeCode user'))
58 )
58 )
59 )|n
59 )|n
60 }
60 }
61 </div>
61 </div>
62 <div style="clear: both"></div>
62 <div style="clear: both"></div>
63 <textarea id="text_{1}" name="text" class="comment-block-ta ac-input"></textarea>
63 <textarea id="text_{1}" name="text" class="comment-block-ta ac-input"></textarea>
64 </div>
64 </div>
65 <div id="preview-container_{1}" class="clearfix" style="display: none;">
65 <div id="preview-container_{1}" class="clearfix" style="display: none;">
66 <div class="comment-help">
66 <div class="comment-help">
67 ${_('Comment preview')}
67 ${_('Comment preview')}
68 </div>
68 </div>
69 <div id="preview-box_{1}" class="preview-box"></div>
69 <div id="preview-box_{1}" class="preview-box"></div>
70 </div>
70 </div>
71 <div class="comment-footer">
71 <div class="comment-footer">
72 <div class="action-buttons">
72 <div class="action-buttons">
73 <input type="hidden" name="f_path" value="{0}">
73 <input type="hidden" name="f_path" value="{0}">
74 <input type="hidden" name="line" value="{1}">
74 <input type="hidden" name="line" value="{1}">
75 <button id="preview-btn_{1}" class="btn btn-secondary">${_('Preview')}</button>
75 <button id="preview-btn_{1}" class="btn btn-secondary">${_('Preview')}</button>
76 <button id="edit-btn_{1}" class="btn btn-secondary" style="display: none;">${_('Edit')}</button>
76 <button id="edit-btn_{1}" class="btn btn-secondary" style="display: none;">${_('Edit')}</button>
77 ${h.submit('save', _('Comment'), class_='btn btn-success save-inline-form')}
77 ${h.submit('save', _('Comment'), class_='btn btn-success save-inline-form')}
78 </div>
78 </div>
79 <div class="comment-button">
79 <div class="comment-button">
80 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
80 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
81 ${_('Cancel')}
81 ${_('Cancel')}
82 </button>
82 </button>
83 </div>
83 </div>
84 ${h.end_form()}
84 ${h.end_form()}
85 </div>
85 </div>
86 %else:
86 %else:
87 ${h.form('', class_='inline-form comment-form-login', method='get')}
87 ${h.form('', class_='inline-form comment-form-login', method='get')}
88 <div class="pull-left">
88 <div class="pull-left">
89 <div class="comment-help pull-right">
89 <div class="comment-help pull-right">
90 ${_('You need to be logged in to comment.')} <a href="${h.route_path('login', _query={'came_from': h.url.current()})}">${_('Login now')}</a>
90 ${_('You need to be logged in to comment.')} <a href="${h.route_path('login', _query={'came_from': h.url.current()})}">${_('Login now')}</a>
91 </div>
91 </div>
92 </div>
92 </div>
93 <div class="comment-button pull-right">
93 <div class="comment-button pull-right">
94 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
94 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
95 ${_('Cancel')}
95 ${_('Cancel')}
96 </button>
96 </button>
97 </div>
97 </div>
98 <div class="clearfix"></div>
98 <div class="clearfix"></div>
99 ${h.end_form()}
99 ${h.end_form()}
100 %endif
100 %endif
101 </div>
101 </div>
102 </div>
102 </div>
103
103
104 %endif
104 %endif
105 <%
105 <%
106 collapse_all = len(diffset.files) > collapse_when_files_over
106 collapse_all = len(diffset.files) > collapse_when_files_over
107 %>
107 %>
108
108
109 %if c.diffmode == 'sideside':
109 %if c.diffmode == 'sideside':
110 <style>
110 <style>
111 .wrapper {
111 .wrapper {
112 max-width: 1600px !important;
112 max-width: 1600px !important;
113 }
113 }
114 </style>
114 </style>
115 %endif
115 %endif
116 %if ruler_at_chars:
116 %if ruler_at_chars:
117 <style>
117 <style>
118 .diff table.cb .cb-content:after {
118 .diff table.cb .cb-content:after {
119 content: "";
119 content: "";
120 border-left: 1px solid blue;
120 border-left: 1px solid blue;
121 position: absolute;
121 position: absolute;
122 top: 0;
122 top: 0;
123 height: 18px;
123 height: 18px;
124 opacity: .2;
124 opacity: .2;
125 z-index: 10;
125 z-index: 10;
126 ## +5 to account for diff action (+/-)
126 ## +5 to account for diff action (+/-)
127 left: ${ruler_at_chars + 5}ch;
127 left: ${ruler_at_chars + 5}ch;
128 </style>
128 </style>
129 %endif
129 %endif
130
130
131 <div class="diffset">
131 <div class="diffset">
132 <div class="diffset-heading ${diffset.limited_diff and 'diffset-heading-warning' or ''}">
132 <div class="diffset-heading ${diffset.limited_diff and 'diffset-heading-warning' or ''}">
133 %if commit:
133 %if commit:
134 <div class="pull-right">
134 <div class="pull-right">
135 <a class="btn tooltip" title="${_('Browse Files at revision {}').format(commit.raw_id)}" href="${h.url('files_home',repo_name=diffset.repo_name, revision=commit.raw_id, f_path='')}">
135 <a class="btn tooltip" title="${_('Browse Files at revision {}').format(commit.raw_id)}" href="${h.url('files_home',repo_name=diffset.repo_name, revision=commit.raw_id, f_path='')}">
136 ${_('Browse Files')}
136 ${_('Browse Files')}
137 </a>
137 </a>
138 </div>
138 </div>
139 %endif
139 %endif
140 <h2 class="clearinner">
140 <h2 class="clearinner">
141 %if commit:
141 %if commit:
142 <a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id)}">${'r%s:%s' % (commit.revision,h.short_id(commit.raw_id))}</a> -
142 <a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id)}">${'r%s:%s' % (commit.revision,h.short_id(commit.raw_id))}</a> -
143 ${h.age_component(commit.date)} -
143 ${h.age_component(commit.date)} -
144 %endif
144 %endif
145 %if diffset.limited_diff:
145 %if diffset.limited_diff:
146 ${_('The requested commit is too big and content was truncated.')}
146 ${_('The requested commit is too big and content was truncated.')}
147
147
148 ${ungettext('%(num)s file changed.', '%(num)s files changed.', diffset.changed_files) % {'num': diffset.changed_files}}
148 ${ungettext('%(num)s file changed.', '%(num)s files changed.', diffset.changed_files) % {'num': diffset.changed_files}}
149 <a href="${link_for(fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
149 <a href="${link_for(fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
150 %else:
150 %else:
151 ${ungettext('%(num)s file changed: %(linesadd)s inserted, ''%(linesdel)s deleted',
151 ${ungettext('%(num)s file changed: %(linesadd)s inserted, ''%(linesdel)s deleted',
152 '%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted', diffset.changed_files) % {'num': diffset.changed_files, 'linesadd': diffset.lines_added, 'linesdel': diffset.lines_deleted}}
152 '%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted', diffset.changed_files) % {'num': diffset.changed_files, 'linesadd': diffset.lines_added, 'linesdel': diffset.lines_deleted}}
153 %endif
153 %endif
154 </h2>
154 </h2>
155 </div>
155 </div>
156
156
157 %if not diffset.files:
157 %if not diffset.files:
158 <p class="empty_data">${_('No files')}</p>
158 <p class="empty_data">${_('No files')}</p>
159 %endif
159 %endif
160
160
161 <div class="filediffs">
161 <div class="filediffs">
162 %for i, filediff in enumerate(diffset.files):
162 %for i, filediff in enumerate(diffset.files):
163 <%
163 <%
164 lines_changed = filediff['patch']['stats']['added'] + filediff['patch']['stats']['deleted']
164 lines_changed = filediff['patch']['stats']['added'] + filediff['patch']['stats']['deleted']
165 over_lines_changed_limit = lines_changed > lines_changed_limit
165 over_lines_changed_limit = lines_changed > lines_changed_limit
166 %>
166 %>
167 <input ${collapse_all and 'checked' or ''} class="filediff-collapse-state" id="filediff-collapse-${id(filediff)}" type="checkbox">
167 <input ${collapse_all and 'checked' or ''} class="filediff-collapse-state" id="filediff-collapse-${id(filediff)}" type="checkbox">
168 <div
168 <div
169 class="filediff"
169 class="filediff"
170 data-f-path="${filediff['patch']['filename']}"
170 data-f-path="${filediff['patch']['filename']}"
171 id="a_${h.FID('', filediff['patch']['filename'])}">
171 id="a_${h.FID('', filediff['patch']['filename'])}">
172 <label for="filediff-collapse-${id(filediff)}" class="filediff-heading">
172 <label for="filediff-collapse-${id(filediff)}" class="filediff-heading">
173 <div class="filediff-collapse-indicator"></div>
173 <div class="filediff-collapse-indicator"></div>
174 ${diff_ops(filediff)}
174 ${diff_ops(filediff)}
175 </label>
175 </label>
176 ${diff_menu(filediff, use_comments=use_comments)}
176 ${diff_menu(filediff, use_comments=use_comments)}
177 <table class="cb cb-diff-${c.diffmode} code-highlight ${over_lines_changed_limit and 'cb-collapsed' or ''}">
177 <table class="cb cb-diff-${c.diffmode} code-highlight ${over_lines_changed_limit and 'cb-collapsed' or ''}">
178 %if not filediff.hunks:
178 %if not filediff.hunks:
179 %for op_id, op_text in filediff['patch']['stats']['ops'].items():
179 %for op_id, op_text in filediff['patch']['stats']['ops'].items():
180 <tr>
180 <tr>
181 <td class="cb-text cb-${op_class(op_id)}" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}>
181 <td class="cb-text cb-${op_class(op_id)}" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}>
182 %if op_id == DEL_FILENODE:
182 %if op_id == DEL_FILENODE:
183 ${_('File was deleted')}
183 ${_('File was deleted')}
184 %elif op_id == BIN_FILENODE:
184 %elif op_id == BIN_FILENODE:
185 ${_('Binary file hidden')}
185 ${_('Binary file hidden')}
186 %else:
186 %else:
187 ${op_text}
187 ${op_text}
188 %endif
188 %endif
189 </td>
189 </td>
190 </tr>
190 </tr>
191 %endfor
191 %endfor
192 %endif
192 %endif
193 %if over_lines_changed_limit:
193 %if over_lines_changed_limit:
194 <tr class="cb-warning cb-collapser">
194 <tr class="cb-warning cb-collapser">
195 <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}>
195 <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=4' or 'colspan=4'}>
196 ${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)}
196 ${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)}
197 <a href="#" class="cb-expand"
197 <a href="#" class="cb-expand"
198 onclick="$(this).closest('table').removeClass('cb-collapsed'); return false;">${_('Show them')}
198 onclick="$(this).closest('table').removeClass('cb-collapsed'); return false;">${_('Show them')}
199 </a>
199 </a>
200 <a href="#" class="cb-collapse"
200 <a href="#" class="cb-collapse"
201 onclick="$(this).closest('table').addClass('cb-collapsed'); return false;">${_('Hide them')}
201 onclick="$(this).closest('table').addClass('cb-collapsed'); return false;">${_('Hide them')}
202 </a>
202 </a>
203 </td>
203 </td>
204 </tr>
204 </tr>
205 %endif
205 %endif
206 %if filediff.patch['is_limited_diff']:
206 %if filediff.patch['is_limited_diff']:
207 <tr class="cb-warning cb-collapser">
207 <tr class="cb-warning cb-collapser">
208 <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}>
208 <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=4' or 'colspan=4'}>
209 ${_('The requested commit is too big and content was truncated.')} <a href="${link_for(fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
209 ${_('The requested commit is too big and content was truncated.')} <a href="${link_for(fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
210 </td>
210 </td>
211 </tr>
211 </tr>
212 %endif
212 %endif
213 %for hunk in filediff.hunks:
213 %for hunk in filediff.hunks:
214 <tr class="cb-hunk">
214 <tr class="cb-hunk">
215 <td ${c.diffmode == 'unified' and 'colspan=2' or ''}>
215 <td ${c.diffmode == 'unified' and 'colspan=3' or ''}>
216 ## TODO: dan: add ajax loading of more context here
216 ## TODO: dan: add ajax loading of more context here
217 ## <a href="#">
217 ## <a href="#">
218 <i class="icon-more"></i>
218 <i class="icon-more"></i>
219 ## </a>
219 ## </a>
220 </td>
220 </td>
221 <td ${c.diffmode == 'sideside' and 'colspan=3' or ''}>
221 <td ${c.diffmode == 'sideside' and 'colspan=5' or ''}>
222 @@
222 @@
223 -${hunk.source_start},${hunk.source_length}
223 -${hunk.source_start},${hunk.source_length}
224 +${hunk.target_start},${hunk.target_length}
224 +${hunk.target_start},${hunk.target_length}
225 ${hunk.section_header}
225 ${hunk.section_header}
226 </td>
226 </td>
227 </tr>
227 </tr>
228 %if c.diffmode == 'unified':
228 %if c.diffmode == 'unified':
229 ${render_hunk_lines_unified(hunk, use_comments=use_comments)}
229 ${render_hunk_lines_unified(hunk, use_comments=use_comments)}
230 %elif c.diffmode == 'sideside':
230 %elif c.diffmode == 'sideside':
231 ${render_hunk_lines_sideside(hunk, use_comments=use_comments)}
231 ${render_hunk_lines_sideside(hunk, use_comments=use_comments)}
232 %else:
232 %else:
233 <tr class="cb-line">
233 <tr class="cb-line">
234 <td>unknown diff mode</td>
234 <td>unknown diff mode</td>
235 </tr>
235 </tr>
236 %endif
236 %endif
237 %endfor
237 %endfor
238 </table>
238 </table>
239 </div>
239 </div>
240 %endfor
240 %endfor
241 </div>
241 </div>
242 </div>
242 </div>
243 </%def>
243 </%def>
244
244
245 <%def name="diff_ops(filediff)">
245 <%def name="diff_ops(filediff)">
246 <%
246 <%
247 stats = filediff['patch']['stats']
247 stats = filediff['patch']['stats']
248 from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \
248 from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \
249 MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE
249 MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE
250 %>
250 %>
251 <span class="pill">
251 <span class="pill">
252 %if filediff.source_file_path and filediff.target_file_path:
252 %if filediff.source_file_path and filediff.target_file_path:
253 %if filediff.source_file_path != filediff.target_file_path: # file was renamed
253 %if filediff.source_file_path != filediff.target_file_path: # file was renamed
254 <strong>${filediff.target_file_path}</strong> β¬… <del>${filediff.source_file_path}</del>
254 <strong>${filediff.target_file_path}</strong> β¬… <del>${filediff.source_file_path}</del>
255 %else:
255 %else:
256 ## file was modified
256 ## file was modified
257 <strong>${filediff.source_file_path}</strong>
257 <strong>${filediff.source_file_path}</strong>
258 %endif
258 %endif
259 %else:
259 %else:
260 %if filediff.source_file_path:
260 %if filediff.source_file_path:
261 ## file was deleted
261 ## file was deleted
262 <strong>${filediff.source_file_path}</strong>
262 <strong>${filediff.source_file_path}</strong>
263 %else:
263 %else:
264 ## file was added
264 ## file was added
265 <strong>${filediff.target_file_path}</strong>
265 <strong>${filediff.target_file_path}</strong>
266 %endif
266 %endif
267 %endif
267 %endif
268 </span>
268 </span>
269 <span class="pill-group" style="float: left">
269 <span class="pill-group" style="float: left">
270 %if filediff.patch['is_limited_diff']:
270 %if filediff.patch['is_limited_diff']:
271 <span class="pill tooltip" op="limited" title="The stats for this diff are not complete">limited diff</span>
271 <span class="pill tooltip" op="limited" title="The stats for this diff are not complete">limited diff</span>
272 %endif
272 %endif
273 %if RENAMED_FILENODE in stats['ops']:
273 %if RENAMED_FILENODE in stats['ops']:
274 <span class="pill" op="renamed">renamed</span>
274 <span class="pill" op="renamed">renamed</span>
275 %endif
275 %endif
276
276
277 %if NEW_FILENODE in stats['ops']:
277 %if NEW_FILENODE in stats['ops']:
278 <span class="pill" op="created">created</span>
278 <span class="pill" op="created">created</span>
279 %if filediff['target_mode'].startswith('120'):
279 %if filediff['target_mode'].startswith('120'):
280 <span class="pill" op="symlink">symlink</span>
280 <span class="pill" op="symlink">symlink</span>
281 %else:
281 %else:
282 <span class="pill" op="mode">${nice_mode(filediff['target_mode'])}</span>
282 <span class="pill" op="mode">${nice_mode(filediff['target_mode'])}</span>
283 %endif
283 %endif
284 %endif
284 %endif
285
285
286 %if DEL_FILENODE in stats['ops']:
286 %if DEL_FILENODE in stats['ops']:
287 <span class="pill" op="removed">removed</span>
287 <span class="pill" op="removed">removed</span>
288 %endif
288 %endif
289
289
290 %if CHMOD_FILENODE in stats['ops']:
290 %if CHMOD_FILENODE in stats['ops']:
291 <span class="pill" op="mode">
291 <span class="pill" op="mode">
292 ${nice_mode(filediff['source_mode'])} ➑ ${nice_mode(filediff['target_mode'])}
292 ${nice_mode(filediff['source_mode'])} ➑ ${nice_mode(filediff['target_mode'])}
293 </span>
293 </span>
294 %endif
294 %endif
295 </span>
295 </span>
296
296
297 <a class="pill filediff-anchor" href="#a_${h.FID('', filediff.patch['filename'])}">ΒΆ</a>
297 <a class="pill filediff-anchor" href="#a_${h.FID('', filediff.patch['filename'])}">ΒΆ</a>
298
298
299 <span class="pill-group" style="float: right">
299 <span class="pill-group" style="float: right">
300 %if BIN_FILENODE in stats['ops']:
300 %if BIN_FILENODE in stats['ops']:
301 <span class="pill" op="binary">binary</span>
301 <span class="pill" op="binary">binary</span>
302 %if MOD_FILENODE in stats['ops']:
302 %if MOD_FILENODE in stats['ops']:
303 <span class="pill" op="modified">modified</span>
303 <span class="pill" op="modified">modified</span>
304 %endif
304 %endif
305 %endif
305 %endif
306 %if stats['added']:
306 %if stats['added']:
307 <span class="pill" op="added">+${stats['added']}</span>
307 <span class="pill" op="added">+${stats['added']}</span>
308 %endif
308 %endif
309 %if stats['deleted']:
309 %if stats['deleted']:
310 <span class="pill" op="deleted">-${stats['deleted']}</span>
310 <span class="pill" op="deleted">-${stats['deleted']}</span>
311 %endif
311 %endif
312 </span>
312 </span>
313
313
314 </%def>
314 </%def>
315
315
316 <%def name="nice_mode(filemode)">
316 <%def name="nice_mode(filemode)">
317 ${filemode.startswith('100') and filemode[3:] or filemode}
317 ${filemode.startswith('100') and filemode[3:] or filemode}
318 </%def>
318 </%def>
319
319
320 <%def name="diff_menu(filediff, use_comments=False)">
320 <%def name="diff_menu(filediff, use_comments=False)">
321 <div class="filediff-menu">
321 <div class="filediff-menu">
322 %if filediff.diffset.source_ref:
322 %if filediff.diffset.source_ref:
323 %if filediff.patch['operation'] in ['D', 'M']:
323 %if filediff.patch['operation'] in ['D', 'M']:
324 <a
324 <a
325 class="tooltip"
325 class="tooltip"
326 href="${h.url('files_home',repo_name=filediff.diffset.repo_name,f_path=filediff.source_file_path,revision=filediff.diffset.source_ref)}"
326 href="${h.url('files_home',repo_name=filediff.diffset.repo_name,f_path=filediff.source_file_path,revision=filediff.diffset.source_ref)}"
327 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
327 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
328 >
328 >
329 ${_('Show file before')}
329 ${_('Show file before')}
330 </a>
330 </a>
331 %else:
331 %else:
332 <span
332 <span
333 class="tooltip"
333 class="tooltip"
334 title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
334 title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
335 >
335 >
336 ${_('Show file before')}
336 ${_('Show file before')}
337 </span>
337 </span>
338 %endif
338 %endif
339 %if filediff.patch['operation'] in ['A', 'M']:
339 %if filediff.patch['operation'] in ['A', 'M']:
340 <a
340 <a
341 class="tooltip"
341 class="tooltip"
342 href="${h.url('files_home',repo_name=filediff.diffset.repo_name,f_path=filediff.target_file_path,revision=filediff.diffset.target_ref)}"
342 href="${h.url('files_home',repo_name=filediff.diffset.repo_name,f_path=filediff.target_file_path,revision=filediff.diffset.target_ref)}"
343 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
343 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
344 >
344 >
345 ${_('Show file after')}
345 ${_('Show file after')}
346 </a>
346 </a>
347 %else:
347 %else:
348 <span
348 <span
349 class="tooltip"
349 class="tooltip"
350 title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
350 title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
351 >
351 >
352 ${_('Show file after')}
352 ${_('Show file after')}
353 </span>
353 </span>
354 %endif
354 %endif
355 <a
355 <a
356 class="tooltip"
356 class="tooltip"
357 title="${h.tooltip(_('Raw diff'))}"
357 title="${h.tooltip(_('Raw diff'))}"
358 href="${h.url('files_diff_home',repo_name=filediff.diffset.repo_name,f_path=filediff.target_file_path,diff2=filediff.diffset.target_ref,diff1=filediff.diffset.source_ref,diff='raw')}"
358 href="${h.url('files_diff_home',repo_name=filediff.diffset.repo_name,f_path=filediff.target_file_path,diff2=filediff.diffset.target_ref,diff1=filediff.diffset.source_ref,diff='raw')}"
359 >
359 >
360 ${_('Raw diff')}
360 ${_('Raw diff')}
361 </a>
361 </a>
362 <a
362 <a
363 class="tooltip"
363 class="tooltip"
364 title="${h.tooltip(_('Download diff'))}"
364 title="${h.tooltip(_('Download diff'))}"
365 href="${h.url('files_diff_home',repo_name=filediff.diffset.repo_name,f_path=filediff.target_file_path,diff2=filediff.diffset.target_ref,diff1=filediff.diffset.source_ref,diff='download')}"
365 href="${h.url('files_diff_home',repo_name=filediff.diffset.repo_name,f_path=filediff.target_file_path,diff2=filediff.diffset.target_ref,diff1=filediff.diffset.source_ref,diff='download')}"
366 >
366 >
367 ${_('Download diff')}
367 ${_('Download diff')}
368 </a>
368 </a>
369
369
370 ## TODO: dan: refactor ignorews_url and context_url into the diff renderer same as diffmode=unified/sideside. Also use ajax to load more context (by clicking hunks)
370 ## TODO: dan: refactor ignorews_url and context_url into the diff renderer same as diffmode=unified/sideside. Also use ajax to load more context (by clicking hunks)
371 %if hasattr(c, 'ignorews_url'):
371 %if hasattr(c, 'ignorews_url'):
372 ${c.ignorews_url(request.GET, h.FID('', filediff['patch']['filename']))}
372 ${c.ignorews_url(request.GET, h.FID('', filediff['patch']['filename']))}
373 %endif
373 %endif
374 %if hasattr(c, 'context_url'):
374 %if hasattr(c, 'context_url'):
375 ${c.context_url(request.GET, h.FID('', filediff['patch']['filename']))}
375 ${c.context_url(request.GET, h.FID('', filediff['patch']['filename']))}
376 %endif
376 %endif
377
377
378
378
379 %if use_comments:
379 %if use_comments:
380 <a href="#" onclick="$(this).closest('.filediff').toggleClass('hide-comments'); return false;">
380 <a href="#" onclick="return Rhodecode.comments.toggleComments(this);">
381 <span class="show-comment-button">${_('Show comments')}</span><span class="hide-comment-button">${_('Hide comments')}</span>
381 <span class="show-comment-button">${_('Show comments')}</span><span class="hide-comment-button">${_('Hide comments')}</span>
382 </a>
382 </a>
383 %endif
383 %endif
384 %endif
384 %endif
385 </div>
385 </div>
386 </%def>
386 </%def>
387
387
388
388
389 <%namespace name="commentblock" file="/changeset/changeset_file_comment.html"/>
389 <%namespace name="commentblock" file="/changeset/changeset_file_comment.html"/>
390 <%def name="inline_comments_container(comments)">
390 <%def name="inline_comments_container(comments)">
391 <div class="inline-comments">
391 <div class="inline-comments">
392 %for comment in comments:
392 %for comment in comments:
393 ${commentblock.comment_block(comment, inline=True)}
393 ${commentblock.comment_block(comment, inline=True)}
394 %endfor
394 %endfor
395 <span onclick="return Rhodecode.comments.createComment(this)"
395 <span onclick="return Rhodecode.comments.createComment(this)"
396 class="btn btn-secondary cb-comment-add-button">
396 class="btn btn-secondary cb-comment-add-button">
397 ${_('Add another comment')}
397 ${_('Add another comment')}
398 </span>
398 </span>
399 </div>
399 </div>
400 </%def>
400 </%def>
401
401
402
402
403 <%def name="render_hunk_lines_sideside(hunk, use_comments=False)">
403 <%def name="render_hunk_lines_sideside(hunk, use_comments=False)">
404 %for i, line in enumerate(hunk.sideside):
404 %for i, line in enumerate(hunk.sideside):
405 <%
405 <%
406 old_line_anchor, new_line_anchor = None, None
406 old_line_anchor, new_line_anchor = None, None
407 if line.original.lineno:
407 if line.original.lineno:
408 old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, line.original.lineno, 'o')
408 old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, line.original.lineno, 'o')
409 if line.modified.lineno:
409 if line.modified.lineno:
410 new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, line.modified.lineno, 'n')
410 new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, line.modified.lineno, 'n')
411 %>
411 %>
412 <tr class="cb-line">
412 <tr class="cb-line">
413 <td class="cb-data ${action_class(line.original.action)}"
414 data-line-number="${line.original.lineno}"
415 >
416 <div>
417 %if line.original.comments:
418 <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
419 %endif
420 </div>
421 </td>
413 <td class="cb-lineno ${action_class(line.original.action)}"
422 <td class="cb-lineno ${action_class(line.original.action)}"
414 data-line-number="${line.original.lineno}"
423 data-line-number="${line.original.lineno}"
415 %if old_line_anchor:
424 %if old_line_anchor:
416 id="${old_line_anchor}"
425 id="${old_line_anchor}"
417 %endif
426 %endif
418 >
427 >
419 %if line.original.lineno:
428 %if line.original.lineno:
420 <a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a>
429 <a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a>
421 %endif
430 %endif
422 </td>
431 </td>
423 <td class="cb-content ${action_class(line.original.action)}"
432 <td class="cb-content ${action_class(line.original.action)}"
424 data-line-number="o${line.original.lineno}"
433 data-line-number="o${line.original.lineno}"
425 >
434 >
426 %if use_comments and line.original.lineno:
435 %if use_comments and line.original.lineno:
427 ${render_add_comment_button()}
436 ${render_add_comment_button()}
428 %endif
437 %endif
429 <span class="cb-code">${line.original.action} ${line.original.content or '' | n}</span>
438 <span class="cb-code">${line.original.action} ${line.original.content or '' | n}</span>
430 %if use_comments and line.original.lineno and line.original.comments:
439 %if use_comments and line.original.lineno and line.original.comments:
431 ${inline_comments_container(line.original.comments)}
440 ${inline_comments_container(line.original.comments)}
432 %endif
441 %endif
433 </td>
442 </td>
443 <td class="cb-data ${action_class(line.modified.action)}"
444 data-line-number="${line.modified.lineno}"
445 >
446 <div>
447 %if line.modified.comments:
448 <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
449 %endif
450 </div>
451 </td>
434 <td class="cb-lineno ${action_class(line.modified.action)}"
452 <td class="cb-lineno ${action_class(line.modified.action)}"
435 data-line-number="${line.modified.lineno}"
453 data-line-number="${line.modified.lineno}"
436 %if new_line_anchor:
454 %if new_line_anchor:
437 id="${new_line_anchor}"
455 id="${new_line_anchor}"
438 %endif
456 %endif
439 >
457 >
440 %if line.modified.lineno:
458 %if line.modified.lineno:
441 <a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a>
459 <a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a>
442 %endif
460 %endif
443 </td>
461 </td>
444 <td class="cb-content ${action_class(line.modified.action)}"
462 <td class="cb-content ${action_class(line.modified.action)}"
445 data-line-number="n${line.modified.lineno}"
463 data-line-number="n${line.modified.lineno}"
446 >
464 >
447 %if use_comments and line.modified.lineno:
465 %if use_comments and line.modified.lineno:
448 ${render_add_comment_button()}
466 ${render_add_comment_button()}
449 %endif
467 %endif
450 <span class="cb-code">${line.modified.action} ${line.modified.content or '' | n}</span>
468 <span class="cb-code">${line.modified.action} ${line.modified.content or '' | n}</span>
451 %if use_comments and line.modified.lineno and line.modified.comments:
469 %if use_comments and line.modified.lineno and line.modified.comments:
452 ${inline_comments_container(line.modified.comments)}
470 ${inline_comments_container(line.modified.comments)}
453 %endif
471 %endif
454 </td>
472 </td>
455 </tr>
473 </tr>
456 %endfor
474 %endfor
457 </%def>
475 </%def>
458
476
459
477
460 <%def name="render_hunk_lines_unified(hunk, use_comments=False)">
478 <%def name="render_hunk_lines_unified(hunk, use_comments=False)">
461 %for old_line_no, new_line_no, action, content, comments in hunk.unified:
479 %for old_line_no, new_line_no, action, content, comments in hunk.unified:
462 <%
480 <%
463 old_line_anchor, new_line_anchor = None, None
481 old_line_anchor, new_line_anchor = None, None
464 if old_line_no:
482 if old_line_no:
465 old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, old_line_no, 'o')
483 old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, old_line_no, 'o')
466 if new_line_no:
484 if new_line_no:
467 new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, new_line_no, 'n')
485 new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, new_line_no, 'n')
468 %>
486 %>
469 <tr class="cb-line">
487 <tr class="cb-line">
488 <td class="cb-data ${action_class(action)}">
489 <div>
490 %if comments:
491 <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
492 %endif
493 </div>
494 </td>
470 <td class="cb-lineno ${action_class(action)}"
495 <td class="cb-lineno ${action_class(action)}"
471 data-line-number="${old_line_no}"
496 data-line-number="${old_line_no}"
472 %if old_line_anchor:
497 %if old_line_anchor:
473 id="${old_line_anchor}"
498 id="${old_line_anchor}"
474 %endif
499 %endif
475 >
500 >
476 %if old_line_anchor:
501 %if old_line_anchor:
477 <a name="${old_line_anchor}" href="#${old_line_anchor}">${old_line_no}</a>
502 <a name="${old_line_anchor}" href="#${old_line_anchor}">${old_line_no}</a>
478 %endif
503 %endif
479 </td>
504 </td>
480 <td class="cb-lineno ${action_class(action)}"
505 <td class="cb-lineno ${action_class(action)}"
481 data-line-number="${new_line_no}"
506 data-line-number="${new_line_no}"
482 %if new_line_anchor:
507 %if new_line_anchor:
483 id="${new_line_anchor}"
508 id="${new_line_anchor}"
484 %endif
509 %endif
485 >
510 >
486 %if new_line_anchor:
511 %if new_line_anchor:
487 <a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a>
512 <a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a>
488 %endif
513 %endif
489 </td>
514 </td>
490 <td class="cb-content ${action_class(action)}"
515 <td class="cb-content ${action_class(action)}"
491 data-line-number="${new_line_no and 'n' or 'o'}${new_line_no or old_line_no}"
516 data-line-number="${new_line_no and 'n' or 'o'}${new_line_no or old_line_no}"
492 >
517 >
493 %if use_comments:
518 %if use_comments:
494 ${render_add_comment_button()}
519 ${render_add_comment_button()}
495 %endif
520 %endif
496 <span class="cb-code">${action} ${content or '' | n}</span>
521 <span class="cb-code">${action} ${content or '' | n}</span>
497 %if use_comments and comments:
522 %if use_comments and comments:
498 ${inline_comments_container(comments)}
523 ${inline_comments_container(comments)}
499 %endif
524 %endif
500 </td>
525 </td>
501 </tr>
526 </tr>
502 %endfor
527 %endfor
503 </%def>
528 </%def>
504
529
505 <%def name="render_add_comment_button()">
530 <%def name="render_add_comment_button()">
506 <button
531 <button
507 class="btn btn-small btn-primary cb-comment-box-opener"
532 class="btn btn-small btn-primary cb-comment-box-opener"
508 onclick="return Rhodecode.comments.createComment(this)"
533 onclick="return Rhodecode.comments.createComment(this)"
509 >+</button>
534 ><span>+</span></button>
510 </%def>
535 </%def>
511
536
512 <%def name="render_diffset_menu()">
537 <%def name="render_diffset_menu()">
513 <div class="diffset-menu clearinner">
538 <div class="diffset-menu clearinner">
514 <div class="pull-right">
539 <div class="pull-right">
515 <div class="btn-group">
540 <div class="btn-group">
516 <a
541 <a
517 class="btn ${c.diffmode == 'sideside' and 'btn-primary'} tooltip"
542 class="btn ${c.diffmode == 'sideside' and 'btn-primary'} tooltip"
518 title="${_('View side by side')}"
543 title="${_('View side by side')}"
519 href="${h.url_replace(diffmode='sideside')}">
544 href="${h.url_replace(diffmode='sideside')}">
520 <span>${_('Side by Side')}</span>
545 <span>${_('Side by Side')}</span>
521 </a>
546 </a>
522 <a
547 <a
523 class="btn ${c.diffmode == 'unified' and 'btn-primary'} tooltip"
548 class="btn ${c.diffmode == 'unified' and 'btn-primary'} tooltip"
524 title="${_('View unified')}" href="${h.url_replace(diffmode='unified')}">
549 title="${_('View unified')}" href="${h.url_replace(diffmode='unified')}">
525 <span>${_('Unified')}</span>
550 <span>${_('Unified')}</span>
526 </a>
551 </a>
527 </div>
552 </div>
528 </div>
553 </div>
529 <div class="pull-left">
554 <div class="pull-left">
530 <div class="btn-group">
555 <div class="btn-group">
531 <a
556 <a
532 class="btn"
557 class="btn"
533 href="#"
558 href="#"
534 onclick="$('input[class=filediff-collapse-state]').prop('checked', false); return false">${_('Expand All')}</a>
559 onclick="$('input[class=filediff-collapse-state]').prop('checked', false); return false">${_('Expand All')}</a>
535 <a
560 <a
536 class="btn"
561 class="btn"
537 href="#"
562 href="#"
538 onclick="$('input[class=filediff-collapse-state]').prop('checked', true); return false">${_('Collapse All')}</a>
563 onclick="$('input[class=filediff-collapse-state]').prop('checked', true); return false">${_('Collapse All')}</a>
539 </div>
564 </div>
540 </div>
565 </div>
541 </div>
566 </div>
542 </%def>
567 </%def>
General Comments 0
You need to be logged in to leave comments. Login now