##// END OF EJS Templates
js: cleanup linkifyComments function
marcink -
r1329:d188249b default
parent child Browse files
Show More
@@ -1,791 +1,774 b''
1 1 // # Copyright (C) 2010-2017 RhodeCode GmbH
2 2 // #
3 3 // # This program is free software: you can redistribute it and/or modify
4 4 // # it under the terms of the GNU Affero General Public License, version 3
5 5 // # (only), as published by the Free Software Foundation.
6 6 // #
7 7 // # This program is distributed in the hope that it will be useful,
8 8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 // # GNU General Public License for more details.
11 11 // #
12 12 // # You should have received a copy of the GNU Affero General Public License
13 13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 // #
15 15 // # This program is dual-licensed. If you wish to learn more about the
16 16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18 18
19 19 var firefoxAnchorFix = function() {
20 20 // hack to make anchor links behave properly on firefox, in our inline
21 21 // comments generation when comments are injected firefox is misbehaving
22 22 // when jumping to anchor links
23 23 if (location.href.indexOf('#') > -1) {
24 24 location.href += '';
25 25 }
26 26 };
27 27
28 28 var linkifyComments = function(comments) {
29 /* TODO: marcink: remove this - it should no longer needed */
30 for (var i = 0; i < comments.length; i++) {
31 var comment_id = $(comments[i]).data('comment-id');
32 var prev_comment_id = $(comments[i - 1]).data('comment-id');
33 var next_comment_id = $(comments[i + 1]).data('comment-id');
34
35 // place next/prev links
36 if (prev_comment_id) {
37 $('#prev_c_' + comment_id).show();
38 $('#prev_c_' + comment_id + " a.arrow_comment_link").attr(
39 'href', '#comment-' + prev_comment_id).removeClass('disabled');
40 }
41 if (next_comment_id) {
42 $('#next_c_' + comment_id).show();
43 $('#next_c_' + comment_id + " a.arrow_comment_link").attr(
44 'href', '#comment-' + next_comment_id).removeClass('disabled');
45 }
46 /* TODO(marcink): end removal here */
47
48 // place a first link to the total counter
49 if (i === 0) {
50 $('#inline-comments-counter').attr('href', '#comment-' + comment_id);
51 }
29 var firstCommentId = null;
30 if (comments) {
31 firstCommentId = $(comments[0]).data('comment-id');
52 32 }
53 33
34 if (firstCommentId){
35 $('#inline-comments-counter').attr('href', '#comment-' + firstCommentId);
36 }
54 37 };
55 38
56 39 var bindToggleButtons = function() {
57 40 $('.comment-toggle').on('click', function() {
58 41 $(this).parent().nextUntil('tr.line').toggle('inline-comments');
59 42 });
60 43 };
61 44
62 45 /* Comment form for main and inline comments */
63 46
64 47 (function(mod) {
65 48 if (typeof exports == "object" && typeof module == "object") // CommonJS
66 49 module.exports = mod();
67 50 else // Plain browser env
68 51 (this || window).CommentForm = mod();
69 52
70 53 })(function() {
71 54 "use strict";
72 55
73 56 function CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId) {
74 57 if (!(this instanceof CommentForm)) {
75 58 return new CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId);
76 59 }
77 60
78 61 // bind the element instance to our Form
79 62 $(formElement).get(0).CommentForm = this;
80 63
81 64 this.withLineNo = function(selector) {
82 65 var lineNo = this.lineNo;
83 66 if (lineNo === undefined) {
84 67 return selector
85 68 } else {
86 69 return selector + '_' + lineNo;
87 70 }
88 71 };
89 72
90 73 this.commitId = commitId;
91 74 this.pullRequestId = pullRequestId;
92 75 this.lineNo = lineNo;
93 76 this.initAutocompleteActions = initAutocompleteActions;
94 77
95 78 this.previewButton = this.withLineNo('#preview-btn');
96 79 this.previewContainer = this.withLineNo('#preview-container');
97 80
98 81 this.previewBoxSelector = this.withLineNo('#preview-box');
99 82
100 83 this.editButton = this.withLineNo('#edit-btn');
101 84 this.editContainer = this.withLineNo('#edit-container');
102 85 this.cancelButton = this.withLineNo('#cancel-btn');
103 86 this.commentType = this.withLineNo('#comment_type');
104 87
105 88 this.resolvesId = null;
106 89 this.resolvesActionId = null;
107 90
108 91 this.cmBox = this.withLineNo('#text');
109 92 this.cm = initCommentBoxCodeMirror(this.cmBox, this.initAutocompleteActions);
110 93
111 94 this.statusChange = this.withLineNo('#change_status');
112 95
113 96 this.submitForm = formElement;
114 97 this.submitButton = $(this.submitForm).find('input[type="submit"]');
115 98 this.submitButtonText = this.submitButton.val();
116 99
117 100 this.previewUrl = pyroutes.url('changeset_comment_preview',
118 101 {'repo_name': templateContext.repo_name});
119 102
120 103 if (resolvesCommentId){
121 104 this.resolvesId = '#resolve_comment_{0}'.format(resolvesCommentId);
122 105 this.resolvesActionId = '#resolve_comment_action_{0}'.format(resolvesCommentId);
123 106 $(this.commentType).prop('disabled', true);
124 107 $(this.commentType).addClass('disabled');
125 108
126 109 // disable select
127 110 setTimeout(function() {
128 111 $(self.statusChange).select2('readonly', true);
129 112 }, 10);
130 113
131 114 var resolvedInfo = (
132 115 '<li class="">' +
133 116 '<input type="hidden" id="resolve_comment_{0}" name="resolve_comment_{0}" value="{0}">' +
134 117 '<button id="resolve_comment_action_{0}" class="resolve-text btn btn-sm" onclick="return Rhodecode.comments.submitResolution({0})">{1} #{0}</button>' +
135 118 '</li>'
136 119 ).format(resolvesCommentId, _gettext('resolve comment'));
137 120 $(resolvedInfo).insertAfter($(this.commentType).parent());
138 121 }
139 122
140 123 // based on commitId, or pullRequestId decide where do we submit
141 124 // out data
142 125 if (this.commitId){
143 126 this.submitUrl = pyroutes.url('changeset_comment',
144 127 {'repo_name': templateContext.repo_name,
145 128 'revision': this.commitId});
146 129 this.selfUrl = pyroutes.url('changeset_home',
147 130 {'repo_name': templateContext.repo_name,
148 131 'revision': this.commitId});
149 132
150 133 } else if (this.pullRequestId) {
151 134 this.submitUrl = pyroutes.url('pullrequest_comment',
152 135 {'repo_name': templateContext.repo_name,
153 136 'pull_request_id': this.pullRequestId});
154 137 this.selfUrl = pyroutes.url('pullrequest_show',
155 138 {'repo_name': templateContext.repo_name,
156 139 'pull_request_id': this.pullRequestId});
157 140
158 141 } else {
159 142 throw new Error(
160 143 'CommentForm requires pullRequestId, or commitId to be specified.')
161 144 }
162 145
163 146 // FUNCTIONS and helpers
164 147 var self = this;
165 148
166 149 this.isInline = function(){
167 150 return this.lineNo && this.lineNo != 'general';
168 151 };
169 152
170 153 this.getCmInstance = function(){
171 154 return this.cm
172 155 };
173 156
174 157 this.setPlaceholder = function(placeholder) {
175 158 var cm = this.getCmInstance();
176 159 if (cm){
177 160 cm.setOption('placeholder', placeholder);
178 161 }
179 162 };
180 163
181 164 this.getCommentStatus = function() {
182 165 return $(this.submitForm).find(this.statusChange).val();
183 166 };
184 167 this.getCommentType = function() {
185 168 return $(this.submitForm).find(this.commentType).val();
186 169 };
187 170
188 171 this.getResolvesId = function() {
189 172 return $(this.submitForm).find(this.resolvesId).val() || null;
190 173 };
191 174 this.markCommentResolved = function(resolvedCommentId){
192 175 $('#comment-label-{0}'.format(resolvedCommentId)).find('.resolved').show();
193 176 $('#comment-label-{0}'.format(resolvedCommentId)).find('.resolve').hide();
194 177 };
195 178
196 179 this.isAllowedToSubmit = function() {
197 180 return !$(this.submitButton).prop('disabled');
198 181 };
199 182
200 183 this.initStatusChangeSelector = function(){
201 184 var formatChangeStatus = function(state, escapeMarkup) {
202 185 var originalOption = state.element;
203 186 return '<div class="flag_status ' + $(originalOption).data('status') + ' pull-left"></div>' +
204 187 '<span>' + escapeMarkup(state.text) + '</span>';
205 188 };
206 189 var formatResult = function(result, container, query, escapeMarkup) {
207 190 return formatChangeStatus(result, escapeMarkup);
208 191 };
209 192
210 193 var formatSelection = function(data, container, escapeMarkup) {
211 194 return formatChangeStatus(data, escapeMarkup);
212 195 };
213 196
214 197 $(this.submitForm).find(this.statusChange).select2({
215 198 placeholder: _gettext('Status Review'),
216 199 formatResult: formatResult,
217 200 formatSelection: formatSelection,
218 201 containerCssClass: "drop-menu status_box_menu",
219 202 dropdownCssClass: "drop-menu-dropdown",
220 203 dropdownAutoWidth: true,
221 204 minimumResultsForSearch: -1
222 205 });
223 206 $(this.submitForm).find(this.statusChange).on('change', function() {
224 207 var status = self.getCommentStatus();
225 208 if (status && !self.isInline()) {
226 209 $(self.submitButton).prop('disabled', false);
227 210 }
228 211
229 212 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
230 213 self.setPlaceholder(placeholderText)
231 214 })
232 215 };
233 216
234 217 // reset the comment form into it's original state
235 218 this.resetCommentFormState = function(content) {
236 219 content = content || '';
237 220
238 221 $(this.editContainer).show();
239 222 $(this.editButton).parent().addClass('active');
240 223
241 224 $(this.previewContainer).hide();
242 225 $(this.previewButton).parent().removeClass('active');
243 226
244 227 this.setActionButtonsDisabled(true);
245 228 self.cm.setValue(content);
246 229 self.cm.setOption("readOnly", false);
247 230
248 231 if (this.resolvesId) {
249 232 // destroy the resolve action
250 233 $(this.resolvesId).parent().remove();
251 234 }
252 235
253 236 $(this.statusChange).select2('readonly', false);
254 237 };
255 238
256 239 this.submitAjaxPOST = function(url, postData, successHandler, failHandler) {
257 240 failHandler = failHandler || function() {};
258 241 var postData = toQueryString(postData);
259 242 var request = $.ajax({
260 243 url: url,
261 244 type: 'POST',
262 245 data: postData,
263 246 headers: {'X-PARTIAL-XHR': true}
264 247 })
265 248 .done(function(data) {
266 249 successHandler(data);
267 250 })
268 251 .fail(function(data, textStatus, errorThrown){
269 252 alert(
270 253 "Error while submitting comment.\n" +
271 254 "Error code {0} ({1}).".format(data.status, data.statusText));
272 255 failHandler()
273 256 });
274 257 return request;
275 258 };
276 259
277 260 // overwrite a submitHandler, we need to do it for inline comments
278 261 this.setHandleFormSubmit = function(callback) {
279 262 this.handleFormSubmit = callback;
280 263 };
281 264
282 265 // default handler for for submit for main comments
283 266 this.handleFormSubmit = function() {
284 267 var text = self.cm.getValue();
285 268 var status = self.getCommentStatus();
286 269 var commentType = self.getCommentType();
287 270 var resolvesCommentId = self.getResolvesId();
288 271
289 272 if (text === "" && !status) {
290 273 return;
291 274 }
292 275
293 276 var excludeCancelBtn = false;
294 277 var submitEvent = true;
295 278 self.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
296 279 self.cm.setOption("readOnly", true);
297 280
298 281 var postData = {
299 282 'text': text,
300 283 'changeset_status': status,
301 284 'comment_type': commentType,
302 285 'csrf_token': CSRF_TOKEN
303 286 };
304 287 if (resolvesCommentId){
305 288 postData['resolves_comment_id'] = resolvesCommentId;
306 289 }
307 290 var submitSuccessCallback = function(o) {
308 291 if (status) {
309 292 location.reload(true);
310 293 } else {
311 294 $('#injected_page_comments').append(o.rendered_text);
312 295 self.resetCommentFormState();
313 296 timeagoActivate();
314 297
315 298 // mark visually which comment was resolved
316 299 if (resolvesCommentId) {
317 300 self.markCommentResolved(resolvesCommentId);
318 301 }
319 302 }
320 303 };
321 304 var submitFailCallback = function(){
322 305 self.resetCommentFormState(text);
323 306 };
324 307 self.submitAjaxPOST(
325 308 self.submitUrl, postData, submitSuccessCallback, submitFailCallback);
326 309 };
327 310
328 311 this.previewSuccessCallback = function(o) {
329 312 $(self.previewBoxSelector).html(o);
330 313 $(self.previewBoxSelector).removeClass('unloaded');
331 314
332 315 // swap buttons, making preview active
333 316 $(self.previewButton).parent().addClass('active');
334 317 $(self.editButton).parent().removeClass('active');
335 318
336 319 // unlock buttons
337 320 self.setActionButtonsDisabled(false);
338 321 };
339 322
340 323 this.setActionButtonsDisabled = function(state, excludeCancelBtn, submitEvent) {
341 324 excludeCancelBtn = excludeCancelBtn || false;
342 325 submitEvent = submitEvent || false;
343 326
344 327 $(this.editButton).prop('disabled', state);
345 328 $(this.previewButton).prop('disabled', state);
346 329
347 330 if (!excludeCancelBtn) {
348 331 $(this.cancelButton).prop('disabled', state);
349 332 }
350 333
351 334 var submitState = state;
352 335 if (!submitEvent && this.getCommentStatus() && !this.lineNo) {
353 336 // if the value of commit review status is set, we allow
354 337 // submit button, but only on Main form, lineNo means inline
355 338 submitState = false
356 339 }
357 340 $(this.submitButton).prop('disabled', submitState);
358 341 if (submitEvent) {
359 342 $(this.submitButton).val(_gettext('Submitting...'));
360 343 } else {
361 344 $(this.submitButton).val(this.submitButtonText);
362 345 }
363 346
364 347 };
365 348
366 349 // lock preview/edit/submit buttons on load, but exclude cancel button
367 350 var excludeCancelBtn = true;
368 351 this.setActionButtonsDisabled(true, excludeCancelBtn);
369 352
370 353 // anonymous users don't have access to initialized CM instance
371 354 if (this.cm !== undefined){
372 355 this.cm.on('change', function(cMirror) {
373 356 if (cMirror.getValue() === "") {
374 357 self.setActionButtonsDisabled(true, excludeCancelBtn)
375 358 } else {
376 359 self.setActionButtonsDisabled(false, excludeCancelBtn)
377 360 }
378 361 });
379 362 }
380 363
381 364 $(this.editButton).on('click', function(e) {
382 365 e.preventDefault();
383 366
384 367 $(self.previewButton).parent().removeClass('active');
385 368 $(self.previewContainer).hide();
386 369
387 370 $(self.editButton).parent().addClass('active');
388 371 $(self.editContainer).show();
389 372
390 373 });
391 374
392 375 $(this.previewButton).on('click', function(e) {
393 376 e.preventDefault();
394 377 var text = self.cm.getValue();
395 378
396 379 if (text === "") {
397 380 return;
398 381 }
399 382
400 383 var postData = {
401 384 'text': text,
402 385 'renderer': templateContext.visual.default_renderer,
403 386 'csrf_token': CSRF_TOKEN
404 387 };
405 388
406 389 // lock ALL buttons on preview
407 390 self.setActionButtonsDisabled(true);
408 391
409 392 $(self.previewBoxSelector).addClass('unloaded');
410 393 $(self.previewBoxSelector).html(_gettext('Loading ...'));
411 394
412 395 $(self.editContainer).hide();
413 396 $(self.previewContainer).show();
414 397
415 398 // by default we reset state of comment preserving the text
416 399 var previewFailCallback = function(){
417 400 self.resetCommentFormState(text)
418 401 };
419 402 self.submitAjaxPOST(
420 403 self.previewUrl, postData, self.previewSuccessCallback,
421 404 previewFailCallback);
422 405
423 406 $(self.previewButton).parent().addClass('active');
424 407 $(self.editButton).parent().removeClass('active');
425 408 });
426 409
427 410 $(this.submitForm).submit(function(e) {
428 411 e.preventDefault();
429 412 var allowedToSubmit = self.isAllowedToSubmit();
430 413 if (!allowedToSubmit){
431 414 return false;
432 415 }
433 416 self.handleFormSubmit();
434 417 });
435 418
436 419 }
437 420
438 421 return CommentForm;
439 422 });
440 423
441 424 /* comments controller */
442 425 var CommentsController = function() {
443 426 var mainComment = '#text';
444 427 var self = this;
445 428
446 429 this.cancelComment = function(node) {
447 430 var $node = $(node);
448 431 var $td = $node.closest('td');
449 432 $node.closest('.comment-inline-form').remove();
450 433 return false;
451 434 };
452 435
453 436 this.getLineNumber = function(node) {
454 437 var $node = $(node);
455 438 return $node.closest('td').attr('data-line-number');
456 439 };
457 440
458 441 this.scrollToComment = function(node, offset, outdated) {
459 442 var outdated = outdated || false;
460 443 var klass = outdated ? 'div.comment-outdated' : 'div.comment-current';
461 444
462 445 if (!node) {
463 446 node = $('.comment-selected');
464 447 if (!node.length) {
465 448 node = $('comment-current')
466 449 }
467 450 }
468 451 $comment = $(node).closest(klass);
469 452 $comments = $(klass);
470 453
471 454 $('.comment-selected').removeClass('comment-selected');
472 455
473 456 var nextIdx = $(klass).index($comment) + offset;
474 457 if (nextIdx >= $comments.length) {
475 458 nextIdx = 0;
476 459 }
477 460 var $next = $(klass).eq(nextIdx);
478 461 var $cb = $next.closest('.cb');
479 462 $cb.removeClass('cb-collapsed');
480 463
481 464 var $filediffCollapseState = $cb.closest('.filediff').prev();
482 465 $filediffCollapseState.prop('checked', false);
483 466 $next.addClass('comment-selected');
484 467 scrollToElement($next);
485 468 return false;
486 469 };
487 470
488 471 this.nextComment = function(node) {
489 472 return self.scrollToComment(node, 1);
490 473 };
491 474
492 475 this.prevComment = function(node) {
493 476 return self.scrollToComment(node, -1);
494 477 };
495 478
496 479 this.nextOutdatedComment = function(node) {
497 480 return self.scrollToComment(node, 1, true);
498 481 };
499 482
500 483 this.prevOutdatedComment = function(node) {
501 484 return self.scrollToComment(node, -1, true);
502 485 };
503 486
504 487 this.deleteComment = function(node) {
505 488 if (!confirm(_gettext('Delete this comment?'))) {
506 489 return false;
507 490 }
508 491 var $node = $(node);
509 492 var $td = $node.closest('td');
510 493 var $comment = $node.closest('.comment');
511 494 var comment_id = $comment.attr('data-comment-id');
512 495 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id);
513 496 var postData = {
514 497 '_method': 'delete',
515 498 'csrf_token': CSRF_TOKEN
516 499 };
517 500
518 501 $comment.addClass('comment-deleting');
519 502 $comment.hide('fast');
520 503
521 504 var success = function(response) {
522 505 $comment.remove();
523 506 return false;
524 507 };
525 508 var failure = function(data, textStatus, xhr) {
526 509 alert("error processing request: " + textStatus);
527 510 $comment.show('fast');
528 511 $comment.removeClass('comment-deleting');
529 512 return false;
530 513 };
531 514 ajaxPOST(url, postData, success, failure);
532 515 };
533 516
534 517 this.toggleWideMode = function (node) {
535 518 if ($('#content').hasClass('wrapper')) {
536 519 $('#content').removeClass("wrapper");
537 520 $('#content').addClass("wide-mode-wrapper");
538 521 $(node).addClass('btn-success');
539 522 } else {
540 523 $('#content').removeClass("wide-mode-wrapper");
541 524 $('#content').addClass("wrapper");
542 525 $(node).removeClass('btn-success');
543 526 }
544 527 return false;
545 528 };
546 529
547 530 this.toggleComments = function(node, show) {
548 531 var $filediff = $(node).closest('.filediff');
549 532 if (show === true) {
550 533 $filediff.removeClass('hide-comments');
551 534 } else if (show === false) {
552 535 $filediff.find('.hide-line-comments').removeClass('hide-line-comments');
553 536 $filediff.addClass('hide-comments');
554 537 } else {
555 538 $filediff.find('.hide-line-comments').removeClass('hide-line-comments');
556 539 $filediff.toggleClass('hide-comments');
557 540 }
558 541 return false;
559 542 };
560 543
561 544 this.toggleLineComments = function(node) {
562 545 self.toggleComments(node, true);
563 546 var $node = $(node);
564 547 $node.closest('tr').toggleClass('hide-line-comments');
565 548 };
566 549
567 550 this.createCommentForm = function(formElement, lineno, placeholderText, initAutocompleteActions, resolvesCommentId){
568 551 var pullRequestId = templateContext.pull_request_data.pull_request_id;
569 552 var commitId = templateContext.commit_data.commit_id;
570 553
571 554 var commentForm = new CommentForm(
572 555 formElement, commitId, pullRequestId, lineno, initAutocompleteActions, resolvesCommentId);
573 556 var cm = commentForm.getCmInstance();
574 557
575 558 if (resolvesCommentId){
576 559 var placeholderText = _gettext('Leave a comment, or click resolve button to resolve TODO comment #{0}').format(resolvesCommentId);
577 560 }
578 561
579 562 setTimeout(function() {
580 563 // callbacks
581 564 if (cm !== undefined) {
582 565 commentForm.setPlaceholder(placeholderText);
583 566 if (commentForm.isInline()) {
584 567 cm.focus();
585 568 cm.refresh();
586 569 }
587 570 }
588 571 }, 10);
589 572
590 573 // trigger scrolldown to the resolve comment, since it might be away
591 574 // from the clicked
592 575 if (resolvesCommentId){
593 576 var actionNode = $(commentForm.resolvesActionId).offset();
594 577
595 578 setTimeout(function() {
596 579 if (actionNode) {
597 580 $('body, html').animate({scrollTop: actionNode.top}, 10);
598 581 }
599 582 }, 100);
600 583 }
601 584
602 585 return commentForm;
603 586 };
604 587
605 588 this.createGeneralComment = function(lineNo, placeholderText, resolvesCommentId){
606 589
607 590 var tmpl = $('#cb-comment-general-form-template').html();
608 591 tmpl = tmpl.format(null, 'general');
609 592 var $form = $(tmpl);
610 593
611 594 var curForm = $('#cb-comment-general-form-placeholder').find('form');
612 595 if (curForm){
613 596 curForm.remove();
614 597 }
615 598 $('#cb-comment-general-form-placeholder').append($form);
616 599
617 600 var _form = $($form[0]);
618 601 var commentForm = this.createCommentForm(
619 602 _form, lineNo, placeholderText, true, resolvesCommentId);
620 603 commentForm.initStatusChangeSelector();
621 604 };
622 605
623 606 this.createComment = function(node, resolutionComment) {
624 607 var resolvesCommentId = resolutionComment || null;
625 608 var $node = $(node);
626 609 var $td = $node.closest('td');
627 610 var $form = $td.find('.comment-inline-form');
628 611
629 612 if (!$form.length) {
630 613
631 614 var $filediff = $node.closest('.filediff');
632 615 $filediff.removeClass('hide-comments');
633 616 var f_path = $filediff.attr('data-f-path');
634 617 var lineno = self.getLineNumber(node);
635 618 // create a new HTML from template
636 619 var tmpl = $('#cb-comment-inline-form-template').html();
637 620 tmpl = tmpl.format(f_path, lineno);
638 621 $form = $(tmpl);
639 622
640 623 var $comments = $td.find('.inline-comments');
641 624 if (!$comments.length) {
642 625 $comments = $(
643 626 $('#cb-comments-inline-container-template').html());
644 627 $td.append($comments);
645 628 }
646 629
647 630 $td.find('.cb-comment-add-button').before($form);
648 631
649 632 var placeholderText = _gettext('Leave a comment on line {0}.').format(lineno);
650 633 var _form = $($form[0]).find('form');
651 634
652 635 var commentForm = this.createCommentForm(
653 636 _form, lineno, placeholderText, false, resolvesCommentId);
654 637
655 638 $.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({
656 639 form: _form,
657 640 parent: $td[0],
658 641 lineno: lineno,
659 642 f_path: f_path}
660 643 );
661 644
662 645 // set a CUSTOM submit handler for inline comments.
663 646 commentForm.setHandleFormSubmit(function(o) {
664 647 var text = commentForm.cm.getValue();
665 648 var commentType = commentForm.getCommentType();
666 649 var resolvesCommentId = commentForm.getResolvesId();
667 650
668 651 if (text === "") {
669 652 return;
670 653 }
671 654
672 655 if (lineno === undefined) {
673 656 alert('missing line !');
674 657 return;
675 658 }
676 659 if (f_path === undefined) {
677 660 alert('missing file path !');
678 661 return;
679 662 }
680 663
681 664 var excludeCancelBtn = false;
682 665 var submitEvent = true;
683 666 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
684 667 commentForm.cm.setOption("readOnly", true);
685 668 var postData = {
686 669 'text': text,
687 670 'f_path': f_path,
688 671 'line': lineno,
689 672 'comment_type': commentType,
690 673 'csrf_token': CSRF_TOKEN
691 674 };
692 675 if (resolvesCommentId){
693 676 postData['resolves_comment_id'] = resolvesCommentId;
694 677 }
695 678
696 679 var submitSuccessCallback = function(json_data) {
697 680 $form.remove();
698 681 try {
699 682 var html = json_data.rendered_text;
700 683 var lineno = json_data.line_no;
701 684 var target_id = json_data.target_id;
702 685
703 686 $comments.find('.cb-comment-add-button').before(html);
704 687
705 688 //mark visually which comment was resolved
706 689 if (resolvesCommentId) {
707 690 commentForm.markCommentResolved(resolvesCommentId);
708 691 }
709 692
710 693 } catch (e) {
711 694 console.error(e);
712 695 }
713 696
714 697 // re trigger the linkification of next/prev navigation
715 698 linkifyComments($('.inline-comment-injected'));
716 699 timeagoActivate();
717 700 commentForm.setActionButtonsDisabled(false);
718 701
719 702 };
720 703 var submitFailCallback = function(){
721 704 commentForm.resetCommentFormState(text)
722 705 };
723 706 commentForm.submitAjaxPOST(
724 707 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
725 708 });
726 709 }
727 710
728 711 $form.addClass('comment-inline-form-open');
729 712 };
730 713
731 714 this.createResolutionComment = function(commentId){
732 715 // hide the trigger text
733 716 $('#resolve-comment-{0}'.format(commentId)).hide();
734 717
735 718 var comment = $('#comment-'+commentId);
736 719 var commentData = comment.data();
737 720 if (commentData.commentInline) {
738 721 this.createComment(comment, commentId)
739 722 } else {
740 723 Rhodecode.comments.createGeneralComment('general', "$placeholder", commentId)
741 724 }
742 725
743 726 return false;
744 727 };
745 728
746 729 this.submitResolution = function(commentId){
747 730 var form = $('#resolve_comment_{0}'.format(commentId)).closest('form');
748 731 var commentForm = form.get(0).CommentForm;
749 732
750 733 var cm = commentForm.getCmInstance();
751 734 var renderer = templateContext.visual.default_renderer;
752 735 if (renderer == 'rst'){
753 736 var commentUrl = '`#{0} <{1}#comment-{0}>`_'.format(commentId, commentForm.selfUrl);
754 737 } else if (renderer == 'markdown') {
755 738 var commentUrl = '[#{0}]({1}#comment-{0})'.format(commentId, commentForm.selfUrl);
756 739 } else {
757 740 var commentUrl = '{1}#comment-{0}'.format(commentId, commentForm.selfUrl);
758 741 }
759 742
760 743 cm.setValue(_gettext('TODO from comment {0} was fixed.').format(commentUrl));
761 744 form.submit();
762 745 return false;
763 746 };
764 747
765 748 this.renderInlineComments = function(file_comments) {
766 749 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
767 750
768 751 for (var i = 0; i < file_comments.length; i++) {
769 752 var box = file_comments[i];
770 753
771 754 var target_id = $(box).attr('target_id');
772 755
773 756 // actually comments with line numbers
774 757 var comments = box.children;
775 758
776 759 for (var j = 0; j < comments.length; j++) {
777 760 var data = {
778 761 'rendered_text': comments[j].outerHTML,
779 762 'line_no': $(comments[j]).attr('line'),
780 763 'target_id': target_id
781 764 };
782 765 }
783 766 }
784 767
785 768 // since order of injection is random, we're now re-iterating
786 769 // from correct order and filling in links
787 770 linkifyComments($('.inline-comment-injected'));
788 771 firefoxAnchorFix();
789 772 };
790 773
791 774 };
General Comments 0
You need to be logged in to leave comments. Login now