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