##// END OF EJS Templates
comments: allow submitting id of comment which submitted comment resolved....
marcink -
r1325:b4535cc7 default
parent child Browse files
Show More
@@ -694,8 +694,8 b' def make_map(config):'
694 694 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
695 695
696 696 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
697 controller='summary', action='repo_refs_data', jsroute=True,
698 requirements=URL_NAME_REQUIREMENTS)
697 controller='summary', action='repo_refs_data',
698 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
699 699 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
700 700 controller='summary', action='repo_refs_changelog_data',
701 701 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
@@ -704,9 +704,9 b' def make_map(config):'
704 704 jsroute=True, requirements=URL_NAME_REQUIREMENTS)
705 705
706 706 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
707 controller='changeset', revision='tip', jsroute=True,
707 controller='changeset', revision='tip',
708 708 conditions={'function': check_repo},
709 requirements=URL_NAME_REQUIREMENTS)
709 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
710 710 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
711 711 controller='changeset', revision='tip', action='changeset_children',
712 712 conditions={'function': check_repo},
@@ -923,7 +923,7 b' def make_map(config):'
923 923 controller='pullrequests',
924 924 action='show', conditions={'function': check_repo,
925 925 'method': ['GET']},
926 requirements=URL_NAME_REQUIREMENTS)
926 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
927 927
928 928 rmap.connect('pullrequest_update',
929 929 '/{repo_name}/pull-request/{pull_request_id}',
@@ -904,6 +904,8 b' class PullrequestsController(BaseRepoCon'
904 904 status = request.POST.get('changeset_status', None)
905 905 text = request.POST.get('text')
906 906 comment_type = request.POST.get('comment_type')
907 resolves_comment_id = request.POST.get('resolves_comment_id')
908
907 909 if status and '_closed' in status:
908 910 close_pr = True
909 911 status = status.replace('_closed', '')
@@ -936,7 +938,8 b' class PullrequestsController(BaseRepoCon'
936 938 status_change_type=(status
937 939 if status and allowed_to_change_status else None),
938 940 closing_pr=close_pr,
939 comment_type=comment_type
941 comment_type=comment_type,
942 resolves_comment_id=resolves_comment_id
940 943 )
941 944
942 945 if allowed_to_change_status:
@@ -84,9 +84,10 b' class CommentsModel(BaseModel):'
84 84 return global_renderer
85 85
86 86 def create(self, text, repo, user, commit_id=None, pull_request=None,
87 f_path=None, line_no=None, status_change=None, comment_type=None,
88 status_change_type=None, closing_pr=False,
89 send_email=True, renderer=None):
87 f_path=None, line_no=None, status_change=None,
88 status_change_type=None, comment_type=None,
89 resolves_comment_id=None, closing_pr=False, send_email=True,
90 renderer=None):
90 91 """
91 92 Creates new comment for commit or pull request.
92 93 IF status_change is not none this comment is associated with a
@@ -113,6 +114,8 b' class CommentsModel(BaseModel):'
113 114 if not renderer:
114 115 renderer = self._get_renderer()
115 116
117 repo = self._get_repo(repo)
118 user = self._get_user(user)
116 119
117 120 schema = comment_schema.CommentSchema()
118 121 validated_kwargs = schema.deserialize(dict(
@@ -121,15 +124,12 b' class CommentsModel(BaseModel):'
121 124 comment_file=f_path,
122 125 comment_line=line_no,
123 126 renderer_type=renderer,
124 status_change=status_change,
125
126 repo=repo,
127 user=user,
127 status_change=status_change_type,
128 resolves_comment_id=resolves_comment_id,
129 repo=repo.repo_id,
130 user=user.user_id,
128 131 ))
129 132
130 repo = self._get_repo(validated_kwargs['repo'])
131 user = self._get_user(validated_kwargs['user'])
132
133 133 comment = ChangesetComment()
134 134 comment.renderer = validated_kwargs['renderer_type']
135 135 comment.text = validated_kwargs['comment_body']
@@ -139,6 +139,8 b' class CommentsModel(BaseModel):'
139 139
140 140 comment.repo = repo
141 141 comment.author = user
142 comment.resolved_comment = self.__get_commit_comment(
143 validated_kwargs['resolves_comment_id'])
142 144
143 145 pull_request_id = pull_request
144 146
@@ -2917,7 +2917,7 b' class ChangesetComment(Base, BaseModel):'
2917 2917
2918 2918 comment_type = Column('comment_type', Unicode(128), nullable=True, default=COMMENT_TYPE_NOTE)
2919 2919 resolved_comment_id = Column('resolved_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'), nullable=True)
2920 resolved_comment = relationship('ChangesetComment', remote_side=comment_id)
2920 resolved_comment = relationship('ChangesetComment', remote_side=comment_id, backref='resolved_by')
2921 2921 author = relationship('User', lazy='joined')
2922 2922 repo = relationship('Repository')
2923 2923 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
@@ -2959,6 +2959,10 b' class ChangesetComment(Base, BaseModel):'
2959 2959 """
2960 2960 return self.outdated and self.pull_request_version_id != version
2961 2961
2962 @property
2963 def resolved(self):
2964 return self.resolved_by[0] if self.resolved_by else None
2965
2962 2966 def get_index_version(self, versions):
2963 2967 return self.get_index_from_version(
2964 2968 self.pull_request_version_id, versions)
@@ -53,18 +53,22 b" comment_types = ['note', 'todo']"
53 53
54 54
55 55 class CommentSchema(colander.MappingSchema):
56 from rhodecode.model.db import ChangesetComment
56 from rhodecode.model.db import ChangesetComment, ChangesetStatus
57 57
58 58 comment_body = colander.SchemaNode(colander.String())
59 59 comment_type = colander.SchemaNode(
60 60 colander.String(),
61 validator=colander.OneOf(ChangesetComment.COMMENT_TYPES))
61 validator=colander.OneOf(ChangesetComment.COMMENT_TYPES),
62 missing=ChangesetComment.COMMENT_TYPE_NOTE)
62 63
63 64 comment_file = colander.SchemaNode(colander.String(), missing=None)
64 65 comment_line = colander.SchemaNode(colander.String(), missing=None)
65 status_change = colander.SchemaNode(colander.String(), missing=None)
66 status_change = colander.SchemaNode(
67 colander.String(), missing=None,
68 validator=colander.OneOf([x[0] for x in ChangesetStatus.STATUSES]))
66 69 renderer_type = colander.SchemaNode(colander.String())
67 70
68 # do those ?
71 resolves_comment_id = colander.SchemaNode(colander.Integer(), missing=None)
72
69 73 user = colander.SchemaNode(types.StrOrIntType())
70 74 repo = colander.SchemaNode(types.StrOrIntType())
@@ -66,6 +66,7 b' tr.inline-comments div {'
66 66 white-space: nowrap;
67 67
68 68 text-transform: uppercase;
69 min-width: 40px;
69 70
70 71 &.todo {
71 72 color: @color5;
@@ -366,7 +367,7 b' form.comment-form {'
366 367 display: inline-block;
367 368 }
368 369
369 .comment-button .comment-button-input {
370 .comment-button-input {
370 371 margin-right: 0;
371 372 }
372 373
@@ -37,6 +37,7 b' function registerRCRoutes() {'
37 37 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
38 38 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
39 39 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
40 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
40 41 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
41 42 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
42 43 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
@@ -79,7 +79,7 b' var bindToggleButtons = function() {'
79 79 };
80 80
81 81 var linkifyComments = function(comments) {
82 /* TODO: dan: remove this - it should no longer needed */
82 /* TODO: marcink: remove this - it should no longer needed */
83 83 for (var i = 0; i < comments.length; i++) {
84 84 var comment_id = $(comments[i]).data('comment-id');
85 85 var prev_comment_id = $(comments[i - 1]).data('comment-id');
@@ -96,6 +96,8 b' var linkifyComments = function(comments)'
96 96 $('#next_c_' + comment_id + " a.arrow_comment_link").attr(
97 97 'href', '#comment-' + next_comment_id).removeClass('disabled');
98 98 }
99 /* TODO(marcink): end removal here */
100
99 101 // place a first link to the total counter
100 102 if (i === 0) {
101 103 $('#inline-comments-counter').attr('href', '#comment-' + comment_id);
@@ -106,10 +108,23 b' var linkifyComments = function(comments)'
106 108
107 109
108 110 /* Comment form for main and inline comments */
109 var CommentForm = (function() {
111
112 (function(mod) {
113 if (typeof exports == "object" && typeof module == "object") // CommonJS
114 module.exports = mod();
115 else // Plain browser env
116 (this || window).CommentForm = mod();
117
118 })(function() {
110 119 "use strict";
111 120
112 function CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions) {
121 function CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId) {
122 if (!(this instanceof CommentForm)) {
123 return new CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId);
124 }
125
126 // bind the element instance to our Form
127 $(formElement).get(0).CommentForm = this;
113 128
114 129 this.withLineNo = function(selector) {
115 130 var lineNo = this.lineNo;
@@ -135,6 +150,9 b' var CommentForm = (function() {'
135 150 this.cancelButton = this.withLineNo('#cancel-btn');
136 151 this.commentType = this.withLineNo('#comment_type');
137 152
153 this.resolvesId = null;
154 this.resolvesActionId = null;
155
138 156 this.cmBox = this.withLineNo('#text');
139 157 this.cm = initCommentBoxCodeMirror(this.cmBox, this.initAutocompleteActions);
140 158
@@ -147,17 +165,38 b' var CommentForm = (function() {'
147 165 this.previewUrl = pyroutes.url('changeset_comment_preview',
148 166 {'repo_name': templateContext.repo_name});
149 167
150 // based on commitId, or pullReuqestId decide where do we submit
168 if (resolvesCommentId){
169 this.resolvesId = '#resolve_comment_{0}'.format(resolvesCommentId);
170 this.resolvesActionId = '#resolve_comment_action_{0}'.format(resolvesCommentId);
171 $(this.commentType).prop('disabled', true);
172 $(this.commentType).addClass('disabled');
173
174 var resolvedInfo = (
175 '<li class="">' +
176 '<input type="hidden" id="resolve_comment_{0}" name="resolve_comment_{0}" value="{0}">' +
177 '<button id="resolve_comment_action_{0}" class="resolve-text btn btn-sm" onclick="return Rhodecode.comments.submitResolution({0})">{1} #{0}</button>' +
178 '</li>'
179 ).format(resolvesCommentId, _gettext('resolve comment'));
180 $(resolvedInfo).insertAfter($(this.commentType).parent());
181 }
182
183 // based on commitId, or pullRequestId decide where do we submit
151 184 // out data
152 185 if (this.commitId){
153 186 this.submitUrl = pyroutes.url('changeset_comment',
154 187 {'repo_name': templateContext.repo_name,
155 188 'revision': this.commitId});
189 this.selfUrl = pyroutes.url('changeset_home',
190 {'repo_name': templateContext.repo_name,
191 'revision': this.commitId});
156 192
157 193 } else if (this.pullRequestId) {
158 194 this.submitUrl = pyroutes.url('pullrequest_comment',
159 195 {'repo_name': templateContext.repo_name,
160 196 'pull_request_id': this.pullRequestId});
197 this.selfUrl = pyroutes.url('pullrequest_show',
198 {'repo_name': templateContext.repo_name,
199 'pull_request_id': this.pullRequestId});
161 200
162 201 } else {
163 202 throw new Error(
@@ -168,6 +207,13 b' var CommentForm = (function() {'
168 207 return this.cm
169 208 };
170 209
210 this.setPlaceholder = function(placeholder) {
211 var cm = this.getCmInstance();
212 if (cm){
213 cm.setOption('placeholder', placeholder);
214 }
215 };
216
171 217 var self = this;
172 218
173 219 this.getCommentStatus = function() {
@@ -176,6 +222,15 b' var CommentForm = (function() {'
176 222 this.getCommentType = function() {
177 223 return $(this.submitForm).find(this.commentType).val();
178 224 };
225
226 this.getResolvesId = function() {
227 return $(this.submitForm).find(this.resolvesId).val() || null;
228 };
229 this.markCommentResolved = function(resolvedCommentId){
230 $('#comment-label-{0}'.format(resolvedCommentId)).find('.resolved').show();
231 $('#comment-label-{0}'.format(resolvedCommentId)).find('.resolve').hide();
232 };
233
179 234 this.isAllowedToSubmit = function() {
180 235 return !$(this.submitButton).prop('disabled');
181 236 };
@@ -205,12 +260,12 b' var CommentForm = (function() {'
205 260 });
206 261 $(this.submitForm).find(this.statusChange).on('change', function() {
207 262 var status = self.getCommentStatus();
208 if (status && !self.lineNo) {
263 if (status && self.lineNo == 'general') {
209 264 $(self.submitButton).prop('disabled', false);
210 265 }
211 //todo, fix this name
266
212 267 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
213 self.cm.setOption('placeholder', placeholderText);
268 self.setPlaceholder(placeholderText)
214 269 })
215 270 };
216 271
@@ -260,6 +315,7 b' var CommentForm = (function() {'
260 315 var text = self.cm.getValue();
261 316 var status = self.getCommentStatus();
262 317 var commentType = self.getCommentType();
318 var resolvesCommentId = self.getResolvesId();
263 319
264 320 if (text === "" && !status) {
265 321 return;
@@ -275,7 +331,9 b' var CommentForm = (function() {'
275 331 'comment_type': commentType,
276 332 'csrf_token': CSRF_TOKEN
277 333 };
278
334 if (resolvesCommentId){
335 postData['resolves_comment_id'] = resolvesCommentId;
336 }
279 337 var submitSuccessCallback = function(o) {
280 338 if (status) {
281 339 location.reload(true);
@@ -284,10 +342,15 b' var CommentForm = (function() {'
284 342 self.resetCommentFormState();
285 343 bindDeleteCommentButtons();
286 344 timeagoActivate();
345
346 //mark visually which comment was resolved
347 if (resolvesCommentId) {
348 this.markCommentResolved(resolvesCommentId);
349 }
287 350 }
288 351 };
289 352 var submitFailCallback = function(){
290 self.resetCommentFormState(text)
353 self.resetCommentFormState(text);
291 354 };
292 355 self.submitAjaxPOST(
293 356 self.submitUrl, postData, submitSuccessCallback, submitFailCallback);
@@ -367,7 +430,7 b' var CommentForm = (function() {'
367 430
368 431 var postData = {
369 432 'text': text,
370 'renderer': DEFAULT_RENDERER,
433 'renderer': templateContext.visual.default_renderer,
371 434 'csrf_token': CSRF_TOKEN
372 435 };
373 436
@@ -404,15 +467,17 b' var CommentForm = (function() {'
404 467 }
405 468
406 469 return CommentForm;
407 })();
470 });
408 471
409 var CommentsController = function() { /* comments controller */
472 /* comments controller */
473 var CommentsController = function() {
474 var mainComment = '#text';
410 475 var self = this;
411 476
412 477 this.cancelComment = function(node) {
413 478 var $node = $(node);
414 479 var $td = $node.closest('td');
415 $node.closest('.comment-inline-form').removeClass('comment-inline-form-open');
480 $node.closest('.comment-inline-form').remove();
416 481 return false;
417 482 };
418 483
@@ -530,7 +595,8 b' var CommentsController = function() { /*'
530 595 $node.closest('tr').toggleClass('hide-line-comments');
531 596 };
532 597
533 this.createComment = function(node) {
598 this.createComment = function(node, resolutionComment) {
599 var resolvesCommentId = resolutionComment || null;
534 600 var $node = $(node);
535 601 var $td = $node.closest('td');
536 602 var $form = $td.find('.comment-inline-form');
@@ -556,14 +622,16 b' var CommentsController = function() { /*'
556 622
557 623 var pullRequestId = templateContext.pull_request_data.pull_request_id;
558 624 var commitId = templateContext.commit_data.commit_id;
559 var _form = $form[0];
560 var commentForm = new CommentForm(_form, commitId, pullRequestId, lineno, false);
625 var _form = $($form[0]).find('form');
626
627 var commentForm = new CommentForm(_form, commitId, pullRequestId, lineno, false, resolvesCommentId);
561 628 var cm = commentForm.getCmInstance();
562 629
563 630 // set a CUSTOM submit handler for inline comments.
564 631 commentForm.setHandleFormSubmit(function(o) {
565 632 var text = commentForm.cm.getValue();
566 633 var commentType = commentForm.getCommentType();
634 var resolvesCommentId = commentForm.getResolvesId();
567 635
568 636 if (text === "") {
569 637 return;
@@ -589,6 +657,10 b' var CommentsController = function() { /*'
589 657 'comment_type': commentType,
590 658 'csrf_token': CSRF_TOKEN
591 659 };
660 if (resolvesCommentId){
661 postData['resolves_comment_id'] = resolvesCommentId;
662 }
663
592 664 var submitSuccessCallback = function(json_data) {
593 665 $form.remove();
594 666 try {
@@ -598,6 +670,11 b' var CommentsController = function() { /*'
598 670
599 671 $comments.find('.cb-comment-add-button').before(html);
600 672
673 //mark visually which comment was resolved
674 if (resolvesCommentId) {
675 commentForm.markCommentResolved(resolvesCommentId);
676 }
677
601 678 } catch (e) {
602 679 console.error(e);
603 680 }
@@ -616,10 +693,17 b' var CommentsController = function() { /*'
616 693 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
617 694 });
618 695
696 if (resolvesCommentId){
697 var placeholderText = _gettext('Leave a comment, or click resolve button to resolve TODO comment #{0}').format(resolvesCommentId);
698
699 } else {
700 var placeholderText = _gettext('Leave a comment on line {0}.').format(lineno);
701 }
702
619 703 setTimeout(function() {
620 704 // callbacks
621 705 if (cm !== undefined) {
622 cm.setOption('placeholder', _gettext('Leave a comment on line {0}.').format(lineno));
706 commentForm.setPlaceholder(placeholderText);
623 707 cm.focus();
624 708 cm.refresh();
625 709 }
@@ -631,11 +715,59 b' var CommentsController = function() { /*'
631 715 lineno: lineno,
632 716 f_path: f_path}
633 717 );
718
719 // trigger hash
720 if (resolvesCommentId){
721 var resolveAction = $(commentForm.resolvesActionId);
722 setTimeout(function() {
723 $('body, html').animate({ scrollTop: resolveAction.offset().top }, 10);
724 }, 100);
725 }
634 726 }
635 727
636 728 $form.addClass('comment-inline-form-open');
637 729 };
638 730
731 this.createResolutionComment = function(commentId){
732 // hide the trigger text
733 $('#resolve-comment-{0}'.format(commentId)).hide();
734
735 var comment = $('#comment-'+commentId);
736 var commentData = comment.data();
737
738 if (commentData.commentInline) {
739 var resolutionComment = true;
740 this.createComment(comment, commentId)
741 } else {
742
743 this.createComment(comment, commentId)
744
745 console.log('TODO')
746 console.log(commentId)
747 }
748
749 return false;
750 };
751
752 this.submitResolution = function(commentId){
753 var form = $('#resolve_comment_{0}'.format(commentId)).closest('form');
754 var commentForm = form.get(0).CommentForm;
755
756 var cm = commentForm.getCmInstance();
757 var renderer = templateContext.visual.default_renderer;
758 if (renderer == 'rst'){
759 var commentUrl = '`#{0} <{1}#comment-{0}>`_'.format(commentId, commentForm.selfUrl);
760 } else if (renderer == 'markdown') {
761 var commentUrl = '[#{0}]({1}#comment-{0})'.format(commentId, commentForm.selfUrl);
762 } else {
763 var commentUrl = '{1}#comment-{0}'.format(commentId, commentForm.selfUrl);
764 }
765
766 cm.setValue(_gettext('TODO from comment {0} was fixed.').format(commentUrl));
767 form.submit();
768 return false;
769 };
770
639 771 this.renderInlineComments = function(file_comments) {
640 772 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
641 773
@@ -15,12 +15,33 b''
15 15 id="comment-${comment.comment_id}"
16 16 line="${comment.line_no}"
17 17 data-comment-id="${comment.comment_id}"
18 data-comment-type="${comment.comment_type}"
19 data-comment-inline=${h.json.dumps(inline)}
18 20 style="${'display: none;' if outdated_at_ver else ''}">
19 21
20 22 <div class="meta">
21 <div class="comment-type-label tooltip">
22 <div class="comment-label ${comment.comment_type or 'note'}">
23 <div class="comment-type-label">
24 <div class="comment-label ${comment.comment_type or 'note'}" id="comment-label-${comment.comment_id}">
25 % if comment.comment_type == 'todo':
26 % if comment.resolved:
27 <div class="resolved tooltip" title="${_('Resolved by comment #{}').format(comment.resolved.comment_id)}">
28 <a href="#comment-${comment.resolved.comment_id}">${comment.comment_type}</a>
29 </div>
30 % else:
31 <div class="resolved tooltip" style="display: none">
32 <span>${comment.comment_type}</span>
33 </div>
34 <div class="resolve tooltip" onclick="return Rhodecode.comments.createResolutionComment(${comment.comment_id});" title="${_('Click to resolve this comment')}">
35 ${comment.comment_type}
36 </div>
37 % endif
38 % else:
39 % if comment.resolved_comment:
40 fix
41 % else:
23 42 ${comment.comment_type or 'note'}
43 % endif
44 % endif
24 45 </div>
25 46 </div>
26 47
@@ -120,6 +141,7 b''
120 141
121 142 </div>
122 143 </%def>
144
123 145 ## generate main comments
124 146 <%def name="generate_comments(include_pull_request=False, is_pull_request=False)">
125 147 <div id="comments">
@@ -137,16 +159,10 b''
137 159 </div>
138 160 </%def>
139 161
140 ## MAIN COMMENT FORM
162
141 163 <%def name="comments(post_url, cur_status, is_pull_request=False, is_compare=False, change_status=True, form_extras=None)">
142 164
143 %if is_compare:
144 <% form_id = "comments_form_compare" %>
145 %else:
146 <% form_id = "comments_form" %>
147 %endif
148
149
165 ## merge status, and merge action
150 166 %if is_pull_request:
151 167 <div class="pull-request-merge">
152 168 %if c.allowed_to_merge:
@@ -168,6 +184,7 b''
168 184 %endif
169 185 </div>
170 186 %endif
187
171 188 <div class="comments">
172 189 <%
173 190 if is_pull_request:
@@ -177,78 +194,28 b''
177 194 else:
178 195 placeholder = _('Leave a comment on this Commit.')
179 196 %>
197
180 198 % if c.rhodecode_user.username != h.DEFAULT_USER:
181 199 <div class="comment-form ac">
182 ${h.secure_form(post_url, id_=form_id)}
183 <div class="comment-area">
184 <div class="comment-area-header">
185 <ul class="nav-links clearfix">
186 <li class="active">
187 <a href="#edit-btn" tabindex="-1" id="edit-btn">${_('Write')}</a>
188 </li>
189 <li class="">
190 <a href="#preview-btn" tabindex="-1" id="preview-btn">${_('Preview')}</a>
191 </li>
192 <li class="pull-right">
193 <select class="comment-type" id="comment_type" name="comment_type">
194 % for val in c.visual.comment_types:
195 <option value="${val}">${val.upper()}</option>
196 % endfor
197 </select>
198 </li>
199 </ul>
200 ## inject form here
201 ${comment_form(form_type='general', form_id='general_comment', lineno_id='general', review_statuses=c.commit_statuses, form_extras=form_extras)}
200 202 </div>
201
202 <div class="comment-area-write" style="display: block;">
203 <div id="edit-container">
204 <textarea id="text" name="text" class="comment-block-ta ac-input"></textarea>
205 </div>
206 <div id="preview-container" class="clearfix" style="display: none;">
207 <div id="preview-box" class="preview-box"></div>
208 </div>
209 </div>
203 <script type="text/javascript">
204 // init active elements of commentForm
205 var commitId = templateContext.commit_data.commit_id;
206 var pullRequestId = templateContext.pull_request_data.pull_request_id;
207 var lineNo = 'general';
208 var resolvesCommitId = null;
210 209
211 <div class="comment-area-footer">
212 <div class="toolbar">
213 <div class="toolbar-text">
214 ${(_('Comments parsed using %s syntax with %s support.') % (
215 ('<a href="%s">%s</a>' % (h.url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper())),
216 ('<span class="tooltip" title="%s">@mention</span>' % _('Use @username inside this text to send notification to this RhodeCode user'))
217 )
218 )|n}
219 </div>
220 </div>
221 </div>
222 </div>
210 var mainCommentForm = new CommentForm(
211 "#general_comment", commitId, pullRequestId, lineNo, true, resolvesCommitId);
212 mainCommentForm.setPlaceholder("${placeholder}");
213 mainCommentForm.initStatusChangeSelector();
214 </script>
223 215
224 <div id="comment_form_extras">
225 %if form_extras and isinstance(form_extras, (list, tuple)):
226 % for form_ex_el in form_extras:
227 ${form_ex_el|n}
228 % endfor
229 %endif
230 </div>
231 <div class="comment-footer">
232 %if change_status:
233 <div class="status_box">
234 <select id="change_status" name="changeset_status">
235 <option></option> # Placeholder
236 %for status,lbl in c.commit_statuses:
237 <option value="${status}" data-status="${status}">${lbl}</option>
238 %if is_pull_request and change_status and status in ('approved', 'rejected'):
239 <option value="${status}_closed" data-status="${status}">${lbl} & ${_('Closed')}</option>
240 %endif
241 %endfor
242 </select>
243 </div>
244 %endif
245 <div class="action-buttons">
246 <div class="comment-button">${h.submit('save', _('Comment'), class_="btn btn-success comment-button-input")}</div>
247 </div>
248 </div>
249 ${h.end_form()}
250 </div>
216
251 217 % else:
218 ## form state when not logged in
252 219 <div class="comment-form ac">
253 220
254 221 <div class="comment-area">
@@ -289,22 +256,98 b''
289 256 </div>
290 257 % endif
291 258
259 <script type="text/javascript">
260 bindToggleButtons();
261 </script>
262 </div>
263 </%def>
264
265
266 <%def name="comment_form(form_type, form_id='', lineno_id='{1}', review_statuses=None, form_extras=None)">
267 ## comment injected based on assumption that user is logged in
268
269 <form ${'id="{}"'.format(form_id) if form_id else '' |n} action="#" method="GET">
270
271 <div class="comment-area">
272 <div class="comment-area-header">
273 <ul class="nav-links clearfix">
274 <li class="active">
275 <a href="#edit-btn" tabindex="-1" id="edit-btn_${lineno_id}">${_('Write')}</a>
276 </li>
277 <li class="">
278 <a href="#preview-btn" tabindex="-1" id="preview-btn_${lineno_id}">${_('Preview')}</a>
279 </li>
280 <li class="pull-right">
281 <select class="comment-type" id="comment_type_${lineno_id}" name="comment_type">
282 % for val in c.visual.comment_types:
283 <option value="${val}">${val.upper()}</option>
284 % endfor
285 </select>
286 </li>
287 </ul>
288 </div>
289
290 <div class="comment-area-write" style="display: block;">
291 <div id="edit-container_${lineno_id}">
292 <textarea id="text_${lineno_id}" name="text" class="comment-block-ta ac-input"></textarea>
293 </div>
294 <div id="preview-container_${lineno_id}" class="clearfix" style="display: none;">
295 <div id="preview-box_${lineno_id}" class="preview-box"></div>
296 </div>
292 297 </div>
293 298
294 <script>
295 // init active elements of commentForm
296 var commitId = templateContext.commit_data.commit_id;
297 var pullRequestId = templateContext.pull_request_data.pull_request_id;
298 var lineNo;
299 <div class="comment-area-footer">
300 <div class="toolbar">
301 <div class="toolbar-text">
302 ${(_('Comments parsed using %s syntax with %s support.') % (
303 ('<a href="%s">%s</a>' % (h.url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper())),
304 ('<span class="tooltip" title="%s">@mention</span>' % _('Use @username inside this text to send notification to this RhodeCode user'))
305 )
306 )|n}
307 </div>
308 </div>
309 </div>
310 </div>
299 311
300 var mainCommentForm = new CommentForm(
301 "#${form_id}", commitId, pullRequestId, lineNo, true);
312 <div class="comment-footer">
302 313
303 if (mainCommentForm.cm){
304 mainCommentForm.cm.setOption('placeholder', "${placeholder}");
305 }
314 % if review_statuses:
315 <div class="status_box">
316 <select id="change_status" name="changeset_status">
317 <option></option> ## Placeholder
318 % for status, lbl in review_statuses:
319 <option value="${status}" data-status="${status}">${lbl}</option>
320 %if is_pull_request and change_status and status in ('approved', 'rejected'):
321 <option value="${status}_closed" data-status="${status}">${lbl} & ${_('Closed')}</option>
322 %endif
323 % endfor
324 </select>
325 </div>
326 % endif
306 327
307 mainCommentForm.initStatusChangeSelector();
308 bindToggleButtons();
309 </script>
310 </%def>
328 ## inject extra inputs into the form
329 % if form_extras and isinstance(form_extras, (list, tuple)):
330 <div id="comment_form_extras">
331 % for form_ex_el in form_extras:
332 ${form_ex_el|n}
333 % endfor
334 </div>
335 % endif
336
337 <div class="action-buttons">
338 ## inline for has a file, and line-number together with cancel hide button.
339 % if form_type == 'inline':
340 <input type="hidden" name="f_path" value="{0}">
341 <input type="hidden" name="line" value="${lineno_id}">
342 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
343 ${_('Cancel')}
344 </button>
345 % endif
346 ${h.submit('save', _('Comment'), class_='btn btn-success comment-button-input')}
347
348 </div>
349 </div>
350
351 </form>
352
353 </%def> No newline at end of file
@@ -1,3 +1,5 b''
1 <%namespace name="commentblock" file="/changeset/changeset_file_comment.mako"/>
2
1 3 <%def name="diff_line_anchor(filename, line, type)"><%
2 4 return '%s_%s_%i' % (h.safeid(filename), type, line)
3 5 %></%def>
@@ -60,59 +62,8 b" return h.url('', **new_args)"
60 62 <div class="comment-inline-form ac">
61 63
62 64 %if c.rhodecode_user.username != h.DEFAULT_USER:
63 ${h.form('#', method='get')}
64 <div class="comment-area">
65 <div class="comment-area-header">
66 <ul class="nav-links clearfix">
67 <li class="active">
68 <a href="#edit-btn" tabindex="-1" id="edit-btn_{1}">${_('Write')}</a>
69 </li>
70 <li class="">
71 <a href="#preview-btn" tabindex="-1" id="preview-btn_{1}">${_('Preview')}</a>
72 </li>
73 <li class="pull-right">
74 <select class="comment-type" id="comment_type_{1}" name="comment_type">
75 % for val in c.visual.comment_types:
76 <option value="${val}">${val.upper()}</option>
77 % endfor
78 </select>
79 </li>
80 </ul>
81 </div>
82
83 <div class="comment-area-write" style="display: block;">
84 <div id="edit-container_{1}">
85 <textarea id="text_{1}" name="text" class="comment-block-ta ac-input"></textarea>
86 </div>
87 <div id="preview-container_{1}" class="clearfix" style="display: none;">
88 <div id="preview-box_{1}" class="preview-box"></div>
89 </div>
90 </div>
91
92 <div class="comment-area-footer">
93 <div class="toolbar">
94 <div class="toolbar-text">
95 ${(_('Comments parsed using %s syntax with %s support.') % (
96 ('<a href="%s">%s</a>' % (h.url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper())),
97 ('<span class="tooltip" title="%s">@mention</span>' % _('Use @username inside this text to send notification to this RhodeCode user'))
98 )
99 )|n}
100 </div>
101 </div>
102 </div>
103 </div>
104
105 <div class="comment-footer">
106 <div class="action-buttons">
107 <input type="hidden" name="f_path" value="{0}">
108 <input type="hidden" name="line" value="{1}">
109 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
110 ${_('Cancel')}
111 </button>
112 ${h.submit('save', _('Comment'), class_='btn btn-success save-inline-form')}
113 </div>
114 ${h.end_form()}
115 </div>
65 ## render template for inline comments
66 ${commentblock.comment_form(form_type='inline')}
116 67 %else:
117 68 ${h.form('', class_='inline-form comment-form-login', method='get')}
118 69 <div class="pull-left">
@@ -521,7 +472,6 b' from rhodecode.lib.diffs import NEW_FILE'
521 472 </%def>
522 473
523 474
524 <%namespace name="commentblock" file="/changeset/changeset_file_comment.mako"/>
525 475 <%def name="inline_comments_container(comments)">
526 476 <div class="inline-comments">
527 477 %for comment in comments:
General Comments 0
You need to be logged in to leave comments. Login now