##// END OF EJS Templates
comments: fixed inline TODO comments resolution.
milka -
r4573:9c89fbd9 stable
parent child Browse files
Show More
@@ -1,746 +1,747 b''
1 // comments.less
1 // comments.less
2 // For use in RhodeCode applications;
2 // For use in RhodeCode applications;
3 // see style guide documentation for guidelines.
3 // see style guide documentation for guidelines.
4
4
5
5
6 // Comments
6 // Comments
7 @comment-outdated-opacity: 1.0;
7 @comment-outdated-opacity: 1.0;
8
8
9 .comments {
9 .comments {
10 width: 100%;
10 width: 100%;
11 }
11 }
12
12
13 .comments-heading {
13 .comments-heading {
14 margin-bottom: -1px;
14 margin-bottom: -1px;
15 background: @grey6;
15 background: @grey6;
16 display: block;
16 display: block;
17 padding: 10px 0px;
17 padding: 10px 0px;
18 font-size: 18px
18 font-size: 18px
19 }
19 }
20
20
21 #comment-tr-show {
21 #comment-tr-show {
22 padding: 5px 0;
22 padding: 5px 0;
23 }
23 }
24
24
25 tr.inline-comments div {
25 tr.inline-comments div {
26 max-width: 100%;
26 max-width: 100%;
27
27
28 p {
28 p {
29 white-space: normal;
29 white-space: normal;
30 }
30 }
31
31
32 code, pre, .code, dd {
32 code, pre, .code, dd {
33 overflow-x: auto;
33 overflow-x: auto;
34 width: 1062px;
34 width: 1062px;
35 }
35 }
36
36
37 dd {
37 dd {
38 width: auto;
38 width: auto;
39 }
39 }
40 }
40 }
41
41
42 #injected_page_comments {
42 #injected_page_comments {
43 .comment-previous-link,
43 .comment-previous-link,
44 .comment-next-link,
44 .comment-next-link,
45 .comment-links-divider {
45 .comment-links-divider {
46 display: none;
46 display: none;
47 }
47 }
48 }
48 }
49
49
50 .add-comment {
50 .add-comment {
51 margin-bottom: 10px;
51 margin-bottom: 10px;
52 }
52 }
53 .hide-comment-button .add-comment {
53 .hide-comment-button .add-comment {
54 display: none;
54 display: none;
55 }
55 }
56
56
57 .comment-bubble {
57 .comment-bubble {
58 color: @grey4;
58 color: @grey4;
59 margin-top: 4px;
59 margin-top: 4px;
60 margin-right: 30px;
60 margin-right: 30px;
61 visibility: hidden;
61 visibility: hidden;
62 }
62 }
63
63
64 .comment-draft {
64 .comment-draft {
65 float: left;
65 float: left;
66 margin-right: 10px;
66 margin-right: 10px;
67 font-weight: 400;
67 font-weight: 400;
68 color: @color-draft;
68 color: @color-draft;
69 }
69 }
70
70
71 .comment-new {
71 .comment-new {
72 float: left;
72 float: left;
73 margin-right: 10px;
73 margin-right: 10px;
74 font-weight: 400;
74 font-weight: 400;
75 color: @color-new;
75 color: @color-new;
76 }
76 }
77
77
78 .comment-label {
78 .comment-label {
79 float: left;
79 float: left;
80
80
81 padding: 0 8px 0 0;
81 padding: 0 8px 0 0;
82 min-height: 0;
82 min-height: 0;
83
83
84 text-align: center;
84 text-align: center;
85 font-size: 10px;
85 font-size: 10px;
86
86
87 font-family: @text-italic;
87 font-family: @text-italic;
88 font-style: italic;
88 font-style: italic;
89 background: #fff none;
89 background: #fff none;
90 color: @grey3;
90 color: @grey3;
91 white-space: nowrap;
91 white-space: nowrap;
92
92
93 text-transform: uppercase;
93 text-transform: uppercase;
94 min-width: 50px;
94 min-width: 50px;
95
95
96 &.todo {
96 &.todo {
97 color: @color5;
97 color: @color5;
98 font-style: italic;
98 font-style: italic;
99 font-weight: @text-bold-italic-weight;
99 font-weight: @text-bold-italic-weight;
100 font-family: @text-bold-italic;
100 font-family: @text-bold-italic;
101 }
101 }
102
102
103 .resolve {
103 .resolve {
104 cursor: pointer;
104 cursor: pointer;
105 text-decoration: underline;
105 text-decoration: underline;
106 }
106 }
107
107
108 .resolved {
108 .resolved {
109 text-decoration: line-through;
109 text-decoration: line-through;
110 color: @color1;
110 color: @color1;
111 }
111 }
112 .resolved a {
112 .resolved a {
113 text-decoration: line-through;
113 text-decoration: line-through;
114 color: @color1;
114 color: @color1;
115 }
115 }
116 .resolve-text {
116 .resolve-text {
117 color: @color1;
117 color: @color1;
118 margin: 2px 8px;
118 margin: 2px 8px;
119 font-family: @text-italic;
119 font-family: @text-italic;
120 font-style: italic;
120 font-style: italic;
121 }
121 }
122 }
122 }
123
123
124 .has-spacer-after {
124 .has-spacer-after {
125 &:after {
125 &:after {
126 content: ' | ';
126 content: ' | ';
127 color: @grey5;
127 color: @grey5;
128 }
128 }
129 }
129 }
130
130
131 .has-spacer-before {
131 .has-spacer-before {
132 &:before {
132 &:before {
133 content: ' | ';
133 content: ' | ';
134 color: @grey5;
134 color: @grey5;
135 }
135 }
136 }
136 }
137
137
138 .comment {
138 .comment {
139
139
140 &.comment-general {
140 &.comment-general {
141 border: 1px solid @grey5;
141 border: 1px solid @grey5;
142 padding: 5px 5px 5px 5px;
142 padding: 5px 5px 5px 5px;
143 }
143 }
144
144
145 margin: @padding 0;
145 margin: @padding 0;
146 padding: 4px 0 0 0;
146 padding: 4px 0 0 0;
147 line-height: 1em;
147 line-height: 1em;
148
148
149 .rc-user {
149 .rc-user {
150 min-width: 0;
150 min-width: 0;
151 margin: 0px .5em 0 0;
151 margin: 0px .5em 0 0;
152
152
153 .user {
153 .user {
154 display: inline;
154 display: inline;
155 }
155 }
156 }
156 }
157
157
158 .meta {
158 .meta {
159 position: relative;
159 position: relative;
160 width: 100%;
160 width: 100%;
161 border-bottom: 1px solid @grey5;
161 border-bottom: 1px solid @grey5;
162 margin: -5px 0px;
162 margin: -5px 0px;
163 line-height: 24px;
163 line-height: 24px;
164
164
165 &:hover .permalink {
165 &:hover .permalink {
166 visibility: visible;
166 visibility: visible;
167 color: @rcblue;
167 color: @rcblue;
168 }
168 }
169 }
169 }
170
170
171 .author,
171 .author,
172 .date {
172 .date {
173 display: inline;
173 display: inline;
174
174
175 &:after {
175 &:after {
176 content: ' | ';
176 content: ' | ';
177 color: @grey5;
177 color: @grey5;
178 }
178 }
179 }
179 }
180
180
181 .author-general img {
181 .author-general img {
182 top: 3px;
182 top: 3px;
183 }
183 }
184 .author-inline img {
184 .author-inline img {
185 top: 3px;
185 top: 3px;
186 }
186 }
187
187
188 .status-change,
188 .status-change,
189 .permalink,
189 .permalink,
190 .changeset-status-lbl {
190 .changeset-status-lbl {
191 display: inline;
191 display: inline;
192 }
192 }
193
193
194 .permalink {
194 .permalink {
195 visibility: hidden;
195 visibility: hidden;
196 }
196 }
197
197
198 .comment-links-divider {
198 .comment-links-divider {
199 display: inline;
199 display: inline;
200 }
200 }
201
201
202 .comment-links-block {
202 .comment-links-block {
203 float:right;
203 float:right;
204 text-align: right;
204 text-align: right;
205 min-width: 85px;
205 min-width: 85px;
206
206
207 [class^="icon-"]:before,
207 [class^="icon-"]:before,
208 [class*=" icon-"]:before {
208 [class*=" icon-"]:before {
209 margin-left: 0;
209 margin-left: 0;
210 margin-right: 0;
210 margin-right: 0;
211 }
211 }
212 }
212 }
213
213
214 .comment-previous-link {
214 .comment-previous-link {
215 display: inline-block;
215 display: inline-block;
216
216
217 .arrow_comment_link{
217 .arrow_comment_link{
218 cursor: pointer;
218 cursor: pointer;
219 i {
219 i {
220 font-size:10px;
220 font-size:10px;
221 }
221 }
222 }
222 }
223 .arrow_comment_link.disabled {
223 .arrow_comment_link.disabled {
224 cursor: default;
224 cursor: default;
225 color: @grey5;
225 color: @grey5;
226 }
226 }
227 }
227 }
228
228
229 .comment-next-link {
229 .comment-next-link {
230 display: inline-block;
230 display: inline-block;
231
231
232 .arrow_comment_link{
232 .arrow_comment_link{
233 cursor: pointer;
233 cursor: pointer;
234 i {
234 i {
235 font-size:10px;
235 font-size:10px;
236 }
236 }
237 }
237 }
238 .arrow_comment_link.disabled {
238 .arrow_comment_link.disabled {
239 cursor: default;
239 cursor: default;
240 color: @grey5;
240 color: @grey5;
241 }
241 }
242 }
242 }
243
243
244 .delete-comment {
244 .delete-comment {
245 display: inline-block;
245 display: inline-block;
246 color: @rcblue;
246 color: @rcblue;
247
247
248 &:hover {
248 &:hover {
249 cursor: pointer;
249 cursor: pointer;
250 }
250 }
251 }
251 }
252
252
253 .text {
253 .text {
254 clear: both;
254 clear: both;
255 .border-radius(@border-radius);
255 .border-radius(@border-radius);
256 .box-sizing(border-box);
256 .box-sizing(border-box);
257
257
258 .markdown-block p,
258 .markdown-block p,
259 .rst-block p {
259 .rst-block p {
260 margin: .5em 0 !important;
260 margin: .5em 0 !important;
261 // TODO: lisa: This is needed because of other rst !important rules :[
261 // TODO: lisa: This is needed because of other rst !important rules :[
262 }
262 }
263 }
263 }
264
264
265 .pr-version {
265 .pr-version {
266 display: inline-block;
266 display: inline-block;
267 }
267 }
268 .pr-version-inline {
268 .pr-version-inline {
269 display: inline-block;
269 display: inline-block;
270 }
270 }
271 .pr-version-num {
271 .pr-version-num {
272 font-size: 10px;
272 font-size: 10px;
273 }
273 }
274 }
274 }
275
275
276 @comment-padding: 5px;
276 @comment-padding: 5px;
277
277
278 .general-comments {
278 .general-comments {
279 .comment-outdated {
279 .comment-outdated {
280 opacity: @comment-outdated-opacity;
280 opacity: @comment-outdated-opacity;
281 }
281 }
282
282
283 .comment-outdated-label {
283 .comment-outdated-label {
284 color: @grey3;
284 color: @grey3;
285 padding-right: 4px;
285 padding-right: 4px;
286 }
286 }
287 }
287 }
288
288
289 .inline-comments {
289 .inline-comments {
290
290
291 .comment {
291 .comment {
292 margin: 0;
292 margin: 0;
293 }
293 }
294
294
295 .comment-outdated {
295 .comment-outdated {
296 opacity: @comment-outdated-opacity;
296 opacity: @comment-outdated-opacity;
297 }
297 }
298
298
299 .comment-outdated-label {
299 .comment-outdated-label {
300 color: @grey3;
300 color: @grey3;
301 padding-right: 4px;
301 padding-right: 4px;
302 }
302 }
303
303
304 .comment-inline {
304 .comment-inline {
305
305
306 &:first-child {
306 &:first-child {
307 margin: 4px 4px 0 4px;
307 margin: 4px 4px 0 4px;
308 border-top: 1px solid @grey5;
308 border-top: 1px solid @grey5;
309 border-bottom: 0 solid @grey5;
309 border-bottom: 0 solid @grey5;
310 border-left: 1px solid @grey5;
310 border-left: 1px solid @grey5;
311 border-right: 1px solid @grey5;
311 border-right: 1px solid @grey5;
312 .border-radius-top(4px);
312 .border-radius-top(4px);
313 }
313 }
314
314
315 &:only-child {
315 &:only-child {
316 margin: 4px 4px 0 4px;
316 margin: 4px 4px 0 4px;
317 border-top: 1px solid @grey5;
317 border-top: 1px solid @grey5;
318 border-bottom: 0 solid @grey5;
318 border-bottom: 0 solid @grey5;
319 border-left: 1px solid @grey5;
319 border-left: 1px solid @grey5;
320 border-right: 1px solid @grey5;
320 border-right: 1px solid @grey5;
321 .border-radius-top(4px);
321 .border-radius-top(4px);
322 }
322 }
323
323
324 background: white;
324 background: white;
325 padding: @comment-padding @comment-padding;
325 padding: @comment-padding @comment-padding;
326 margin: 0 4px 0 4px;
326 margin: 0 4px 0 4px;
327 border-top: 0 solid @grey5;
327 border-top: 0 solid @grey5;
328 border-bottom: 0 solid @grey5;
328 border-bottom: 0 solid @grey5;
329 border-left: 1px solid @grey5;
329 border-left: 1px solid @grey5;
330 border-right: 1px solid @grey5;
330 border-right: 1px solid @grey5;
331
331
332 .text {
332 .text {
333 border: none;
333 border: none;
334 }
334 }
335
335
336 .meta {
336 .meta {
337 border-bottom: 1px solid @grey6;
337 border-bottom: 1px solid @grey6;
338 margin: -5px 0px;
338 margin: -5px 0px;
339 line-height: 24px;
339 line-height: 24px;
340 }
340 }
341
341
342 }
342 }
343 .comment-selected {
343 .comment-selected {
344 border-left: 6px solid @comment-highlight-color;
344 border-left: 6px solid @comment-highlight-color;
345 }
345 }
346
346
347 .comment-inline-form-open {
347 .comment-inline-form-open {
348 display: block !important;
348 display: block !important;
349 }
349 }
350
350
351 .comment-inline-form {
351 .comment-inline-form {
352 display: none;
352 display: none;
353 }
353 }
354
354
355 .comment-inline-form-edit {
355 .comment-inline-form-edit {
356 padding: 0;
356 padding: 0;
357 margin: 0px 4px 2px 4px;
357 margin: 0px 4px 2px 4px;
358 }
358 }
359
359
360 .reply-thread-container {
360 .reply-thread-container {
361 display: table;
361 display: table;
362 width: 100%;
362 width: 100%;
363 padding: 0px 4px 4px 4px;
363 padding: 0px 4px 4px 4px;
364 }
364 }
365
365
366 .reply-thread-container-wrapper {
366 .reply-thread-container-wrapper {
367 margin: 0 4px 4px 4px;
367 margin: 0 4px 4px 4px;
368 border-top: 0 solid @grey5;
368 border-top: 0 solid @grey5;
369 border-bottom: 1px solid @grey5;
369 border-bottom: 1px solid @grey5;
370 border-left: 1px solid @grey5;
370 border-left: 1px solid @grey5;
371 border-right: 1px solid @grey5;
371 border-right: 1px solid @grey5;
372 .border-radius-bottom(4px);
372 .border-radius-bottom(4px);
373 }
373 }
374
374
375 .reply-thread-gravatar {
375 .reply-thread-gravatar {
376 display: table-cell;
376 display: table-cell;
377 width: 24px;
377 width: 24px;
378 height: 24px;
378 height: 24px;
379 padding-top: 10px;
379 padding-top: 10px;
380 padding-left: 10px;
380 padding-left: 10px;
381 background-color: #eeeeee;
381 background-color: #eeeeee;
382 vertical-align: top;
382 vertical-align: top;
383 }
383 }
384
384
385 .reply-thread-reply-button {
385 .reply-thread-reply-button {
386 display: table-cell;
386 display: table-cell;
387 width: 100%;
387 width: 100%;
388 height: 33px;
388 height: 33px;
389 padding: 3px 8px;
389 padding: 3px 8px;
390 margin-left: 8px;
390 margin-left: 8px;
391 background-color: #eeeeee;
391 background-color: #eeeeee;
392 }
392 }
393
393
394 .reply-thread-reply-button .cb-comment-add-button {
394 .reply-thread-reply-button .cb-comment-add-button {
395 border-radius: 4px;
395 border-radius: 4px;
396 width: 100%;
396 width: 100%;
397 padding: 6px 2px;
397 padding: 6px 2px;
398 text-align: left;
398 text-align: left;
399 cursor: text;
399 cursor: text;
400 color: @grey3;
400 color: @grey3;
401 }
401 }
402 .reply-thread-reply-button .cb-comment-add-button:hover {
402 .reply-thread-reply-button .cb-comment-add-button:hover {
403 background-color: white;
403 background-color: white;
404 color: @grey2;
404 color: @grey2;
405 }
405 }
406
406
407 .reply-thread-last {
407 .reply-thread-last {
408 display: table-cell;
408 display: table-cell;
409 width: 10px;
409 width: 10px;
410 }
410 }
411
411
412 /* Hide reply box when it's a first element,
412 /* Hide reply box when it's a first element,
413 can happen when drafts are saved but not shown to specific user,
413 can happen when drafts are saved but not shown to specific user,
414 or there are outdated comments hidden
414 or there are outdated comments hidden
415 */
415 */
416 .reply-thread-container-wrapper:first-child:not(.comment-form-active) {
416 .reply-thread-container-wrapper:first-child:not(.comment-form-active) {
417 display: none;
417 display: none;
418 }
418 }
419
419
420 .reply-thread-container-wrapper.comment-outdated {
420 .reply-thread-container-wrapper.comment-outdated {
421 display: none
421 display: none
422 }
422 }
423
423
424 /* hide add comment button when form is open */
424 /* hide add comment button when form is open */
425 .comment-inline-form-open ~ .cb-comment-add-button {
425 .comment-inline-form-open ~ .cb-comment-add-button {
426 display: none;
426 display: none;
427 }
427 }
428
428
429 /* hide add comment button when only comment is being deleted */
429 /* hide add comment button when only comment is being deleted */
430 .comment-deleting:first-child + .cb-comment-add-button {
430 .comment-deleting:first-child + .cb-comment-add-button {
431 display: none;
431 display: none;
432 }
432 }
433
433
434 /* hide add comment button when form but no comments */
434 /* hide add comment button when form but no comments */
435 .comment-inline-form:first-child + .cb-comment-add-button {
435 .comment-inline-form:first-child + .cb-comment-add-button {
436 display: none;
436 display: none;
437 }
437 }
438
438
439 }
439 }
440
440
441 .show-outdated-comments {
441 .show-outdated-comments {
442 display: inline;
442 display: inline;
443 color: @rcblue;
443 color: @rcblue;
444 }
444 }
445
445
446 // Comment Form
446 // Comment Form
447 div.comment-form {
447 div.comment-form {
448 margin-top: 20px;
448 margin-top: 20px;
449 }
449 }
450
450
451 .comment-form strong {
451 .comment-form strong {
452 display: block;
452 display: block;
453 margin-bottom: 15px;
453 margin-bottom: 15px;
454 }
454 }
455
455
456 .comment-form textarea {
456 .comment-form textarea {
457 width: 100%;
457 width: 100%;
458 height: 100px;
458 height: 100px;
459 font-family: @text-monospace;
459 font-family: @text-monospace;
460 }
460 }
461
461
462 form.comment-form {
462 form.comment-form {
463 margin-top: 10px;
463 margin-top: 10px;
464 margin-left: 10px;
464 margin-left: 10px;
465 }
465 }
466
466
467 .comment-inline-form .comment-block-ta,
467 .comment-inline-form .comment-block-ta,
468 .comment-form .comment-block-ta,
468 .comment-form .comment-block-ta,
469 .comment-form .preview-box {
469 .comment-form .preview-box {
470 .border-radius(@border-radius);
470 .border-radius(@border-radius);
471 .box-sizing(border-box);
471 .box-sizing(border-box);
472 background-color: white;
472 background-color: white;
473 }
473 }
474
474
475 .comment-form-submit {
475 .comment-form-submit {
476 margin-top: 5px;
476 margin-top: 5px;
477 margin-left: 525px;
477 margin-left: 525px;
478 }
478 }
479
479
480 .file-comments {
480 .file-comments {
481 display: none;
481 display: none;
482 }
482 }
483
483
484 .comment-form .preview-box.unloaded,
484 .comment-form .preview-box.unloaded,
485 .comment-inline-form .preview-box.unloaded {
485 .comment-inline-form .preview-box.unloaded {
486 height: 50px;
486 height: 50px;
487 text-align: center;
487 text-align: center;
488 padding: 20px;
488 padding: 20px;
489 background-color: white;
489 background-color: white;
490 }
490 }
491
491
492 .comment-footer {
492 .comment-footer {
493 display: table;
493 display: table;
494 width: 100%;
494 width: 100%;
495 height: 42px;
495 height: 42px;
496
496
497 .comment-status-box,
497 .comment-status-box,
498 .cancel-button {
498 .cancel-button {
499 display: inline-block;
499 display: inline-block;
500 }
500 }
501
501
502 .comment-status-box {
502 .comment-status-box {
503 margin-left: 10px;
503 margin-left: 10px;
504 }
504 }
505
505
506 .action-buttons {
506 .action-buttons {
507 display: table-cell;
507 display: table-cell;
508 padding: 5px 0 5px 2px;
508 padding: 5px 0 5px 2px;
509 }
509 }
510
510
511 .toolbar-text {
511 .toolbar-text {
512 height: 28px;
512 height: 28px;
513 display: table-cell;
513 display: table-cell;
514 vertical-align: baseline;
514 vertical-align: baseline;
515 font-size: 11px;
515 font-size: 11px;
516 color: @grey4;
516 color: @grey4;
517 text-align: right;
517 text-align: right;
518
518
519 a {
519 a {
520 color: @grey4;
520 color: @grey4;
521 }
521 }
522
522
523 }
523 }
524
524
525 .action-buttons-extra {
525 .action-buttons-extra {
526 display: inline-block;
526 display: inline-block;
527 }
527 }
528 }
528 }
529
529
530 .comment-form {
530 .comment-form {
531
531
532 .comment {
532 .comment {
533 margin-left: 10px;
533 margin-left: 10px;
534 }
534 }
535
535
536 .comment-help {
536 .comment-help {
537 color: @grey4;
537 color: @grey4;
538 padding: 5px 0 5px 0;
538 padding: 5px 0 5px 0;
539 }
539 }
540
540
541 .comment-title {
541 .comment-title {
542 padding: 5px 0 5px 0;
542 padding: 5px 0 5px 0;
543 }
543 }
544
544
545 .comment-button {
545 .comment-button {
546 display: inline-block;
546 display: inline-block;
547 }
547 }
548
548
549 .comment-button-input {
549 .comment-button-input {
550 margin-right: 0;
550 margin-right: 0;
551 }
551 }
552
552
553 #save_general {
553 #save_general {
554 margin-left: -6px;
554 margin-left: -6px;
555 }
555 }
556
556
557 }
557 }
558
558
559
559
560 .comment-form-login {
560 .comment-form-login {
561 .comment-help {
561 .comment-help {
562 padding: 0.7em; //same as the button
562 padding: 0.7em; //same as the button
563 }
563 }
564
564
565 div.clearfix {
565 div.clearfix {
566 clear: both;
566 clear: both;
567 width: 100%;
567 width: 100%;
568 display: block;
568 display: block;
569 }
569 }
570 }
570 }
571
571
572 .comment-version-select {
572 .comment-version-select {
573 margin: 0px;
573 margin: 0px;
574 border-radius: inherit;
574 border-radius: inherit;
575 border-color: @grey6;
575 border-color: @grey6;
576 height: 20px;
576 height: 20px;
577 }
577 }
578
578
579 .comment-type {
579 .comment-type {
580 margin: 0px;
580 margin: 0px;
581 border-radius: inherit;
581 border-radius: inherit;
582 border-color: @grey6;
582 border-color: @grey6;
583 }
583 }
584
584
585 .preview-box {
585 .preview-box {
586 min-height: 105px;
586 min-height: 105px;
587 margin-bottom: 15px;
587 margin-bottom: 15px;
588 background-color: white;
588 background-color: white;
589 .border-radius(@border-radius);
589 .border-radius(@border-radius);
590 .box-sizing(border-box);
590 .box-sizing(border-box);
591 }
591 }
592
592
593 .add-another-button {
593 .add-another-button {
594 margin-left: 10px;
594 margin-left: 10px;
595 margin-top: 10px;
595 margin-top: 10px;
596 margin-bottom: 10px;
596 margin-bottom: 10px;
597 }
597 }
598
598
599 .comment .buttons {
599 .comment .buttons {
600 float: right;
600 float: right;
601 margin: -1px 0px 0px 0px;
601 margin: -1px 0px 0px 0px;
602 }
602 }
603
603
604 // Inline Comment Form
604 // Inline Comment Form
605 .injected_diff .comment-inline-form,
605 .injected_diff .comment-inline-form,
606 .comment-inline-form {
606 .comment-inline-form {
607 background-color: white;
607 background-color: white;
608 margin-top: 4px;
608 margin-top: 4px;
609 margin-bottom: 10px;
609 margin-bottom: 10px;
610 }
610 }
611
611
612 .inline-form {
612 .inline-form {
613 padding: 10px 7px;
613 padding: 10px 7px;
614 }
614 }
615
615
616 .inline-form div {
616 .inline-form div {
617 max-width: 100%;
617 max-width: 100%;
618 }
618 }
619
619
620 .overlay {
620 .overlay {
621 display: none;
621 display: none;
622 position: absolute;
622 position: absolute;
623 width: 100%;
623 width: 100%;
624 text-align: center;
624 text-align: center;
625 vertical-align: middle;
625 vertical-align: middle;
626 font-size: 16px;
626 font-size: 16px;
627 background: none repeat scroll 0 0 white;
627 background: none repeat scroll 0 0 white;
628
628
629 &.submitting {
629 &.submitting {
630 display: block;
630 display: block;
631 opacity: 0.5;
631 opacity: 0.5;
632 z-index: 100;
632 z-index: 100;
633 }
633 }
634 }
634 }
635 .comment-inline-form .overlay.submitting .overlay-text {
635 .comment-inline-form .overlay.submitting .overlay-text {
636 margin-top: 5%;
636 margin-top: 5%;
637 }
637 }
638
638
639 .comment-inline-form .clearfix,
639 .comment-inline-form .clearfix,
640 .comment-form .clearfix {
640 .comment-form .clearfix {
641 .border-radius(@border-radius);
641 .border-radius(@border-radius);
642 margin: 0px;
642 margin: 0px;
643 }
643 }
644
644
645
645
646 .hide-inline-form-button {
646 .hide-inline-form-button {
647 margin-left: 5px;
647 margin-left: 5px;
648 }
648 }
649 .comment-button .hide-inline-form {
649 .comment-button .hide-inline-form {
650 background: white;
650 background: white;
651 }
651 }
652
652
653 .comment-area {
653 .comment-area {
654 padding: 6px 8px;
654 padding: 6px 8px;
655 border: 1px solid @grey5;
655 border: 1px solid @grey5;
656 .border-radius(@border-radius);
656 .border-radius(@border-radius);
657
657
658 .resolve-action {
658 .resolve-action {
659 padding: 1px 0px 0px 6px;
659 padding: 1px 0px 0px 6px;
660 list-style: none;
660 }
661 }
661
662
662 }
663 }
663
664
664 comment-area-text {
665 comment-area-text {
665 color: @grey3;
666 color: @grey3;
666 }
667 }
667
668
668 .comment-area-header {
669 .comment-area-header {
669 height: 35px;
670 height: 35px;
670 border-bottom: 1px solid @grey5;
671 border-bottom: 1px solid @grey5;
671 }
672 }
672
673
673 .comment-area-header .nav-links {
674 .comment-area-header .nav-links {
674 display: flex;
675 display: flex;
675 flex-flow: row wrap;
676 flex-flow: row wrap;
676 -webkit-flex-flow: row wrap;
677 -webkit-flex-flow: row wrap;
677 width: 100%;
678 width: 100%;
678 border: none;
679 border: none;
679 }
680 }
680
681
681 .comment-area-footer {
682 .comment-area-footer {
682 min-height: 30px;
683 min-height: 30px;
683 }
684 }
684
685
685 .comment-footer .toolbar {
686 .comment-footer .toolbar {
686
687
687 }
688 }
688
689
689 .comment-attachment-uploader {
690 .comment-attachment-uploader {
690 border: 1px dashed white;
691 border: 1px dashed white;
691 border-radius: @border-radius;
692 border-radius: @border-radius;
692 margin-top: -10px;
693 margin-top: -10px;
693 line-height: 30px;
694 line-height: 30px;
694 &.dz-drag-hover {
695 &.dz-drag-hover {
695 border-color: @grey3;
696 border-color: @grey3;
696 }
697 }
697
698
698 .dz-error-message {
699 .dz-error-message {
699 padding-top: 0;
700 padding-top: 0;
700 }
701 }
701 }
702 }
702
703
703 .comment-attachment-text {
704 .comment-attachment-text {
704 clear: both;
705 clear: both;
705 font-size: 11px;
706 font-size: 11px;
706 color: #8F8F8F;
707 color: #8F8F8F;
707 width: 100%;
708 width: 100%;
708 .pick-attachment {
709 .pick-attachment {
709 color: #8F8F8F;
710 color: #8F8F8F;
710 }
711 }
711 .pick-attachment:hover {
712 .pick-attachment:hover {
712 color: @rcblue;
713 color: @rcblue;
713 }
714 }
714 }
715 }
715
716
716 .nav-links {
717 .nav-links {
717 padding: 0;
718 padding: 0;
718 margin: 0;
719 margin: 0;
719 list-style: none;
720 list-style: none;
720 height: auto;
721 height: auto;
721 border-bottom: 1px solid @grey5;
722 border-bottom: 1px solid @grey5;
722 }
723 }
723 .nav-links li {
724 .nav-links li {
724 display: inline-block;
725 display: inline-block;
725 list-style-type: none;
726 list-style-type: none;
726 }
727 }
727
728
728 .nav-links li a.disabled {
729 .nav-links li a.disabled {
729 cursor: not-allowed;
730 cursor: not-allowed;
730 }
731 }
731
732
732 .nav-links li.active a {
733 .nav-links li.active a {
733 border-bottom: 2px solid @rcblue;
734 border-bottom: 2px solid @rcblue;
734 color: #000;
735 color: #000;
735 font-weight: 600;
736 font-weight: 600;
736 }
737 }
737 .nav-links li a {
738 .nav-links li a {
738 display: inline-block;
739 display: inline-block;
739 padding: 0px 10px 5px 10px;
740 padding: 0px 10px 5px 10px;
740 margin-bottom: -1px;
741 margin-bottom: -1px;
741 font-size: 14px;
742 font-size: 14px;
742 line-height: 28px;
743 line-height: 28px;
743 color: #8f8f8f;
744 color: #8f8f8f;
744 border-bottom: 2px solid transparent;
745 border-bottom: 2px solid transparent;
745 }
746 }
746
747
@@ -1,1501 +1,1502 b''
1 // # Copyright (C) 2010-2020 RhodeCode GmbH
1 // # Copyright (C) 2010-2020 RhodeCode GmbH
2 // #
2 // #
3 // # This program is free software: you can redistribute it and/or modify
3 // # This program is free software: you can redistribute it and/or modify
4 // # it under the terms of the GNU Affero General Public License, version 3
4 // # it under the terms of the GNU Affero General Public License, version 3
5 // # (only), as published by the Free Software Foundation.
5 // # (only), as published by the Free Software Foundation.
6 // #
6 // #
7 // # This program is distributed in the hope that it will be useful,
7 // # This program is distributed in the hope that it will be useful,
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // # GNU General Public License for more details.
10 // # GNU General Public License for more details.
11 // #
11 // #
12 // # You should have received a copy of the GNU Affero General Public License
12 // # You should have received a copy of the GNU Affero General Public License
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 // #
14 // #
15 // # This program is dual-licensed. If you wish to learn more about the
15 // # This program is dual-licensed. If you wish to learn more about the
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 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 var linkifyComments = function(comments) {
28 var linkifyComments = function(comments) {
29 var firstCommentId = null;
29 var firstCommentId = null;
30 if (comments) {
30 if (comments) {
31 firstCommentId = $(comments[0]).data('comment-id');
31 firstCommentId = $(comments[0]).data('comment-id');
32 }
32 }
33
33
34 if (firstCommentId){
34 if (firstCommentId){
35 $('#inline-comments-counter').attr('href', '#comment-' + firstCommentId);
35 $('#inline-comments-counter').attr('href', '#comment-' + firstCommentId);
36 }
36 }
37 };
37 };
38
38
39 var bindToggleButtons = function() {
39 var bindToggleButtons = function() {
40 $('.comment-toggle').on('click', function() {
40 $('.comment-toggle').on('click', function() {
41 $(this).parent().nextUntil('tr.line').toggle('inline-comments');
41 $(this).parent().nextUntil('tr.line').toggle('inline-comments');
42 });
42 });
43 };
43 };
44
44
45
45
46
46
47 var _submitAjaxPOST = function(url, postData, successHandler, failHandler) {
47 var _submitAjaxPOST = function(url, postData, successHandler, failHandler) {
48 failHandler = failHandler || function() {};
48 failHandler = failHandler || function() {};
49 postData = toQueryString(postData);
49 postData = toQueryString(postData);
50 var request = $.ajax({
50 var request = $.ajax({
51 url: url,
51 url: url,
52 type: 'POST',
52 type: 'POST',
53 data: postData,
53 data: postData,
54 headers: {'X-PARTIAL-XHR': true}
54 headers: {'X-PARTIAL-XHR': true}
55 })
55 })
56 .done(function (data) {
56 .done(function (data) {
57 successHandler(data);
57 successHandler(data);
58 })
58 })
59 .fail(function (data, textStatus, errorThrown) {
59 .fail(function (data, textStatus, errorThrown) {
60 failHandler(data, textStatus, errorThrown)
60 failHandler(data, textStatus, errorThrown)
61 });
61 });
62 return request;
62 return request;
63 };
63 };
64
64
65
65
66
66
67
67
68 /* Comment form for main and inline comments */
68 /* Comment form for main and inline comments */
69 (function(mod) {
69 (function(mod) {
70
70
71 if (typeof exports == "object" && typeof module == "object") {
71 if (typeof exports == "object" && typeof module == "object") {
72 // CommonJS
72 // CommonJS
73 module.exports = mod();
73 module.exports = mod();
74 }
74 }
75 else {
75 else {
76 // Plain browser env
76 // Plain browser env
77 (this || window).CommentForm = mod();
77 (this || window).CommentForm = mod();
78 }
78 }
79
79
80 })(function() {
80 })(function() {
81 "use strict";
81 "use strict";
82
82
83 function CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId, edit, comment_id) {
83 function CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId, edit, comment_id) {
84
84
85 if (!(this instanceof CommentForm)) {
85 if (!(this instanceof CommentForm)) {
86 return new CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId, edit, comment_id);
86 return new CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId, edit, comment_id);
87 }
87 }
88
88
89 // bind the element instance to our Form
89 // bind the element instance to our Form
90 $(formElement).get(0).CommentForm = this;
90 $(formElement).get(0).CommentForm = this;
91
91
92 this.withLineNo = function(selector) {
92 this.withLineNo = function(selector) {
93 var lineNo = this.lineNo;
93 var lineNo = this.lineNo;
94 if (lineNo === undefined) {
94 if (lineNo === undefined) {
95 return selector
95 return selector
96 } else {
96 } else {
97 return selector + '_' + lineNo;
97 return selector + '_' + lineNo;
98 }
98 }
99 };
99 };
100
100
101 this.commitId = commitId;
101 this.commitId = commitId;
102 this.pullRequestId = pullRequestId;
102 this.pullRequestId = pullRequestId;
103 this.lineNo = lineNo;
103 this.lineNo = lineNo;
104 this.initAutocompleteActions = initAutocompleteActions;
104 this.initAutocompleteActions = initAutocompleteActions;
105
105
106 this.previewButton = this.withLineNo('#preview-btn');
106 this.previewButton = this.withLineNo('#preview-btn');
107 this.previewContainer = this.withLineNo('#preview-container');
107 this.previewContainer = this.withLineNo('#preview-container');
108
108
109 this.previewBoxSelector = this.withLineNo('#preview-box');
109 this.previewBoxSelector = this.withLineNo('#preview-box');
110
110
111 this.editButton = this.withLineNo('#edit-btn');
111 this.editButton = this.withLineNo('#edit-btn');
112 this.editContainer = this.withLineNo('#edit-container');
112 this.editContainer = this.withLineNo('#edit-container');
113 this.cancelButton = this.withLineNo('#cancel-btn');
113 this.cancelButton = this.withLineNo('#cancel-btn');
114 this.commentType = this.withLineNo('#comment_type');
114 this.commentType = this.withLineNo('#comment_type');
115
115
116 this.resolvesId = null;
116 this.resolvesId = null;
117 this.resolvesActionId = null;
117 this.resolvesActionId = null;
118
118
119 this.closesPr = '#close_pull_request';
119 this.closesPr = '#close_pull_request';
120
120
121 this.cmBox = this.withLineNo('#text');
121 this.cmBox = this.withLineNo('#text');
122 this.cm = initCommentBoxCodeMirror(this, this.cmBox, this.initAutocompleteActions);
122 this.cm = initCommentBoxCodeMirror(this, this.cmBox, this.initAutocompleteActions);
123
123
124 this.statusChange = this.withLineNo('#change_status');
124 this.statusChange = this.withLineNo('#change_status');
125
125
126 this.submitForm = formElement;
126 this.submitForm = formElement;
127
127
128 this.submitButton = $(this.submitForm).find('.submit-comment-action');
128 this.submitButton = $(this.submitForm).find('.submit-comment-action');
129 this.submitButtonText = this.submitButton.val();
129 this.submitButtonText = this.submitButton.val();
130
130
131 this.submitDraftButton = $(this.submitForm).find('.submit-draft-action');
131 this.submitDraftButton = $(this.submitForm).find('.submit-draft-action');
132 this.submitDraftButtonText = this.submitDraftButton.val();
132 this.submitDraftButtonText = this.submitDraftButton.val();
133
133
134 this.previewUrl = pyroutes.url('repo_commit_comment_preview',
134 this.previewUrl = pyroutes.url('repo_commit_comment_preview',
135 {'repo_name': templateContext.repo_name,
135 {'repo_name': templateContext.repo_name,
136 'commit_id': templateContext.commit_data.commit_id});
136 'commit_id': templateContext.commit_data.commit_id});
137
137
138 if (edit){
138 if (edit){
139 this.submitDraftButton.hide();
139 this.submitDraftButton.hide();
140 this.submitButtonText = _gettext('Update Comment');
140 this.submitButtonText = _gettext('Update Comment');
141 $(this.commentType).prop('disabled', true);
141 $(this.commentType).prop('disabled', true);
142 $(this.commentType).addClass('disabled');
142 $(this.commentType).addClass('disabled');
143 var editInfo =
143 var editInfo =
144 '';
144 '';
145 $(editInfo).insertBefore($(this.editButton).parent());
145 $(editInfo).insertBefore($(this.editButton).parent());
146 }
146 }
147
147
148 if (resolvesCommentId){
148 if (resolvesCommentId){
149 this.resolvesId = '#resolve_comment_{0}'.format(resolvesCommentId);
149 this.resolvesId = '#resolve_comment_{0}'.format(resolvesCommentId);
150 this.resolvesActionId = '#resolve_comment_action_{0}'.format(resolvesCommentId);
150 this.resolvesActionId = '#resolve_comment_action_{0}'.format(resolvesCommentId);
151 $(this.commentType).prop('disabled', true);
151 $(this.commentType).prop('disabled', true);
152 $(this.commentType).addClass('disabled');
152 $(this.commentType).addClass('disabled');
153
153
154 // disable select
154 // disable select
155 setTimeout(function() {
155 setTimeout(function() {
156 $(self.statusChange).select2('readonly', true);
156 $(self.statusChange).select2('readonly', true);
157 }, 10);
157 }, 10);
158
158
159 var resolvedInfo = (
159 var resolvedInfo = (
160 '<li class="resolve-action">' +
160 '<li class="resolve-action">' +
161 '<input type="hidden" id="resolve_comment_{0}" name="resolve_comment_{0}" value="{0}">' +
161 '<input type="hidden" id="resolve_comment_{0}" name="resolve_comment_{0}" value="{0}">' +
162 '<button id="resolve_comment_action_{0}" class="resolve-text btn btn-sm" onclick="return Rhodecode.comments.submitResolution({0})">{1} #{0}</button>' +
162 '<button id="resolve_comment_action_{0}" class="resolve-text btn btn-sm" onclick="return Rhodecode.comments.submitResolution({0})">{1} #{0}</button>' +
163 '</li>'
163 '</li>'
164 ).format(resolvesCommentId, _gettext('resolve comment'));
164 ).format(resolvesCommentId, _gettext('resolve comment'));
165 $(resolvedInfo).insertAfter($(this.commentType).parent());
165 $(resolvedInfo).insertAfter($(this.commentType).parent());
166 }
166 }
167
167
168 // based on commitId, or pullRequestId decide where do we submit
168 // based on commitId, or pullRequestId decide where do we submit
169 // out data
169 // out data
170 if (this.commitId){
170 if (this.commitId){
171 var pyurl = 'repo_commit_comment_create';
171 var pyurl = 'repo_commit_comment_create';
172 if(edit){
172 if(edit){
173 pyurl = 'repo_commit_comment_edit';
173 pyurl = 'repo_commit_comment_edit';
174 }
174 }
175 this.submitUrl = pyroutes.url(pyurl,
175 this.submitUrl = pyroutes.url(pyurl,
176 {'repo_name': templateContext.repo_name,
176 {'repo_name': templateContext.repo_name,
177 'commit_id': this.commitId,
177 'commit_id': this.commitId,
178 'comment_id': comment_id});
178 'comment_id': comment_id});
179 this.selfUrl = pyroutes.url('repo_commit',
179 this.selfUrl = pyroutes.url('repo_commit',
180 {'repo_name': templateContext.repo_name,
180 {'repo_name': templateContext.repo_name,
181 'commit_id': this.commitId});
181 'commit_id': this.commitId});
182
182
183 } else if (this.pullRequestId) {
183 } else if (this.pullRequestId) {
184 var pyurl = 'pullrequest_comment_create';
184 var pyurl = 'pullrequest_comment_create';
185 if(edit){
185 if(edit){
186 pyurl = 'pullrequest_comment_edit';
186 pyurl = 'pullrequest_comment_edit';
187 }
187 }
188 this.submitUrl = pyroutes.url(pyurl,
188 this.submitUrl = pyroutes.url(pyurl,
189 {'repo_name': templateContext.repo_name,
189 {'repo_name': templateContext.repo_name,
190 'pull_request_id': this.pullRequestId,
190 'pull_request_id': this.pullRequestId,
191 'comment_id': comment_id});
191 'comment_id': comment_id});
192 this.selfUrl = pyroutes.url('pullrequest_show',
192 this.selfUrl = pyroutes.url('pullrequest_show',
193 {'repo_name': templateContext.repo_name,
193 {'repo_name': templateContext.repo_name,
194 'pull_request_id': this.pullRequestId});
194 'pull_request_id': this.pullRequestId});
195
195
196 } else {
196 } else {
197 throw new Error(
197 throw new Error(
198 'CommentForm requires pullRequestId, or commitId to be specified.')
198 'CommentForm requires pullRequestId, or commitId to be specified.')
199 }
199 }
200
200
201 // FUNCTIONS and helpers
201 // FUNCTIONS and helpers
202 var self = this;
202 var self = this;
203
203
204 this.isInline = function(){
204 this.isInline = function(){
205 return this.lineNo && this.lineNo != 'general';
205 return this.lineNo && this.lineNo != 'general';
206 };
206 };
207
207
208 this.getCmInstance = function(){
208 this.getCmInstance = function(){
209 return this.cm
209 return this.cm
210 };
210 };
211
211
212 this.setPlaceholder = function(placeholder) {
212 this.setPlaceholder = function(placeholder) {
213 var cm = this.getCmInstance();
213 var cm = this.getCmInstance();
214 if (cm){
214 if (cm){
215 cm.setOption('placeholder', placeholder);
215 cm.setOption('placeholder', placeholder);
216 }
216 }
217 };
217 };
218
218
219 this.getCommentStatus = function() {
219 this.getCommentStatus = function() {
220 return $(this.submitForm).find(this.statusChange).val();
220 return $(this.submitForm).find(this.statusChange).val();
221 };
221 };
222
222
223 this.getCommentType = function() {
223 this.getCommentType = function() {
224 return $(this.submitForm).find(this.commentType).val();
224 return $(this.submitForm).find(this.commentType).val();
225 };
225 };
226
226
227 this.getDraftState = function () {
227 this.getDraftState = function () {
228 var submitterElem = $(this.submitForm).find('input[type="submit"].submitter');
228 var submitterElem = $(this.submitForm).find('input[type="submit"].submitter');
229 var data = $(submitterElem).data('isDraft');
229 var data = $(submitterElem).data('isDraft');
230 return data
230 return data
231 }
231 }
232
232
233 this.getResolvesId = function() {
233 this.getResolvesId = function() {
234 return $(this.submitForm).find(this.resolvesId).val() || null;
234 return $(this.submitForm).find(this.resolvesId).val() || null;
235 };
235 };
236
236
237 this.getClosePr = function() {
237 this.getClosePr = function() {
238 return $(this.submitForm).find(this.closesPr).val() || null;
238 return $(this.submitForm).find(this.closesPr).val() || null;
239 };
239 };
240
240
241 this.markCommentResolved = function(resolvedCommentId){
241 this.markCommentResolved = function(resolvedCommentId){
242 $('#comment-label-{0}'.format(resolvedCommentId)).find('.resolved').show();
242 $('#comment-label-{0}'.format(resolvedCommentId)).find('.resolved').show();
243 $('#comment-label-{0}'.format(resolvedCommentId)).find('.resolve').hide();
243 $('#comment-label-{0}'.format(resolvedCommentId)).find('.resolve').hide();
244 };
244 };
245
245
246 this.isAllowedToSubmit = function() {
246 this.isAllowedToSubmit = function() {
247 var commentDisabled = $(this.submitButton).prop('disabled');
247 var commentDisabled = $(this.submitButton).prop('disabled');
248 var draftDisabled = $(this.submitDraftButton).prop('disabled');
248 var draftDisabled = $(this.submitDraftButton).prop('disabled');
249 return !commentDisabled && !draftDisabled;
249 return !commentDisabled && !draftDisabled;
250 };
250 };
251
251
252 this.initStatusChangeSelector = function(){
252 this.initStatusChangeSelector = function(){
253 var formatChangeStatus = function(state, escapeMarkup) {
253 var formatChangeStatus = function(state, escapeMarkup) {
254 var originalOption = state.element;
254 var originalOption = state.element;
255 var tmpl = '<i class="icon-circle review-status-{0}"></i><span>{1}</span>'.format($(originalOption).data('status'), escapeMarkup(state.text));
255 var tmpl = '<i class="icon-circle review-status-{0}"></i><span>{1}</span>'.format($(originalOption).data('status'), escapeMarkup(state.text));
256 return tmpl
256 return tmpl
257 };
257 };
258 var formatResult = function(result, container, query, escapeMarkup) {
258 var formatResult = function(result, container, query, escapeMarkup) {
259 return formatChangeStatus(result, escapeMarkup);
259 return formatChangeStatus(result, escapeMarkup);
260 };
260 };
261
261
262 var formatSelection = function(data, container, escapeMarkup) {
262 var formatSelection = function(data, container, escapeMarkup) {
263 return formatChangeStatus(data, escapeMarkup);
263 return formatChangeStatus(data, escapeMarkup);
264 };
264 };
265
265
266 $(this.submitForm).find(this.statusChange).select2({
266 $(this.submitForm).find(this.statusChange).select2({
267 placeholder: _gettext('Status Review'),
267 placeholder: _gettext('Status Review'),
268 formatResult: formatResult,
268 formatResult: formatResult,
269 formatSelection: formatSelection,
269 formatSelection: formatSelection,
270 containerCssClass: "drop-menu status_box_menu",
270 containerCssClass: "drop-menu status_box_menu",
271 dropdownCssClass: "drop-menu-dropdown",
271 dropdownCssClass: "drop-menu-dropdown",
272 dropdownAutoWidth: true,
272 dropdownAutoWidth: true,
273 minimumResultsForSearch: -1
273 minimumResultsForSearch: -1
274 });
274 });
275
275
276 $(this.submitForm).find(this.statusChange).on('change', function() {
276 $(this.submitForm).find(this.statusChange).on('change', function() {
277 var status = self.getCommentStatus();
277 var status = self.getCommentStatus();
278
278
279 if (status && !self.isInline()) {
279 if (status && !self.isInline()) {
280 $(self.submitButton).prop('disabled', false);
280 $(self.submitButton).prop('disabled', false);
281 $(self.submitDraftButton).prop('disabled', false);
281 $(self.submitDraftButton).prop('disabled', false);
282 }
282 }
283
283
284 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
284 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
285 self.setPlaceholder(placeholderText)
285 self.setPlaceholder(placeholderText)
286 })
286 })
287 };
287 };
288
288
289 // reset the comment form into it's original state
289 // reset the comment form into it's original state
290 this.resetCommentFormState = function(content) {
290 this.resetCommentFormState = function(content) {
291 content = content || '';
291 content = content || '';
292
292
293 $(this.editContainer).show();
293 $(this.editContainer).show();
294 $(this.editButton).parent().addClass('active');
294 $(this.editButton).parent().addClass('active');
295
295
296 $(this.previewContainer).hide();
296 $(this.previewContainer).hide();
297 $(this.previewButton).parent().removeClass('active');
297 $(this.previewButton).parent().removeClass('active');
298
298
299 this.setActionButtonsDisabled(true);
299 this.setActionButtonsDisabled(true);
300 self.cm.setValue(content);
300 self.cm.setValue(content);
301 self.cm.setOption("readOnly", false);
301 self.cm.setOption("readOnly", false);
302
302
303 if (this.resolvesId) {
303 if (this.resolvesId) {
304 // destroy the resolve action
304 // destroy the resolve action
305 $(this.resolvesId).parent().remove();
305 $(this.resolvesId).parent().remove();
306 }
306 }
307 // reset closingPR flag
307 // reset closingPR flag
308 $('.close-pr-input').remove();
308 $('.close-pr-input').remove();
309
309
310 $(this.statusChange).select2('readonly', false);
310 $(this.statusChange).select2('readonly', false);
311 };
311 };
312
312
313 this.globalSubmitSuccessCallback = function(comment){
313 this.globalSubmitSuccessCallback = function(comment){
314 // default behaviour is to call GLOBAL hook, if it's registered.
314 // default behaviour is to call GLOBAL hook, if it's registered.
315 if (window.commentFormGlobalSubmitSuccessCallback !== undefined){
315 if (window.commentFormGlobalSubmitSuccessCallback !== undefined){
316 commentFormGlobalSubmitSuccessCallback(comment);
316 commentFormGlobalSubmitSuccessCallback(comment);
317 }
317 }
318 };
318 };
319
319
320 this.submitAjaxPOST = function(url, postData, successHandler, failHandler) {
320 this.submitAjaxPOST = function(url, postData, successHandler, failHandler) {
321 return _submitAjaxPOST(url, postData, successHandler, failHandler);
321 return _submitAjaxPOST(url, postData, successHandler, failHandler);
322 };
322 };
323
323
324 // overwrite a submitHandler, we need to do it for inline comments
324 // overwrite a submitHandler, we need to do it for inline comments
325 this.setHandleFormSubmit = function(callback) {
325 this.setHandleFormSubmit = function(callback) {
326 this.handleFormSubmit = callback;
326 this.handleFormSubmit = callback;
327 };
327 };
328
328
329 // overwrite a submitSuccessHandler
329 // overwrite a submitSuccessHandler
330 this.setGlobalSubmitSuccessCallback = function(callback) {
330 this.setGlobalSubmitSuccessCallback = function(callback) {
331 this.globalSubmitSuccessCallback = callback;
331 this.globalSubmitSuccessCallback = callback;
332 };
332 };
333
333
334 // default handler for for submit for main comments
334 // default handler for for submit for main comments
335 this.handleFormSubmit = function() {
335 this.handleFormSubmit = function() {
336 var text = self.cm.getValue();
336 var text = self.cm.getValue();
337 var status = self.getCommentStatus();
337 var status = self.getCommentStatus();
338 var commentType = self.getCommentType();
338 var commentType = self.getCommentType();
339 var isDraft = self.getDraftState();
339 var isDraft = self.getDraftState();
340 var resolvesCommentId = self.getResolvesId();
340 var resolvesCommentId = self.getResolvesId();
341 var closePullRequest = self.getClosePr();
341 var closePullRequest = self.getClosePr();
342
342
343 if (text === "" && !status) {
343 if (text === "" && !status) {
344 return;
344 return;
345 }
345 }
346
346
347 var excludeCancelBtn = false;
347 var excludeCancelBtn = false;
348 var submitEvent = true;
348 var submitEvent = true;
349 self.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
349 self.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
350 self.cm.setOption("readOnly", true);
350 self.cm.setOption("readOnly", true);
351
351
352 var postData = {
352 var postData = {
353 'text': text,
353 'text': text,
354 'changeset_status': status,
354 'changeset_status': status,
355 'comment_type': commentType,
355 'comment_type': commentType,
356 'csrf_token': CSRF_TOKEN
356 'csrf_token': CSRF_TOKEN
357 };
357 };
358
358
359 if (resolvesCommentId) {
359 if (resolvesCommentId) {
360 postData['resolves_comment_id'] = resolvesCommentId;
360 postData['resolves_comment_id'] = resolvesCommentId;
361 }
361 }
362
362
363 if (closePullRequest) {
363 if (closePullRequest) {
364 postData['close_pull_request'] = true;
364 postData['close_pull_request'] = true;
365 }
365 }
366
366
367 // submitSuccess for general comments
367 // submitSuccess for general comments
368 var submitSuccessCallback = function(json_data) {
368 var submitSuccessCallback = function(json_data) {
369 // reload page if we change status for single commit.
369 // reload page if we change status for single commit.
370 if (status && self.commitId) {
370 if (status && self.commitId) {
371 location.reload(true);
371 location.reload(true);
372 } else {
372 } else {
373 // inject newly created comments, json_data is {<comment_id>: {}}
373 // inject newly created comments, json_data is {<comment_id>: {}}
374 self.attachGeneralComment(json_data)
374 self.attachGeneralComment(json_data)
375
375
376 self.resetCommentFormState();
376 self.resetCommentFormState();
377 timeagoActivate();
377 timeagoActivate();
378 tooltipActivate();
378 tooltipActivate();
379
379
380 // mark visually which comment was resolved
380 // mark visually which comment was resolved
381 if (resolvesCommentId) {
381 if (resolvesCommentId) {
382 self.markCommentResolved(resolvesCommentId);
382 self.markCommentResolved(resolvesCommentId);
383 }
383 }
384 }
384 }
385
385
386 // run global callback on submit
386 // run global callback on submit
387 self.globalSubmitSuccessCallback({draft: isDraft, comment_id: comment_id});
387 self.globalSubmitSuccessCallback({draft: isDraft, comment_id: comment_id});
388
388
389 };
389 };
390 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
390 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
391 var prefix = "Error while submitting comment.\n"
391 var prefix = "Error while submitting comment.\n"
392 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
392 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
393 ajaxErrorSwal(message);
393 ajaxErrorSwal(message);
394 self.resetCommentFormState(text);
394 self.resetCommentFormState(text);
395 };
395 };
396 self.submitAjaxPOST(
396 self.submitAjaxPOST(
397 self.submitUrl, postData, submitSuccessCallback, submitFailCallback);
397 self.submitUrl, postData, submitSuccessCallback, submitFailCallback);
398 };
398 };
399
399
400 this.previewSuccessCallback = function(o) {
400 this.previewSuccessCallback = function(o) {
401 $(self.previewBoxSelector).html(o);
401 $(self.previewBoxSelector).html(o);
402 $(self.previewBoxSelector).removeClass('unloaded');
402 $(self.previewBoxSelector).removeClass('unloaded');
403
403
404 // swap buttons, making preview active
404 // swap buttons, making preview active
405 $(self.previewButton).parent().addClass('active');
405 $(self.previewButton).parent().addClass('active');
406 $(self.editButton).parent().removeClass('active');
406 $(self.editButton).parent().removeClass('active');
407
407
408 // unlock buttons
408 // unlock buttons
409 self.setActionButtonsDisabled(false);
409 self.setActionButtonsDisabled(false);
410 };
410 };
411
411
412 this.setActionButtonsDisabled = function(state, excludeCancelBtn, submitEvent) {
412 this.setActionButtonsDisabled = function(state, excludeCancelBtn, submitEvent) {
413 excludeCancelBtn = excludeCancelBtn || false;
413 excludeCancelBtn = excludeCancelBtn || false;
414 submitEvent = submitEvent || false;
414 submitEvent = submitEvent || false;
415
415
416 $(this.editButton).prop('disabled', state);
416 $(this.editButton).prop('disabled', state);
417 $(this.previewButton).prop('disabled', state);
417 $(this.previewButton).prop('disabled', state);
418
418
419 if (!excludeCancelBtn) {
419 if (!excludeCancelBtn) {
420 $(this.cancelButton).prop('disabled', state);
420 $(this.cancelButton).prop('disabled', state);
421 }
421 }
422
422
423 var submitState = state;
423 var submitState = state;
424 if (!submitEvent && this.getCommentStatus() && !self.isInline()) {
424 if (!submitEvent && this.getCommentStatus() && !self.isInline()) {
425 // if the value of commit review status is set, we allow
425 // if the value of commit review status is set, we allow
426 // submit button, but only on Main form, isInline means inline
426 // submit button, but only on Main form, isInline means inline
427 submitState = false
427 submitState = false
428 }
428 }
429
429
430 $(this.submitButton).prop('disabled', submitState);
430 $(this.submitButton).prop('disabled', submitState);
431 $(this.submitDraftButton).prop('disabled', submitState);
431 $(this.submitDraftButton).prop('disabled', submitState);
432
432
433 if (submitEvent) {
433 if (submitEvent) {
434 var isDraft = self.getDraftState();
434 var isDraft = self.getDraftState();
435
435
436 if (isDraft) {
436 if (isDraft) {
437 $(this.submitDraftButton).val(_gettext('Saving Draft...'));
437 $(this.submitDraftButton).val(_gettext('Saving Draft...'));
438 } else {
438 } else {
439 $(this.submitButton).val(_gettext('Submitting...'));
439 $(this.submitButton).val(_gettext('Submitting...'));
440 }
440 }
441
441
442 } else {
442 } else {
443 $(this.submitButton).val(this.submitButtonText);
443 $(this.submitButton).val(this.submitButtonText);
444 $(this.submitDraftButton).val(this.submitDraftButtonText);
444 $(this.submitDraftButton).val(this.submitDraftButtonText);
445 }
445 }
446
446
447 };
447 };
448
448
449 // lock preview/edit/submit buttons on load, but exclude cancel button
449 // lock preview/edit/submit buttons on load, but exclude cancel button
450 var excludeCancelBtn = true;
450 var excludeCancelBtn = true;
451 this.setActionButtonsDisabled(true, excludeCancelBtn);
451 this.setActionButtonsDisabled(true, excludeCancelBtn);
452
452
453 // anonymous users don't have access to initialized CM instance
453 // anonymous users don't have access to initialized CM instance
454 if (this.cm !== undefined){
454 if (this.cm !== undefined){
455 this.cm.on('change', function(cMirror) {
455 this.cm.on('change', function(cMirror) {
456 if (cMirror.getValue() === "") {
456 if (cMirror.getValue() === "") {
457 self.setActionButtonsDisabled(true, excludeCancelBtn)
457 self.setActionButtonsDisabled(true, excludeCancelBtn)
458 } else {
458 } else {
459 self.setActionButtonsDisabled(false, excludeCancelBtn)
459 self.setActionButtonsDisabled(false, excludeCancelBtn)
460 }
460 }
461 });
461 });
462 }
462 }
463
463
464 $(this.editButton).on('click', function(e) {
464 $(this.editButton).on('click', function(e) {
465 e.preventDefault();
465 e.preventDefault();
466
466
467 $(self.previewButton).parent().removeClass('active');
467 $(self.previewButton).parent().removeClass('active');
468 $(self.previewContainer).hide();
468 $(self.previewContainer).hide();
469
469
470 $(self.editButton).parent().addClass('active');
470 $(self.editButton).parent().addClass('active');
471 $(self.editContainer).show();
471 $(self.editContainer).show();
472
472
473 });
473 });
474
474
475 $(this.previewButton).on('click', function(e) {
475 $(this.previewButton).on('click', function(e) {
476 e.preventDefault();
476 e.preventDefault();
477 var text = self.cm.getValue();
477 var text = self.cm.getValue();
478
478
479 if (text === "") {
479 if (text === "") {
480 return;
480 return;
481 }
481 }
482
482
483 var postData = {
483 var postData = {
484 'text': text,
484 'text': text,
485 'renderer': templateContext.visual.default_renderer,
485 'renderer': templateContext.visual.default_renderer,
486 'csrf_token': CSRF_TOKEN
486 'csrf_token': CSRF_TOKEN
487 };
487 };
488
488
489 // lock ALL buttons on preview
489 // lock ALL buttons on preview
490 self.setActionButtonsDisabled(true);
490 self.setActionButtonsDisabled(true);
491
491
492 $(self.previewBoxSelector).addClass('unloaded');
492 $(self.previewBoxSelector).addClass('unloaded');
493 $(self.previewBoxSelector).html(_gettext('Loading ...'));
493 $(self.previewBoxSelector).html(_gettext('Loading ...'));
494
494
495 $(self.editContainer).hide();
495 $(self.editContainer).hide();
496 $(self.previewContainer).show();
496 $(self.previewContainer).show();
497
497
498 // by default we reset state of comment preserving the text
498 // by default we reset state of comment preserving the text
499 var previewFailCallback = function(jqXHR, textStatus, errorThrown) {
499 var previewFailCallback = function(jqXHR, textStatus, errorThrown) {
500 var prefix = "Error while preview of comment.\n"
500 var prefix = "Error while preview of comment.\n"
501 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
501 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
502 ajaxErrorSwal(message);
502 ajaxErrorSwal(message);
503
503
504 self.resetCommentFormState(text)
504 self.resetCommentFormState(text)
505 };
505 };
506 self.submitAjaxPOST(
506 self.submitAjaxPOST(
507 self.previewUrl, postData, self.previewSuccessCallback,
507 self.previewUrl, postData, self.previewSuccessCallback,
508 previewFailCallback);
508 previewFailCallback);
509
509
510 $(self.previewButton).parent().addClass('active');
510 $(self.previewButton).parent().addClass('active');
511 $(self.editButton).parent().removeClass('active');
511 $(self.editButton).parent().removeClass('active');
512 });
512 });
513
513
514 $(this.submitForm).submit(function(e) {
514 $(this.submitForm).submit(function(e) {
515 e.preventDefault();
515 e.preventDefault();
516 var allowedToSubmit = self.isAllowedToSubmit();
516 var allowedToSubmit = self.isAllowedToSubmit();
517 if (!allowedToSubmit){
517 if (!allowedToSubmit){
518 return false;
518 return false;
519 }
519 }
520
520
521 self.handleFormSubmit();
521 self.handleFormSubmit();
522 });
522 });
523
523
524 }
524 }
525
525
526 return CommentForm;
526 return CommentForm;
527 });
527 });
528
528
529 /* selector for comment versions */
529 /* selector for comment versions */
530 var initVersionSelector = function(selector, initialData) {
530 var initVersionSelector = function(selector, initialData) {
531
531
532 var formatResult = function(result, container, query, escapeMarkup) {
532 var formatResult = function(result, container, query, escapeMarkup) {
533
533
534 return renderTemplate('commentVersion', {
534 return renderTemplate('commentVersion', {
535 show_disabled: true,
535 show_disabled: true,
536 version: result.comment_version,
536 version: result.comment_version,
537 user_name: result.comment_author_username,
537 user_name: result.comment_author_username,
538 gravatar_url: result.comment_author_gravatar,
538 gravatar_url: result.comment_author_gravatar,
539 size: 16,
539 size: 16,
540 timeago_component: result.comment_created_on,
540 timeago_component: result.comment_created_on,
541 })
541 })
542 };
542 };
543
543
544 $(selector).select2({
544 $(selector).select2({
545 placeholder: "Edited",
545 placeholder: "Edited",
546 containerCssClass: "drop-menu-comment-history",
546 containerCssClass: "drop-menu-comment-history",
547 dropdownCssClass: "drop-menu-dropdown",
547 dropdownCssClass: "drop-menu-dropdown",
548 dropdownAutoWidth: true,
548 dropdownAutoWidth: true,
549 minimumResultsForSearch: -1,
549 minimumResultsForSearch: -1,
550 data: initialData,
550 data: initialData,
551 formatResult: formatResult,
551 formatResult: formatResult,
552 });
552 });
553
553
554 $(selector).on('select2-selecting', function (e) {
554 $(selector).on('select2-selecting', function (e) {
555 // hide the mast as we later do preventDefault()
555 // hide the mast as we later do preventDefault()
556 $("#select2-drop-mask").click();
556 $("#select2-drop-mask").click();
557 e.preventDefault();
557 e.preventDefault();
558 e.choice.action();
558 e.choice.action();
559 });
559 });
560
560
561 $(selector).on("select2-open", function() {
561 $(selector).on("select2-open", function() {
562 timeagoActivate();
562 timeagoActivate();
563 });
563 });
564 };
564 };
565
565
566 /* comments controller */
566 /* comments controller */
567 var CommentsController = function() {
567 var CommentsController = function() {
568 var mainComment = '#text';
568 var mainComment = '#text';
569 var self = this;
569 var self = this;
570
570
571 this.showVersion = function (comment_id, comment_history_id) {
571 this.showVersion = function (comment_id, comment_history_id) {
572
572
573 var historyViewUrl = pyroutes.url(
573 var historyViewUrl = pyroutes.url(
574 'repo_commit_comment_history_view',
574 'repo_commit_comment_history_view',
575 {
575 {
576 'repo_name': templateContext.repo_name,
576 'repo_name': templateContext.repo_name,
577 'commit_id': comment_id,
577 'commit_id': comment_id,
578 'comment_history_id': comment_history_id,
578 'comment_history_id': comment_history_id,
579 }
579 }
580 );
580 );
581 successRenderCommit = function (data) {
581 successRenderCommit = function (data) {
582 SwalNoAnimation.fire({
582 SwalNoAnimation.fire({
583 html: data,
583 html: data,
584 title: '',
584 title: '',
585 });
585 });
586 };
586 };
587 failRenderCommit = function () {
587 failRenderCommit = function () {
588 SwalNoAnimation.fire({
588 SwalNoAnimation.fire({
589 html: 'Error while loading comment history',
589 html: 'Error while loading comment history',
590 title: '',
590 title: '',
591 });
591 });
592 };
592 };
593 _submitAjaxPOST(
593 _submitAjaxPOST(
594 historyViewUrl, {'csrf_token': CSRF_TOKEN},
594 historyViewUrl, {'csrf_token': CSRF_TOKEN},
595 successRenderCommit,
595 successRenderCommit,
596 failRenderCommit
596 failRenderCommit
597 );
597 );
598 };
598 };
599
599
600 this.getLineNumber = function(node) {
600 this.getLineNumber = function(node) {
601 var $node = $(node);
601 var $node = $(node);
602 var lineNo = $node.closest('td').attr('data-line-no');
602 var lineNo = $node.closest('td').attr('data-line-no');
603 if (lineNo === undefined && $node.data('commentInline')){
603 if (lineNo === undefined && $node.data('commentInline')){
604 lineNo = $node.data('commentLineNo')
604 lineNo = $node.data('commentLineNo')
605 }
605 }
606
606
607 return lineNo
607 return lineNo
608 };
608 };
609
609
610 this.scrollToComment = function(node, offset, outdated) {
610 this.scrollToComment = function(node, offset, outdated) {
611 if (offset === undefined) {
611 if (offset === undefined) {
612 offset = 0;
612 offset = 0;
613 }
613 }
614 var outdated = outdated || false;
614 var outdated = outdated || false;
615 var klass = outdated ? 'div.comment-outdated' : 'div.comment-current';
615 var klass = outdated ? 'div.comment-outdated' : 'div.comment-current';
616
616
617 if (!node) {
617 if (!node) {
618 node = $('.comment-selected');
618 node = $('.comment-selected');
619 if (!node.length) {
619 if (!node.length) {
620 node = $('comment-current')
620 node = $('comment-current')
621 }
621 }
622 }
622 }
623
623
624 $wrapper = $(node).closest('div.comment');
624 $wrapper = $(node).closest('div.comment');
625
625
626 // show hidden comment when referenced.
626 // show hidden comment when referenced.
627 if (!$wrapper.is(':visible')){
627 if (!$wrapper.is(':visible')){
628 $wrapper.show();
628 $wrapper.show();
629 }
629 }
630
630
631 $comment = $(node).closest(klass);
631 $comment = $(node).closest(klass);
632 $comments = $(klass);
632 $comments = $(klass);
633
633
634 $('.comment-selected').removeClass('comment-selected');
634 $('.comment-selected').removeClass('comment-selected');
635
635
636 var nextIdx = $(klass).index($comment) + offset;
636 var nextIdx = $(klass).index($comment) + offset;
637 if (nextIdx >= $comments.length) {
637 if (nextIdx >= $comments.length) {
638 nextIdx = 0;
638 nextIdx = 0;
639 }
639 }
640 var $next = $(klass).eq(nextIdx);
640 var $next = $(klass).eq(nextIdx);
641
641
642 var $cb = $next.closest('.cb');
642 var $cb = $next.closest('.cb');
643 $cb.removeClass('cb-collapsed');
643 $cb.removeClass('cb-collapsed');
644
644
645 var $filediffCollapseState = $cb.closest('.filediff').prev();
645 var $filediffCollapseState = $cb.closest('.filediff').prev();
646 $filediffCollapseState.prop('checked', false);
646 $filediffCollapseState.prop('checked', false);
647 $next.addClass('comment-selected');
647 $next.addClass('comment-selected');
648 scrollToElement($next);
648 scrollToElement($next);
649 return false;
649 return false;
650 };
650 };
651
651
652 this.nextComment = function(node) {
652 this.nextComment = function(node) {
653 return self.scrollToComment(node, 1);
653 return self.scrollToComment(node, 1);
654 };
654 };
655
655
656 this.prevComment = function(node) {
656 this.prevComment = function(node) {
657 return self.scrollToComment(node, -1);
657 return self.scrollToComment(node, -1);
658 };
658 };
659
659
660 this.nextOutdatedComment = function(node) {
660 this.nextOutdatedComment = function(node) {
661 return self.scrollToComment(node, 1, true);
661 return self.scrollToComment(node, 1, true);
662 };
662 };
663
663
664 this.prevOutdatedComment = function(node) {
664 this.prevOutdatedComment = function(node) {
665 return self.scrollToComment(node, -1, true);
665 return self.scrollToComment(node, -1, true);
666 };
666 };
667
667
668 this.cancelComment = function (node) {
668 this.cancelComment = function (node) {
669 var $node = $(node);
669 var $node = $(node);
670 var edit = $(this).attr('edit');
670 var edit = $(this).attr('edit');
671 var $inlineComments = $node.closest('div.inline-comments');
671 var $inlineComments = $node.closest('div.inline-comments');
672
672
673 if (edit) {
673 if (edit) {
674 var $general_comments = null;
674 var $general_comments = null;
675 if (!$inlineComments.length) {
675 if (!$inlineComments.length) {
676 $general_comments = $('#comments');
676 $general_comments = $('#comments');
677 var $comment = $general_comments.parent().find('div.comment:hidden');
677 var $comment = $general_comments.parent().find('div.comment:hidden');
678 // show hidden general comment form
678 // show hidden general comment form
679 $('#cb-comment-general-form-placeholder').show();
679 $('#cb-comment-general-form-placeholder').show();
680 } else {
680 } else {
681 var $comment = $inlineComments.find('div.comment:hidden');
681 var $comment = $inlineComments.find('div.comment:hidden');
682 }
682 }
683 $comment.show();
683 $comment.show();
684 }
684 }
685 var $replyWrapper = $node.closest('.comment-inline-form').closest('.reply-thread-container-wrapper')
685 var $replyWrapper = $node.closest('.comment-inline-form').closest('.reply-thread-container-wrapper')
686 $replyWrapper.removeClass('comment-form-active');
686 $replyWrapper.removeClass('comment-form-active');
687
687
688 var lastComment = $inlineComments.find('.comment-inline').last();
688 var lastComment = $inlineComments.find('.comment-inline').last();
689 if ($(lastComment).hasClass('comment-outdated')) {
689 if ($(lastComment).hasClass('comment-outdated')) {
690 $replyWrapper.hide();
690 $replyWrapper.hide();
691 }
691 }
692
692
693 $node.closest('.comment-inline-form').remove();
693 $node.closest('.comment-inline-form').remove();
694 return false;
694 return false;
695 };
695 };
696
696
697 this._deleteComment = function(node) {
697 this._deleteComment = function(node) {
698 var $node = $(node);
698 var $node = $(node);
699 var $td = $node.closest('td');
699 var $td = $node.closest('td');
700 var $comment = $node.closest('.comment');
700 var $comment = $node.closest('.comment');
701 var comment_id = $($comment).data('commentId');
701 var comment_id = $($comment).data('commentId');
702 var isDraft = $($comment).data('commentDraft');
702 var isDraft = $($comment).data('commentDraft');
703
703
704 var pullRequestId = templateContext.pull_request_data.pull_request_id;
704 var pullRequestId = templateContext.pull_request_data.pull_request_id;
705 var commitId = templateContext.commit_data.commit_id;
705 var commitId = templateContext.commit_data.commit_id;
706
706
707 if (pullRequestId) {
707 if (pullRequestId) {
708 var url = pyroutes.url('pullrequest_comment_delete', {"comment_id": comment_id, "repo_name": templateContext.repo_name, "pull_request_id": pullRequestId})
708 var url = pyroutes.url('pullrequest_comment_delete', {"comment_id": comment_id, "repo_name": templateContext.repo_name, "pull_request_id": pullRequestId})
709 } else if (commitId) {
709 } else if (commitId) {
710 var url = pyroutes.url('repo_commit_comment_delete', {"comment_id": comment_id, "repo_name": templateContext.repo_name, "commit_id": commitId})
710 var url = pyroutes.url('repo_commit_comment_delete', {"comment_id": comment_id, "repo_name": templateContext.repo_name, "commit_id": commitId})
711 }
711 }
712
712
713 var postData = {
713 var postData = {
714 'csrf_token': CSRF_TOKEN
714 'csrf_token': CSRF_TOKEN
715 };
715 };
716
716
717 $comment.addClass('comment-deleting');
717 $comment.addClass('comment-deleting');
718 $comment.hide('fast');
718 $comment.hide('fast');
719
719
720 var success = function(response) {
720 var success = function(response) {
721 $comment.remove();
721 $comment.remove();
722
722
723 if (window.updateSticky !== undefined) {
723 if (window.updateSticky !== undefined) {
724 // potentially our comments change the active window size, so we
724 // potentially our comments change the active window size, so we
725 // notify sticky elements
725 // notify sticky elements
726 updateSticky()
726 updateSticky()
727 }
727 }
728
728
729 if (window.refreshAllComments !== undefined && !isDraft) {
729 if (window.refreshAllComments !== undefined && !isDraft) {
730 // if we have this handler, run it, and refresh all comments boxes
730 // if we have this handler, run it, and refresh all comments boxes
731 refreshAllComments()
731 refreshAllComments()
732 }
732 }
733 else if (window.refreshDraftComments !== undefined && isDraft) {
733 else if (window.refreshDraftComments !== undefined && isDraft) {
734 // if we have this handler, run it, and refresh all comments boxes
734 // if we have this handler, run it, and refresh all comments boxes
735 refreshDraftComments();
735 refreshDraftComments();
736 }
736 }
737 return false;
737 return false;
738 };
738 };
739
739
740 var failure = function(jqXHR, textStatus, errorThrown) {
740 var failure = function(jqXHR, textStatus, errorThrown) {
741 var prefix = "Error while deleting this comment.\n"
741 var prefix = "Error while deleting this comment.\n"
742 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
742 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
743 ajaxErrorSwal(message);
743 ajaxErrorSwal(message);
744
744
745 $comment.show('fast');
745 $comment.show('fast');
746 $comment.removeClass('comment-deleting');
746 $comment.removeClass('comment-deleting');
747 return false;
747 return false;
748 };
748 };
749 ajaxPOST(url, postData, success, failure);
749 ajaxPOST(url, postData, success, failure);
750
750
751 }
751 }
752
752
753 this.deleteComment = function(node) {
753 this.deleteComment = function(node) {
754 var $comment = $(node).closest('.comment');
754 var $comment = $(node).closest('.comment');
755 var comment_id = $comment.attr('data-comment-id');
755 var comment_id = $comment.attr('data-comment-id');
756
756
757 SwalNoAnimation.fire({
757 SwalNoAnimation.fire({
758 title: 'Delete this comment?',
758 title: 'Delete this comment?',
759 icon: 'warning',
759 icon: 'warning',
760 showCancelButton: true,
760 showCancelButton: true,
761 confirmButtonText: _gettext('Yes, delete comment #{0}!').format(comment_id),
761 confirmButtonText: _gettext('Yes, delete comment #{0}!').format(comment_id),
762
762
763 }).then(function(result) {
763 }).then(function(result) {
764 if (result.value) {
764 if (result.value) {
765 self._deleteComment(node);
765 self._deleteComment(node);
766 }
766 }
767 })
767 })
768 };
768 };
769
769
770 this._finalizeDrafts = function(commentIds) {
770 this._finalizeDrafts = function(commentIds) {
771
771
772 var pullRequestId = templateContext.pull_request_data.pull_request_id;
772 var pullRequestId = templateContext.pull_request_data.pull_request_id;
773 var commitId = templateContext.commit_data.commit_id;
773 var commitId = templateContext.commit_data.commit_id;
774
774
775 if (pullRequestId) {
775 if (pullRequestId) {
776 var url = pyroutes.url('pullrequest_draft_comments_submit', {"repo_name": templateContext.repo_name, "pull_request_id": pullRequestId})
776 var url = pyroutes.url('pullrequest_draft_comments_submit', {"repo_name": templateContext.repo_name, "pull_request_id": pullRequestId})
777 } else if (commitId) {
777 } else if (commitId) {
778 var url = pyroutes.url('commit_draft_comments_submit', {"repo_name": templateContext.repo_name, "commit_id": commitId})
778 var url = pyroutes.url('commit_draft_comments_submit', {"repo_name": templateContext.repo_name, "commit_id": commitId})
779 }
779 }
780
780
781 // remove the drafts so we can lock them before submit.
781 // remove the drafts so we can lock them before submit.
782 $.each(commentIds, function(idx, val){
782 $.each(commentIds, function(idx, val){
783 $('#comment-{0}'.format(val)).remove();
783 $('#comment-{0}'.format(val)).remove();
784 })
784 })
785
785
786 var postData = {'comments': commentIds, 'csrf_token': CSRF_TOKEN};
786 var postData = {'comments': commentIds, 'csrf_token': CSRF_TOKEN};
787
787
788 var submitSuccessCallback = function(json_data) {
788 var submitSuccessCallback = function(json_data) {
789 self.attachInlineComment(json_data);
789 self.attachInlineComment(json_data);
790
790
791 if (window.refreshDraftComments !== undefined) {
791 if (window.refreshDraftComments !== undefined) {
792 // if we have this handler, run it, and refresh all comments boxes
792 // if we have this handler, run it, and refresh all comments boxes
793 refreshDraftComments()
793 refreshDraftComments()
794 }
794 }
795
795
796 return false;
796 return false;
797 };
797 };
798
798
799 ajaxPOST(url, postData, submitSuccessCallback)
799 ajaxPOST(url, postData, submitSuccessCallback)
800
800
801 }
801 }
802
802
803 this.finalizeDrafts = function(commentIds, callback) {
803 this.finalizeDrafts = function(commentIds, callback) {
804
804
805 SwalNoAnimation.fire({
805 SwalNoAnimation.fire({
806 title: _ngettext('Submit {0} draft comment.', 'Submit {0} draft comments.', commentIds.length).format(commentIds.length),
806 title: _ngettext('Submit {0} draft comment.', 'Submit {0} draft comments.', commentIds.length).format(commentIds.length),
807 icon: 'warning',
807 icon: 'warning',
808 showCancelButton: true,
808 showCancelButton: true,
809 confirmButtonText: _gettext('Yes'),
809 confirmButtonText: _gettext('Yes'),
810
810
811 }).then(function(result) {
811 }).then(function(result) {
812 if (result.value) {
812 if (result.value) {
813 if (callback !== undefined) {
813 if (callback !== undefined) {
814 callback(result)
814 callback(result)
815 }
815 }
816 self._finalizeDrafts(commentIds);
816 self._finalizeDrafts(commentIds);
817 }
817 }
818 })
818 })
819 };
819 };
820
820
821 this.toggleWideMode = function (node) {
821 this.toggleWideMode = function (node) {
822
822
823 if ($('#content').hasClass('wrapper')) {
823 if ($('#content').hasClass('wrapper')) {
824 $('#content').removeClass("wrapper");
824 $('#content').removeClass("wrapper");
825 $('#content').addClass("wide-mode-wrapper");
825 $('#content').addClass("wide-mode-wrapper");
826 $(node).addClass('btn-success');
826 $(node).addClass('btn-success');
827 return true
827 return true
828 } else {
828 } else {
829 $('#content').removeClass("wide-mode-wrapper");
829 $('#content').removeClass("wide-mode-wrapper");
830 $('#content').addClass("wrapper");
830 $('#content').addClass("wrapper");
831 $(node).removeClass('btn-success');
831 $(node).removeClass('btn-success');
832 return false
832 return false
833 }
833 }
834
834
835 };
835 };
836
836
837 /**
837 /**
838 * Turn off/on all comments in file diff
838 * Turn off/on all comments in file diff
839 */
839 */
840 this.toggleDiffComments = function(node) {
840 this.toggleDiffComments = function(node) {
841 // Find closes filediff container
841 // Find closes filediff container
842 var $filediff = $(node).closest('.filediff');
842 var $filediff = $(node).closest('.filediff');
843 if ($(node).hasClass('toggle-on')) {
843 if ($(node).hasClass('toggle-on')) {
844 var show = false;
844 var show = false;
845 } else if ($(node).hasClass('toggle-off')) {
845 } else if ($(node).hasClass('toggle-off')) {
846 var show = true;
846 var show = true;
847 }
847 }
848
848
849 // Toggle each individual comment block, so we can un-toggle single ones
849 // Toggle each individual comment block, so we can un-toggle single ones
850 $.each($filediff.find('.toggle-comment-action'), function(idx, val) {
850 $.each($filediff.find('.toggle-comment-action'), function(idx, val) {
851 self.toggleLineComments($(val), show)
851 self.toggleLineComments($(val), show)
852 })
852 })
853
853
854 // since we change the height of the diff container that has anchor points for upper
854 // since we change the height of the diff container that has anchor points for upper
855 // sticky header, we need to tell it to re-calculate those
855 // sticky header, we need to tell it to re-calculate those
856 if (window.updateSticky !== undefined) {
856 if (window.updateSticky !== undefined) {
857 // potentially our comments change the active window size, so we
857 // potentially our comments change the active window size, so we
858 // notify sticky elements
858 // notify sticky elements
859 updateSticky()
859 updateSticky()
860 }
860 }
861
861
862 return false;
862 return false;
863 }
863 }
864
864
865 this.toggleLineComments = function(node, show) {
865 this.toggleLineComments = function(node, show) {
866
866
867 var trElem = $(node).closest('tr')
867 var trElem = $(node).closest('tr')
868
868
869 if (show === true) {
869 if (show === true) {
870 // mark outdated comments as visible before the toggle;
870 // mark outdated comments as visible before the toggle;
871 $(trElem).find('.comment-outdated').show();
871 $(trElem).find('.comment-outdated').show();
872 $(trElem).removeClass('hide-line-comments');
872 $(trElem).removeClass('hide-line-comments');
873 } else if (show === false) {
873 } else if (show === false) {
874 $(trElem).find('.comment-outdated').hide();
874 $(trElem).find('.comment-outdated').hide();
875 $(trElem).addClass('hide-line-comments');
875 $(trElem).addClass('hide-line-comments');
876 } else {
876 } else {
877 // mark outdated comments as visible before the toggle;
877 // mark outdated comments as visible before the toggle;
878 $(trElem).find('.comment-outdated').show();
878 $(trElem).find('.comment-outdated').show();
879 $(trElem).toggleClass('hide-line-comments');
879 $(trElem).toggleClass('hide-line-comments');
880 }
880 }
881
881
882 // since we change the height of the diff container that has anchor points for upper
882 // since we change the height of the diff container that has anchor points for upper
883 // sticky header, we need to tell it to re-calculate those
883 // sticky header, we need to tell it to re-calculate those
884 if (window.updateSticky !== undefined) {
884 if (window.updateSticky !== undefined) {
885 // potentially our comments change the active window size, so we
885 // potentially our comments change the active window size, so we
886 // notify sticky elements
886 // notify sticky elements
887 updateSticky()
887 updateSticky()
888 }
888 }
889
889
890 };
890 };
891
891
892 this.createCommentForm = function(formElement, lineno, placeholderText, initAutocompleteActions, resolvesCommentId, edit, comment_id){
892 this.createCommentForm = function(formElement, lineno, placeholderText, initAutocompleteActions, resolvesCommentId, edit, comment_id){
893 var pullRequestId = templateContext.pull_request_data.pull_request_id;
893 var pullRequestId = templateContext.pull_request_data.pull_request_id;
894 var commitId = templateContext.commit_data.commit_id;
894 var commitId = templateContext.commit_data.commit_id;
895
895
896 var commentForm = new CommentForm(
896 var commentForm = new CommentForm(
897 formElement, commitId, pullRequestId, lineno, initAutocompleteActions, resolvesCommentId, edit, comment_id);
897 formElement, commitId, pullRequestId, lineno, initAutocompleteActions, resolvesCommentId, edit, comment_id);
898 var cm = commentForm.getCmInstance();
898 var cm = commentForm.getCmInstance();
899
899
900 if (resolvesCommentId){
900 if (resolvesCommentId){
901 placeholderText = _gettext('Leave a resolution comment, or click resolve button to resolve TODO comment #{0}').format(resolvesCommentId);
901 placeholderText = _gettext('Leave a resolution comment, or click resolve button to resolve TODO comment #{0}').format(resolvesCommentId);
902 }
902 }
903
903
904 setTimeout(function() {
904 setTimeout(function() {
905 // callbacks
905 // callbacks
906 if (cm !== undefined) {
906 if (cm !== undefined) {
907 commentForm.setPlaceholder(placeholderText);
907 commentForm.setPlaceholder(placeholderText);
908 if (commentForm.isInline()) {
908 if (commentForm.isInline()) {
909 cm.focus();
909 cm.focus();
910 cm.refresh();
910 cm.refresh();
911 }
911 }
912 }
912 }
913 }, 10);
913 }, 10);
914
914
915 // trigger scrolldown to the resolve comment, since it might be away
915 // trigger scrolldown to the resolve comment, since it might be away
916 // from the clicked
916 // from the clicked
917 if (resolvesCommentId){
917 if (resolvesCommentId){
918 var actionNode = $(commentForm.resolvesActionId).offset();
918 var actionNode = $(commentForm.resolvesActionId).offset();
919
919
920 setTimeout(function() {
920 setTimeout(function() {
921 if (actionNode) {
921 if (actionNode) {
922 $('body, html').animate({scrollTop: actionNode.top}, 10);
922 $('body, html').animate({scrollTop: actionNode.top}, 10);
923 }
923 }
924 }, 100);
924 }, 100);
925 }
925 }
926
926
927 // add dropzone support
927 // add dropzone support
928 var insertAttachmentText = function (cm, attachmentName, attachmentStoreUrl, isRendered) {
928 var insertAttachmentText = function (cm, attachmentName, attachmentStoreUrl, isRendered) {
929 var renderer = templateContext.visual.default_renderer;
929 var renderer = templateContext.visual.default_renderer;
930 if (renderer == 'rst') {
930 if (renderer == 'rst') {
931 var attachmentUrl = '`#{0} <{1}>`_'.format(attachmentName, attachmentStoreUrl);
931 var attachmentUrl = '`#{0} <{1}>`_'.format(attachmentName, attachmentStoreUrl);
932 if (isRendered){
932 if (isRendered){
933 attachmentUrl = '\n.. image:: {0}'.format(attachmentStoreUrl);
933 attachmentUrl = '\n.. image:: {0}'.format(attachmentStoreUrl);
934 }
934 }
935 } else if (renderer == 'markdown') {
935 } else if (renderer == 'markdown') {
936 var attachmentUrl = '[{0}]({1})'.format(attachmentName, attachmentStoreUrl);
936 var attachmentUrl = '[{0}]({1})'.format(attachmentName, attachmentStoreUrl);
937 if (isRendered){
937 if (isRendered){
938 attachmentUrl = '!' + attachmentUrl;
938 attachmentUrl = '!' + attachmentUrl;
939 }
939 }
940 } else {
940 } else {
941 var attachmentUrl = '{}'.format(attachmentStoreUrl);
941 var attachmentUrl = '{}'.format(attachmentStoreUrl);
942 }
942 }
943 cm.replaceRange(attachmentUrl+'\n', CodeMirror.Pos(cm.lastLine()));
943 cm.replaceRange(attachmentUrl+'\n', CodeMirror.Pos(cm.lastLine()));
944
944
945 return false;
945 return false;
946 };
946 };
947
947
948 //see: https://www.dropzonejs.com/#configuration
948 //see: https://www.dropzonejs.com/#configuration
949 var storeUrl = pyroutes.url('repo_commit_comment_attachment_upload',
949 var storeUrl = pyroutes.url('repo_commit_comment_attachment_upload',
950 {'repo_name': templateContext.repo_name,
950 {'repo_name': templateContext.repo_name,
951 'commit_id': templateContext.commit_data.commit_id})
951 'commit_id': templateContext.commit_data.commit_id})
952
952
953 var previewTmpl = $(formElement).find('.comment-attachment-uploader-template').get(0);
953 var previewTmpl = $(formElement).find('.comment-attachment-uploader-template').get(0);
954 if (previewTmpl !== undefined){
954 if (previewTmpl !== undefined){
955 var selectLink = $(formElement).find('.pick-attachment').get(0);
955 var selectLink = $(formElement).find('.pick-attachment').get(0);
956 $(formElement).find('.comment-attachment-uploader').dropzone({
956 $(formElement).find('.comment-attachment-uploader').dropzone({
957 url: storeUrl,
957 url: storeUrl,
958 headers: {"X-CSRF-Token": CSRF_TOKEN},
958 headers: {"X-CSRF-Token": CSRF_TOKEN},
959 paramName: function () {
959 paramName: function () {
960 return "attachment"
960 return "attachment"
961 }, // The name that will be used to transfer the file
961 }, // The name that will be used to transfer the file
962 clickable: selectLink,
962 clickable: selectLink,
963 parallelUploads: 1,
963 parallelUploads: 1,
964 maxFiles: 10,
964 maxFiles: 10,
965 maxFilesize: templateContext.attachment_store.max_file_size_mb,
965 maxFilesize: templateContext.attachment_store.max_file_size_mb,
966 uploadMultiple: false,
966 uploadMultiple: false,
967 autoProcessQueue: true, // if false queue will not be processed automatically.
967 autoProcessQueue: true, // if false queue will not be processed automatically.
968 createImageThumbnails: false,
968 createImageThumbnails: false,
969 previewTemplate: previewTmpl.innerHTML,
969 previewTemplate: previewTmpl.innerHTML,
970
970
971 accept: function (file, done) {
971 accept: function (file, done) {
972 done();
972 done();
973 },
973 },
974 init: function () {
974 init: function () {
975
975
976 this.on("sending", function (file, xhr, formData) {
976 this.on("sending", function (file, xhr, formData) {
977 $(formElement).find('.comment-attachment-uploader').find('.dropzone-text').hide();
977 $(formElement).find('.comment-attachment-uploader').find('.dropzone-text').hide();
978 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').show();
978 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').show();
979 });
979 });
980
980
981 this.on("success", function (file, response) {
981 this.on("success", function (file, response) {
982 $(formElement).find('.comment-attachment-uploader').find('.dropzone-text').show();
982 $(formElement).find('.comment-attachment-uploader').find('.dropzone-text').show();
983 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').hide();
983 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').hide();
984
984
985 var isRendered = false;
985 var isRendered = false;
986 var ext = file.name.split('.').pop();
986 var ext = file.name.split('.').pop();
987 var imageExts = templateContext.attachment_store.image_ext;
987 var imageExts = templateContext.attachment_store.image_ext;
988 if (imageExts.indexOf(ext) !== -1){
988 if (imageExts.indexOf(ext) !== -1){
989 isRendered = true;
989 isRendered = true;
990 }
990 }
991
991
992 insertAttachmentText(cm, file.name, response.repo_fqn_access_path, isRendered)
992 insertAttachmentText(cm, file.name, response.repo_fqn_access_path, isRendered)
993 });
993 });
994
994
995 this.on("error", function (file, errorMessage, xhr) {
995 this.on("error", function (file, errorMessage, xhr) {
996 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').hide();
996 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').hide();
997
997
998 var error = null;
998 var error = null;
999
999
1000 if (xhr !== undefined){
1000 if (xhr !== undefined){
1001 var httpStatus = xhr.status + " " + xhr.statusText;
1001 var httpStatus = xhr.status + " " + xhr.statusText;
1002 if (xhr !== undefined && xhr.status >= 500) {
1002 if (xhr !== undefined && xhr.status >= 500) {
1003 error = httpStatus;
1003 error = httpStatus;
1004 }
1004 }
1005 }
1005 }
1006
1006
1007 if (error === null) {
1007 if (error === null) {
1008 error = errorMessage.error || errorMessage || httpStatus;
1008 error = errorMessage.error || errorMessage || httpStatus;
1009 }
1009 }
1010 $(file.previewElement).find('.dz-error-message').html('ERROR: {0}'.format(error));
1010 $(file.previewElement).find('.dz-error-message').html('ERROR: {0}'.format(error));
1011
1011
1012 });
1012 });
1013 }
1013 }
1014 });
1014 });
1015 }
1015 }
1016 return commentForm;
1016 return commentForm;
1017 };
1017 };
1018
1018
1019 this.createGeneralComment = function (lineNo, placeholderText, resolvesCommentId) {
1019 this.createGeneralComment = function (lineNo, placeholderText, resolvesCommentId) {
1020
1020
1021 var tmpl = $('#cb-comment-general-form-template').html();
1021 var tmpl = $('#cb-comment-general-form-template').html();
1022 tmpl = tmpl.format(null, 'general');
1022 tmpl = tmpl.format(null, 'general');
1023 var $form = $(tmpl);
1023 var $form = $(tmpl);
1024
1024
1025 var $formPlaceholder = $('#cb-comment-general-form-placeholder');
1025 var $formPlaceholder = $('#cb-comment-general-form-placeholder');
1026 var curForm = $formPlaceholder.find('form');
1026 var curForm = $formPlaceholder.find('form');
1027 if (curForm){
1027 if (curForm){
1028 curForm.remove();
1028 curForm.remove();
1029 }
1029 }
1030 $formPlaceholder.append($form);
1030 $formPlaceholder.append($form);
1031
1031
1032 var _form = $($form[0]);
1032 var _form = $($form[0]);
1033 var autocompleteActions = ['approve', 'reject', 'as_note', 'as_todo'];
1033 var autocompleteActions = ['approve', 'reject', 'as_note', 'as_todo'];
1034 var edit = false;
1034 var edit = false;
1035 var comment_id = null;
1035 var comment_id = null;
1036 var commentForm = this.createCommentForm(
1036 var commentForm = this.createCommentForm(
1037 _form, lineNo, placeholderText, autocompleteActions, resolvesCommentId, edit, comment_id);
1037 _form, lineNo, placeholderText, autocompleteActions, resolvesCommentId, edit, comment_id);
1038 commentForm.initStatusChangeSelector();
1038 commentForm.initStatusChangeSelector();
1039
1039
1040 return commentForm;
1040 return commentForm;
1041 };
1041 };
1042
1042
1043 this.editComment = function(node, line_no, f_path) {
1043 this.editComment = function(node, line_no, f_path) {
1044 self.edit = true;
1044 self.edit = true;
1045 var $node = $(node);
1045 var $node = $(node);
1046 var $td = $node.closest('td');
1046 var $td = $node.closest('td');
1047
1047
1048 var $comment = $(node).closest('.comment');
1048 var $comment = $(node).closest('.comment');
1049 var comment_id = $($comment).data('commentId');
1049 var comment_id = $($comment).data('commentId');
1050 var isDraft = $($comment).data('commentDraft');
1050 var isDraft = $($comment).data('commentDraft');
1051 var $editForm = null
1051 var $editForm = null
1052
1052
1053 var $comments = $node.closest('div.inline-comments');
1053 var $comments = $node.closest('div.inline-comments');
1054 var $general_comments = null;
1054 var $general_comments = null;
1055
1055
1056 if($comments.length){
1056 if($comments.length){
1057 // inline comments setup
1057 // inline comments setup
1058 $editForm = $comments.find('.comment-inline-form');
1058 $editForm = $comments.find('.comment-inline-form');
1059 line_no = self.getLineNumber(node)
1059 line_no = self.getLineNumber(node)
1060 }
1060 }
1061 else{
1061 else{
1062 // general comments setup
1062 // general comments setup
1063 $comments = $('#comments');
1063 $comments = $('#comments');
1064 $editForm = $comments.find('.comment-inline-form');
1064 $editForm = $comments.find('.comment-inline-form');
1065 line_no = $comment[0].id
1065 line_no = $comment[0].id
1066 $('#cb-comment-general-form-placeholder').hide();
1066 $('#cb-comment-general-form-placeholder').hide();
1067 }
1067 }
1068
1068
1069 if ($editForm.length === 0) {
1069 if ($editForm.length === 0) {
1070
1070
1071 // unhide all comments if they are hidden for a proper REPLY mode
1071 // unhide all comments if they are hidden for a proper REPLY mode
1072 var $filediff = $node.closest('.filediff');
1072 var $filediff = $node.closest('.filediff');
1073 $filediff.removeClass('hide-comments');
1073 $filediff.removeClass('hide-comments');
1074
1074
1075 $editForm = self.createNewFormWrapper(f_path, line_no);
1075 $editForm = self.createNewFormWrapper(f_path, line_no);
1076 if(f_path && line_no) {
1076 if(f_path && line_no) {
1077 $editForm.addClass('comment-inline-form-edit')
1077 $editForm.addClass('comment-inline-form-edit')
1078 }
1078 }
1079
1079
1080 $comment.after($editForm)
1080 $comment.after($editForm)
1081
1081
1082 var _form = $($editForm[0]).find('form');
1082 var _form = $($editForm[0]).find('form');
1083 var autocompleteActions = ['as_note',];
1083 var autocompleteActions = ['as_note',];
1084 var commentForm = this.createCommentForm(
1084 var commentForm = this.createCommentForm(
1085 _form, line_no, '', autocompleteActions, resolvesCommentId,
1085 _form, line_no, '', autocompleteActions, resolvesCommentId,
1086 this.edit, comment_id);
1086 this.edit, comment_id);
1087 var old_comment_text_binary = $comment.attr('data-comment-text');
1087 var old_comment_text_binary = $comment.attr('data-comment-text');
1088 var old_comment_text = b64DecodeUnicode(old_comment_text_binary);
1088 var old_comment_text = b64DecodeUnicode(old_comment_text_binary);
1089 commentForm.cm.setValue(old_comment_text);
1089 commentForm.cm.setValue(old_comment_text);
1090 $comment.hide();
1090 $comment.hide();
1091 tooltipActivate();
1091 tooltipActivate();
1092
1092
1093 // set a CUSTOM submit handler for inline comment edit action.
1093 // set a CUSTOM submit handler for inline comment edit action.
1094 commentForm.setHandleFormSubmit(function(o) {
1094 commentForm.setHandleFormSubmit(function(o) {
1095 var text = commentForm.cm.getValue();
1095 var text = commentForm.cm.getValue();
1096 var commentType = commentForm.getCommentType();
1096 var commentType = commentForm.getCommentType();
1097
1097
1098 if (text === "") {
1098 if (text === "") {
1099 return;
1099 return;
1100 }
1100 }
1101
1101
1102 if (old_comment_text == text) {
1102 if (old_comment_text == text) {
1103 SwalNoAnimation.fire({
1103 SwalNoAnimation.fire({
1104 title: 'Unable to edit comment',
1104 title: 'Unable to edit comment',
1105 html: _gettext('Comment body was not changed.'),
1105 html: _gettext('Comment body was not changed.'),
1106 });
1106 });
1107 return;
1107 return;
1108 }
1108 }
1109 var excludeCancelBtn = false;
1109 var excludeCancelBtn = false;
1110 var submitEvent = true;
1110 var submitEvent = true;
1111 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
1111 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
1112 commentForm.cm.setOption("readOnly", true);
1112 commentForm.cm.setOption("readOnly", true);
1113
1113
1114 // Read last version known
1114 // Read last version known
1115 var versionSelector = $('#comment_versions_{0}'.format(comment_id));
1115 var versionSelector = $('#comment_versions_{0}'.format(comment_id));
1116 var version = versionSelector.data('lastVersion');
1116 var version = versionSelector.data('lastVersion');
1117
1117
1118 if (!version) {
1118 if (!version) {
1119 version = 0;
1119 version = 0;
1120 }
1120 }
1121
1121
1122 var postData = {
1122 var postData = {
1123 'text': text,
1123 'text': text,
1124 'f_path': f_path,
1124 'f_path': f_path,
1125 'line': line_no,
1125 'line': line_no,
1126 'comment_type': commentType,
1126 'comment_type': commentType,
1127 'draft': isDraft,
1127 'draft': isDraft,
1128 'version': version,
1128 'version': version,
1129 'csrf_token': CSRF_TOKEN
1129 'csrf_token': CSRF_TOKEN
1130 };
1130 };
1131
1131
1132 var submitSuccessCallback = function(json_data) {
1132 var submitSuccessCallback = function(json_data) {
1133 $editForm.remove();
1133 $editForm.remove();
1134 $comment.show();
1134 $comment.show();
1135 var postData = {
1135 var postData = {
1136 'text': text,
1136 'text': text,
1137 'renderer': $comment.attr('data-comment-renderer'),
1137 'renderer': $comment.attr('data-comment-renderer'),
1138 'csrf_token': CSRF_TOKEN
1138 'csrf_token': CSRF_TOKEN
1139 };
1139 };
1140
1140
1141 /* Inject new edited version selector */
1141 /* Inject new edited version selector */
1142 var updateCommentVersionDropDown = function () {
1142 var updateCommentVersionDropDown = function () {
1143 var versionSelectId = '#comment_versions_'+comment_id;
1143 var versionSelectId = '#comment_versions_'+comment_id;
1144 var preLoadVersionData = [
1144 var preLoadVersionData = [
1145 {
1145 {
1146 id: json_data['comment_version'],
1146 id: json_data['comment_version'],
1147 text: "v{0}".format(json_data['comment_version']),
1147 text: "v{0}".format(json_data['comment_version']),
1148 action: function () {
1148 action: function () {
1149 Rhodecode.comments.showVersion(
1149 Rhodecode.comments.showVersion(
1150 json_data['comment_id'],
1150 json_data['comment_id'],
1151 json_data['comment_history_id']
1151 json_data['comment_history_id']
1152 )
1152 )
1153 },
1153 },
1154 comment_version: json_data['comment_version'],
1154 comment_version: json_data['comment_version'],
1155 comment_author_username: json_data['comment_author_username'],
1155 comment_author_username: json_data['comment_author_username'],
1156 comment_author_gravatar: json_data['comment_author_gravatar'],
1156 comment_author_gravatar: json_data['comment_author_gravatar'],
1157 comment_created_on: json_data['comment_created_on'],
1157 comment_created_on: json_data['comment_created_on'],
1158 },
1158 },
1159 ]
1159 ]
1160
1160
1161
1161
1162 if ($(versionSelectId).data('select2')) {
1162 if ($(versionSelectId).data('select2')) {
1163 var oldData = $(versionSelectId).data('select2').opts.data.results;
1163 var oldData = $(versionSelectId).data('select2').opts.data.results;
1164 $(versionSelectId).select2("destroy");
1164 $(versionSelectId).select2("destroy");
1165 preLoadVersionData = oldData.concat(preLoadVersionData)
1165 preLoadVersionData = oldData.concat(preLoadVersionData)
1166 }
1166 }
1167
1167
1168 initVersionSelector(versionSelectId, {results: preLoadVersionData});
1168 initVersionSelector(versionSelectId, {results: preLoadVersionData});
1169
1169
1170 $comment.attr('data-comment-text', utf8ToB64(text));
1170 $comment.attr('data-comment-text', utf8ToB64(text));
1171
1171
1172 var versionSelector = $('#comment_versions_'+comment_id);
1172 var versionSelector = $('#comment_versions_'+comment_id);
1173
1173
1174 // set lastVersion so we know our last edit version
1174 // set lastVersion so we know our last edit version
1175 versionSelector.data('lastVersion', json_data['comment_version'])
1175 versionSelector.data('lastVersion', json_data['comment_version'])
1176 versionSelector.parent().show();
1176 versionSelector.parent().show();
1177 }
1177 }
1178 updateCommentVersionDropDown();
1178 updateCommentVersionDropDown();
1179
1179
1180 // by default we reset state of comment preserving the text
1180 // by default we reset state of comment preserving the text
1181 var failRenderCommit = function(jqXHR, textStatus, errorThrown) {
1181 var failRenderCommit = function(jqXHR, textStatus, errorThrown) {
1182 var prefix = "Error while editing this comment.\n"
1182 var prefix = "Error while editing this comment.\n"
1183 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1183 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1184 ajaxErrorSwal(message);
1184 ajaxErrorSwal(message);
1185 };
1185 };
1186
1186
1187 var successRenderCommit = function(o){
1187 var successRenderCommit = function(o){
1188 $comment.show();
1188 $comment.show();
1189 $comment[0].lastElementChild.innerHTML = o;
1189 $comment[0].lastElementChild.innerHTML = o;
1190 };
1190 };
1191
1191
1192 var previewUrl = pyroutes.url(
1192 var previewUrl = pyroutes.url(
1193 'repo_commit_comment_preview',
1193 'repo_commit_comment_preview',
1194 {'repo_name': templateContext.repo_name,
1194 {'repo_name': templateContext.repo_name,
1195 'commit_id': templateContext.commit_data.commit_id});
1195 'commit_id': templateContext.commit_data.commit_id});
1196
1196
1197 _submitAjaxPOST(
1197 _submitAjaxPOST(
1198 previewUrl, postData, successRenderCommit, failRenderCommit
1198 previewUrl, postData, successRenderCommit, failRenderCommit
1199 );
1199 );
1200
1200
1201 try {
1201 try {
1202 var html = json_data.rendered_text;
1202 var html = json_data.rendered_text;
1203 var lineno = json_data.line_no;
1203 var lineno = json_data.line_no;
1204 var target_id = json_data.target_id;
1204 var target_id = json_data.target_id;
1205
1205
1206 $comments.find('.cb-comment-add-button').before(html);
1206 $comments.find('.cb-comment-add-button').before(html);
1207
1207
1208 // run global callback on submit
1208 // run global callback on submit
1209 commentForm.globalSubmitSuccessCallback({draft: isDraft, comment_id: comment_id});
1209 commentForm.globalSubmitSuccessCallback({draft: isDraft, comment_id: comment_id});
1210
1210
1211 } catch (e) {
1211 } catch (e) {
1212 console.error(e);
1212 console.error(e);
1213 }
1213 }
1214
1214
1215 // re trigger the linkification of next/prev navigation
1215 // re trigger the linkification of next/prev navigation
1216 linkifyComments($('.inline-comment-injected'));
1216 linkifyComments($('.inline-comment-injected'));
1217 timeagoActivate();
1217 timeagoActivate();
1218 tooltipActivate();
1218 tooltipActivate();
1219
1219
1220 if (window.updateSticky !== undefined) {
1220 if (window.updateSticky !== undefined) {
1221 // potentially our comments change the active window size, so we
1221 // potentially our comments change the active window size, so we
1222 // notify sticky elements
1222 // notify sticky elements
1223 updateSticky()
1223 updateSticky()
1224 }
1224 }
1225
1225
1226 if (window.refreshAllComments !== undefined && !isDraft) {
1226 if (window.refreshAllComments !== undefined && !isDraft) {
1227 // if we have this handler, run it, and refresh all comments boxes
1227 // if we have this handler, run it, and refresh all comments boxes
1228 refreshAllComments()
1228 refreshAllComments()
1229 }
1229 }
1230 else if (window.refreshDraftComments !== undefined && isDraft) {
1230 else if (window.refreshDraftComments !== undefined && isDraft) {
1231 // if we have this handler, run it, and refresh all comments boxes
1231 // if we have this handler, run it, and refresh all comments boxes
1232 refreshDraftComments();
1232 refreshDraftComments();
1233 }
1233 }
1234
1234
1235 commentForm.setActionButtonsDisabled(false);
1235 commentForm.setActionButtonsDisabled(false);
1236
1236
1237 };
1237 };
1238
1238
1239 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
1239 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
1240 var prefix = "Error while editing comment.\n"
1240 var prefix = "Error while editing comment.\n"
1241 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1241 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1242 if (jqXHR.status == 409){
1242 if (jqXHR.status == 409){
1243 message = 'This comment was probably changed somewhere else. Please reload the content of this comment.'
1243 message = 'This comment was probably changed somewhere else. Please reload the content of this comment.'
1244 ajaxErrorSwal(message, 'Comment version mismatch.');
1244 ajaxErrorSwal(message, 'Comment version mismatch.');
1245 } else {
1245 } else {
1246 ajaxErrorSwal(message);
1246 ajaxErrorSwal(message);
1247 }
1247 }
1248
1248
1249 commentForm.resetCommentFormState(text)
1249 commentForm.resetCommentFormState(text)
1250 };
1250 };
1251 commentForm.submitAjaxPOST(
1251 commentForm.submitAjaxPOST(
1252 commentForm.submitUrl, postData,
1252 commentForm.submitUrl, postData,
1253 submitSuccessCallback,
1253 submitSuccessCallback,
1254 submitFailCallback);
1254 submitFailCallback);
1255 });
1255 });
1256 }
1256 }
1257
1257
1258 $editForm.addClass('comment-inline-form-open');
1258 $editForm.addClass('comment-inline-form-open');
1259 };
1259 };
1260
1260
1261 this.attachComment = function(json_data) {
1261 this.attachComment = function(json_data) {
1262 var self = this;
1262 var self = this;
1263 $.each(json_data, function(idx, val) {
1263 $.each(json_data, function(idx, val) {
1264 var json_data_elem = [val]
1264 var json_data_elem = [val]
1265 var isInline = val.comment_f_path && val.comment_lineno
1265 var isInline = val.comment_f_path && val.comment_lineno
1266
1266
1267 if (isInline) {
1267 if (isInline) {
1268 self.attachInlineComment(json_data_elem)
1268 self.attachInlineComment(json_data_elem)
1269 } else {
1269 } else {
1270 self.attachGeneralComment(json_data_elem)
1270 self.attachGeneralComment(json_data_elem)
1271 }
1271 }
1272 })
1272 })
1273
1273
1274 }
1274 }
1275
1275
1276 this.attachGeneralComment = function(json_data) {
1276 this.attachGeneralComment = function(json_data) {
1277 $.each(json_data, function(idx, val) {
1277 $.each(json_data, function(idx, val) {
1278 $('#injected_page_comments').append(val.rendered_text);
1278 $('#injected_page_comments').append(val.rendered_text);
1279 })
1279 })
1280 }
1280 }
1281
1281
1282 this.attachInlineComment = function(json_data) {
1282 this.attachInlineComment = function(json_data) {
1283
1283
1284 $.each(json_data, function (idx, val) {
1284 $.each(json_data, function (idx, val) {
1285 var line_qry = '*[data-line-no="{0}"]'.format(val.line_no);
1285 var line_qry = '*[data-line-no="{0}"]'.format(val.line_no);
1286 var html = val.rendered_text;
1286 var html = val.rendered_text;
1287 var $inlineComments = $('#' + val.target_id)
1287 var $inlineComments = $('#' + val.target_id)
1288 .find(line_qry)
1288 .find(line_qry)
1289 .find('.inline-comments');
1289 .find('.inline-comments');
1290
1290
1291 var lastComment = $inlineComments.find('.comment-inline').last();
1291 var lastComment = $inlineComments.find('.comment-inline').last();
1292
1292
1293 if (lastComment.length === 0) {
1293 if (lastComment.length === 0) {
1294 // first comment, we append simply
1294 // first comment, we append simply
1295 $inlineComments.find('.reply-thread-container-wrapper').before(html);
1295 $inlineComments.find('.reply-thread-container-wrapper').before(html);
1296 } else {
1296 } else {
1297 $(lastComment).after(html)
1297 $(lastComment).after(html)
1298 }
1298 }
1299
1299
1300 })
1300 })
1301
1301
1302 };
1302 };
1303
1303
1304 this.createNewFormWrapper = function(f_path, line_no) {
1304 this.createNewFormWrapper = function(f_path, line_no) {
1305 // create a new reply HTML form from template
1305 // create a new reply HTML form from template
1306 var tmpl = $('#cb-comment-inline-form-template').html();
1306 var tmpl = $('#cb-comment-inline-form-template').html();
1307 tmpl = tmpl.format(escapeHtml(f_path), line_no);
1307 tmpl = tmpl.format(escapeHtml(f_path), line_no);
1308 return $(tmpl);
1308 return $(tmpl);
1309 }
1309 }
1310
1310
1311 this.createComment = function(node, f_path, line_no, resolutionComment) {
1311 this.createComment = function(node, f_path, line_no, resolutionComment) {
1312 self.edit = false;
1312 self.edit = false;
1313 var $node = $(node);
1313 var $node = $(node);
1314 var $td = $node.closest('td');
1314 var $td = $node.closest('td');
1315 var resolvesCommentId = resolutionComment || null;
1315 var resolvesCommentId = resolutionComment || null;
1316
1316
1317 var $replyForm = $td.find('.comment-inline-form');
1317 var $replyForm = $td.find('.comment-inline-form');
1318
1318
1319 // if form isn't existing, we're generating a new one and injecting it.
1319 // if form isn't existing, we're generating a new one and injecting it.
1320 if ($replyForm.length === 0) {
1320 if ($replyForm.length === 0) {
1321
1321
1322 // unhide/expand all comments if they are hidden for a proper REPLY mode
1322 // unhide/expand all comments if they are hidden for a proper REPLY mode
1323 self.toggleLineComments($node, true);
1323 self.toggleLineComments($node, true);
1324
1324
1325 $replyForm = self.createNewFormWrapper(f_path, line_no);
1325 $replyForm = self.createNewFormWrapper(f_path, line_no);
1326
1326
1327 var $comments = $td.find('.inline-comments');
1327 var $comments = $td.find('.inline-comments');
1328
1328
1329 // There aren't any comments, we init the `.inline-comments` with `reply-thread-container` first
1329 // There aren't any comments, we init the `.inline-comments` with `reply-thread-container` first
1330 if ($comments.length===0) {
1330 if ($comments.length===0) {
1331 var replBtn = '<button class="cb-comment-add-button" onclick="return Rhodecode.comments.createComment(this, \'{0}\', \'{1}\', null)">Reply...</button>'.format(f_path, line_no)
1331 var replBtn = '<button class="cb-comment-add-button" onclick="return Rhodecode.comments.createComment(this, \'{0}\', \'{1}\', null)">Reply...</button>'.format(f_path, line_no)
1332 var $reply_container = $('#cb-comments-inline-container-template')
1332 var $reply_container = $('#cb-comments-inline-container-template')
1333 $reply_container.find('button.cb-comment-add-button').replaceWith(replBtn);
1333 $reply_container.find('button.cb-comment-add-button').replaceWith(replBtn);
1334 $td.append($($reply_container).html());
1334 $td.append($($reply_container).html());
1335 }
1335 }
1336
1336
1337 // default comment button exists, so we prepend the form for leaving initial comment
1337 // default comment button exists, so we prepend the form for leaving initial comment
1338 $td.find('.cb-comment-add-button').before($replyForm);
1338 $td.find('.cb-comment-add-button').before($replyForm);
1339 // set marker, that we have a open form
1339 // set marker, that we have a open form
1340 var $replyWrapper = $td.find('.reply-thread-container-wrapper')
1340 var $replyWrapper = $td.find('.reply-thread-container-wrapper')
1341 $replyWrapper.addClass('comment-form-active');
1341 $replyWrapper.addClass('comment-form-active');
1342
1342
1343 var lastComment = $comments.find('.comment-inline').last();
1343 var lastComment = $comments.find('.comment-inline').last();
1344 if ($(lastComment).hasClass('comment-outdated')) {
1344 if ($(lastComment).hasClass('comment-outdated')) {
1345 $replyWrapper.show();
1345 $replyWrapper.show();
1346 }
1346 }
1347
1347
1348 var _form = $($replyForm[0]).find('form');
1348 var _form = $($replyForm[0]).find('form');
1349 var autocompleteActions = ['as_note', 'as_todo'];
1349 var autocompleteActions = ['as_note', 'as_todo'];
1350 var comment_id=null;
1350 var comment_id=null;
1351 var placeholderText = _gettext('Leave a comment on file {0} line {1}.').format(f_path, line_no);
1351 var placeholderText = _gettext('Leave a comment on file {0} line {1}.').format(f_path, line_no);
1352 var commentForm = self.createCommentForm(
1352 var commentForm = self.createCommentForm(
1353 _form, line_no, placeholderText, autocompleteActions, resolvesCommentId,
1353 _form, line_no, placeholderText, autocompleteActions, resolvesCommentId,
1354 self.edit, comment_id);
1354 self.edit, comment_id);
1355
1355
1356 // set a CUSTOM submit handler for inline comments.
1356 // set a CUSTOM submit handler for inline comments.
1357 commentForm.setHandleFormSubmit(function(o) {
1357 commentForm.setHandleFormSubmit(function(o) {
1358 var text = commentForm.cm.getValue();
1358 var text = commentForm.cm.getValue();
1359 var commentType = commentForm.getCommentType();
1359 var commentType = commentForm.getCommentType();
1360 var resolvesCommentId = commentForm.getResolvesId();
1360 var resolvesCommentId = commentForm.getResolvesId();
1361 var isDraft = commentForm.getDraftState();
1361 var isDraft = commentForm.getDraftState();
1362
1362
1363 if (text === "") {
1363 if (text === "") {
1364 return;
1364 return;
1365 }
1365 }
1366
1366
1367 if (line_no === undefined) {
1367 if (line_no === undefined) {
1368 alert('Error: unable to fetch line number for this inline comment !');
1368 alert('Error: unable to fetch line number for this inline comment !');
1369 return;
1369 return;
1370 }
1370 }
1371
1371
1372 if (f_path === undefined) {
1372 if (f_path === undefined) {
1373 alert('Error: unable to fetch file path for this inline comment !');
1373 alert('Error: unable to fetch file path for this inline comment !');
1374 return;
1374 return;
1375 }
1375 }
1376
1376
1377 var excludeCancelBtn = false;
1377 var excludeCancelBtn = false;
1378 var submitEvent = true;
1378 var submitEvent = true;
1379 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
1379 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
1380 commentForm.cm.setOption("readOnly", true);
1380 commentForm.cm.setOption("readOnly", true);
1381 var postData = {
1381 var postData = {
1382 'text': text,
1382 'text': text,
1383 'f_path': f_path,
1383 'f_path': f_path,
1384 'line': line_no,
1384 'line': line_no,
1385 'comment_type': commentType,
1385 'comment_type': commentType,
1386 'draft': isDraft,
1386 'draft': isDraft,
1387 'csrf_token': CSRF_TOKEN
1387 'csrf_token': CSRF_TOKEN
1388 };
1388 };
1389 if (resolvesCommentId){
1389 if (resolvesCommentId){
1390 postData['resolves_comment_id'] = resolvesCommentId;
1390 postData['resolves_comment_id'] = resolvesCommentId;
1391 }
1391 }
1392
1392
1393 // submitSuccess for inline commits
1393 // submitSuccess for inline commits
1394 var submitSuccessCallback = function(json_data) {
1394 var submitSuccessCallback = function(json_data) {
1395
1395
1396 $replyForm.remove();
1396 $replyForm.remove();
1397 $td.find('.reply-thread-container-wrapper').removeClass('comment-form-active');
1397 $td.find('.reply-thread-container-wrapper').removeClass('comment-form-active');
1398
1398
1399 try {
1399 try {
1400
1400
1401 // inject newly created comments, json_data is {<comment_id>: {}}
1401 // inject newly created comments, json_data is {<comment_id>: {}}
1402 self.attachInlineComment(json_data)
1402 self.attachInlineComment(json_data)
1403
1403
1404 //mark visually which comment was resolved
1404 //mark visually which comment was resolved
1405 if (resolvesCommentId) {
1405 if (resolvesCommentId) {
1406 commentForm.markCommentResolved(resolvesCommentId);
1406 commentForm.markCommentResolved(resolvesCommentId);
1407 }
1407 }
1408
1408
1409 // run global callback on submit
1409 // run global callback on submit
1410 commentForm.globalSubmitSuccessCallback({
1410 commentForm.globalSubmitSuccessCallback({
1411 draft: isDraft,
1411 draft: isDraft,
1412 comment_id: comment_id
1412 comment_id: comment_id
1413 });
1413 });
1414
1414
1415 } catch (e) {
1415 } catch (e) {
1416 console.error(e);
1416 console.error(e);
1417 }
1417 }
1418
1418
1419 if (window.updateSticky !== undefined) {
1419 if (window.updateSticky !== undefined) {
1420 // potentially our comments change the active window size, so we
1420 // potentially our comments change the active window size, so we
1421 // notify sticky elements
1421 // notify sticky elements
1422 updateSticky()
1422 updateSticky()
1423 }
1423 }
1424
1424
1425 if (window.refreshAllComments !== undefined && !isDraft) {
1425 if (window.refreshAllComments !== undefined && !isDraft) {
1426 // if we have this handler, run it, and refresh all comments boxes
1426 // if we have this handler, run it, and refresh all comments boxes
1427 refreshAllComments()
1427 refreshAllComments()
1428 }
1428 }
1429 else if (window.refreshDraftComments !== undefined && isDraft) {
1429 else if (window.refreshDraftComments !== undefined && isDraft) {
1430 // if we have this handler, run it, and refresh all comments boxes
1430 // if we have this handler, run it, and refresh all comments boxes
1431 refreshDraftComments();
1431 refreshDraftComments();
1432 }
1432 }
1433
1433
1434 commentForm.setActionButtonsDisabled(false);
1434 commentForm.setActionButtonsDisabled(false);
1435
1435
1436 // re trigger the linkification of next/prev navigation
1436 // re trigger the linkification of next/prev navigation
1437 linkifyComments($('.inline-comment-injected'));
1437 linkifyComments($('.inline-comment-injected'));
1438 timeagoActivate();
1438 timeagoActivate();
1439 tooltipActivate();
1439 tooltipActivate();
1440 };
1440 };
1441
1441
1442 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
1442 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
1443 var prefix = "Error while submitting comment.\n"
1443 var prefix = "Error while submitting comment.\n"
1444 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1444 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1445 ajaxErrorSwal(message);
1445 ajaxErrorSwal(message);
1446 commentForm.resetCommentFormState(text)
1446 commentForm.resetCommentFormState(text)
1447 };
1447 };
1448
1448
1449 commentForm.submitAjaxPOST(
1449 commentForm.submitAjaxPOST(
1450 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
1450 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
1451 });
1451 });
1452 }
1452 }
1453
1453
1454 // Finally "open" our reply form, since we know there are comments and we have the "attached" old form
1454 // Finally "open" our reply form, since we know there are comments and we have the "attached" old form
1455 $replyForm.addClass('comment-inline-form-open');
1455 $replyForm.addClass('comment-inline-form-open');
1456 tooltipActivate();
1456 tooltipActivate();
1457 };
1457 };
1458
1458
1459 this.createResolutionComment = function(commentId){
1459 this.createResolutionComment = function(commentId){
1460 // hide the trigger text
1460 // hide the trigger text
1461 $('#resolve-comment-{0}'.format(commentId)).hide();
1461 $('#resolve-comment-{0}'.format(commentId)).hide();
1462
1462
1463 var comment = $('#comment-'+commentId);
1463 var comment = $('#comment-'+commentId);
1464 var commentData = comment.data();
1464 var commentData = comment.data();
1465 console.log(commentData);
1466
1465 if (commentData.commentInline) {
1467 if (commentData.commentInline) {
1466 var f_path = commentData.fPath;
1468 var f_path = commentData.commentFPath;
1467 var line_no = commentData.lineNo;
1469 var line_no = commentData.commentLineNo;
1468 //TODO check this if we need to give f_path/line_no
1469 this.createComment(comment, f_path, line_no, commentId)
1470 this.createComment(comment, f_path, line_no, commentId)
1470 } else {
1471 } else {
1471 this.createGeneralComment('general', "$placeholder", commentId)
1472 this.createGeneralComment('general', "$placeholder", commentId)
1472 }
1473 }
1473
1474
1474 return false;
1475 return false;
1475 };
1476 };
1476
1477
1477 this.submitResolution = function(commentId){
1478 this.submitResolution = function(commentId){
1478 var form = $('#resolve_comment_{0}'.format(commentId)).closest('form');
1479 var form = $('#resolve_comment_{0}'.format(commentId)).closest('form');
1479 var commentForm = form.get(0).CommentForm;
1480 var commentForm = form.get(0).CommentForm;
1480
1481
1481 var cm = commentForm.getCmInstance();
1482 var cm = commentForm.getCmInstance();
1482 var renderer = templateContext.visual.default_renderer;
1483 var renderer = templateContext.visual.default_renderer;
1483 if (renderer == 'rst'){
1484 if (renderer == 'rst'){
1484 var commentUrl = '`#{0} <{1}#comment-{0}>`_'.format(commentId, commentForm.selfUrl);
1485 var commentUrl = '`#{0} <{1}#comment-{0}>`_'.format(commentId, commentForm.selfUrl);
1485 } else if (renderer == 'markdown') {
1486 } else if (renderer == 'markdown') {
1486 var commentUrl = '[#{0}]({1}#comment-{0})'.format(commentId, commentForm.selfUrl);
1487 var commentUrl = '[#{0}]({1}#comment-{0})'.format(commentId, commentForm.selfUrl);
1487 } else {
1488 } else {
1488 var commentUrl = '{1}#comment-{0}'.format(commentId, commentForm.selfUrl);
1489 var commentUrl = '{1}#comment-{0}'.format(commentId, commentForm.selfUrl);
1489 }
1490 }
1490
1491
1491 cm.setValue(_gettext('TODO from comment {0} was fixed.').format(commentUrl));
1492 cm.setValue(_gettext('TODO from comment {0} was fixed.').format(commentUrl));
1492 form.submit();
1493 form.submit();
1493 return false;
1494 return false;
1494 };
1495 };
1495
1496
1496 };
1497 };
1497
1498
1498 window.commentHelp = function(renderer) {
1499 window.commentHelp = function(renderer) {
1499 var funcData = {'renderer': renderer}
1500 var funcData = {'renderer': renderer}
1500 return renderTemplate('commentHelpHovercard', funcData)
1501 return renderTemplate('commentHelpHovercard', funcData)
1501 } No newline at end of file
1502 }
General Comments 0
You need to be logged in to leave comments. Login now