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