##// END OF EJS Templates
ux: add hidden comments indicators plus style tweaks...
dan -
r1157:ac063abc default
parent child Browse files
Show More
@@ -877,11 +877,17 b' input.filediff-collapse-state {'
877 .show-comment-button {
877 .show-comment-button {
878 display: inline;
878 display: inline;
879 }
879 }
880 .show-comment-button {
880 .hide-comment-button {
881 display: none;
881 display: none;
882 }
882 }
883 }
883 }
884 }
884 }
885
886 .hide-line-comments {
887 .inline-comments {
888 display: none;
889 }
890 }
885 .inline-comments {
891 .inline-comments {
886 border-radius: @border-radius;
892 border-radius: @border-radius;
887 background: @grey6;
893 background: @grey6;
@@ -1037,6 +1043,9 b' table.cb {'
1037 white-space: pre-wrap;
1043 white-space: pre-wrap;
1038 font-family: @font-family-monospace;
1044 font-family: @font-family-monospace;
1039 word-break: break-word;
1045 word-break: break-word;
1046 .nonl {
1047 color: @color5;
1048 }
1040 }
1049 }
1041
1050
1042 &> button.cb-comment-box-opener {
1051 &> button.cb-comment-box-opener {
@@ -1061,6 +1070,22 b' table.cb {'
1061 }
1070 }
1062 }
1071 }
1063
1072
1073 &.cb-data {
1074 text-align: right;
1075 width: 30px;
1076 font-family: @font-family-monospace;
1077
1078 .icon-comment {
1079 cursor: pointer;
1080 }
1081 &.cb-line-selected > div {
1082 display: block;
1083 background: @comment-highlight-color !important;
1084 line-height: @cb-line-height;
1085 color: rgba(0, 0, 0, 0.3);
1086 }
1087 }
1088
1064 &.cb-lineno {
1089 &.cb-lineno {
1065 padding: 0;
1090 padding: 0;
1066 width: 50px;
1091 width: 50px;
@@ -292,6 +292,7 b' function scrollToElement(element, percen'
292 $('.cb-line-selected').removeClass('cb-line-selected');
292 $('.cb-line-selected').removeClass('cb-line-selected');
293 var td = $(this).parent();
293 var td = $(this).parent();
294 td.addClass('cb-line-selected'); // line number td
294 td.addClass('cb-line-selected'); // line number td
295 td.prev().addClass('cb-line-selected'); // line data td
295 td.next().addClass('cb-line-selected'); // line content td
296 td.next().addClass('cb-line-selected'); // line content td
296
297
297 // Replace URL without jumping to it if browser supports.
298 // Replace URL without jumping to it if browser supports.
@@ -475,6 +476,7 b' function scrollToElement(element, percen'
475 }
476 }
476 $.each(highlightable_line_tds, function (i, $td) {
477 $.each(highlightable_line_tds, function (i, $td) {
477 $td.addClass('cb-line-selected'); // line number td
478 $td.addClass('cb-line-selected'); // line number td
479 $td.prev().addClass('cb-line-selected'); // line data
478 $td.next().addClass('cb-line-selected'); // line content
480 $td.next().addClass('cb-line-selected'); // line content
479 });
481 });
480
482
@@ -670,3 +670,228 b' var CommentForm = (function() {'
670
670
671 return CommentForm;
671 return CommentForm;
672 })();
672 })();
673
674 var CommentsController = function() { /* comments controller */
675 var self = this;
676
677 this.cancelComment = function(node) {
678 var $node = $(node);
679 var $td = $node.closest('td');
680 $node.closest('.comment-inline-form').removeClass('comment-inline-form-open');
681 return false;
682 }
683 this.getLineNumber = function(node) {
684 var $node = $(node);
685 return $node.closest('td').attr('data-line-number');
686 }
687 this.scrollToComment = function(node, offset) {
688 if (!node) {
689 node = $('.comment-selected');
690 if (!node.length) {
691 node = $('comment-current')
692 }
693 }
694 $comment = $(node).closest('.comment-current');
695 $comments = $('.comment-current');
696
697 $('.comment-selected').removeClass('comment-selected');
698
699 var nextIdx = $('.comment-current').index($comment) + offset;
700 if (nextIdx >= $comments.length) {
701 nextIdx = 0;
702 }
703 var $next = $('.comment-current').eq(nextIdx);
704 var $cb = $next.closest('.cb');
705 $cb.removeClass('cb-collapsed')
706
707 var $filediffCollapseState = $cb.closest('.filediff').prev();
708 $filediffCollapseState.prop('checked', false);
709 $next.addClass('comment-selected');
710 scrollToElement($next);
711 return false;
712 }
713 this.nextComment = function(node) {
714 return self.scrollToComment(node, 1);
715 }
716 this.prevComment = function(node) {
717 return self.scrollToComment(node, -1);
718 }
719 this.deleteComment = function(node) {
720 if (!confirm(_gettext('Delete this comment?'))) {
721 return false;
722 }
723 var $node = $(node);
724 var $td = $node.closest('td');
725 var $comment = $node.closest('.comment');
726 var comment_id = $comment.attr('data-comment-id');
727 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id);
728 var postData = {
729 '_method': 'delete',
730 'csrf_token': CSRF_TOKEN
731 };
732
733 $comment.addClass('comment-deleting');
734 $comment.hide('fast');
735
736 var success = function(response) {
737 $comment.remove();
738 return false;
739 };
740 var failure = function(data, textStatus, xhr) {
741 alert("error processing request: " + textStatus);
742 $comment.show('fast');
743 $comment.removeClass('comment-deleting');
744 return false;
745 };
746 ajaxPOST(url, postData, success, failure);
747 }
748 this.toggleComments = function(node, show) {
749 var $filediff = $(node).closest('.filediff');
750 if (show === true) {
751 $filediff.removeClass('hide-comments');
752 } else if (show === false) {
753 $filediff.find('.hide-line-comments').removeClass('hide-line-comments');
754 $filediff.addClass('hide-comments');
755 } else {
756 $filediff.find('.hide-line-comments').removeClass('hide-line-comments');
757 $filediff.toggleClass('hide-comments');
758 }
759 return false;
760 }
761 this.toggleLineComments = function(node) {
762 self.toggleComments(node, true);
763 var $node = $(node);
764 $node.closest('tr').toggleClass('hide-line-comments');
765 }
766 this.createComment = function(node) {
767 var $node = $(node);
768 var $td = $node.closest('td');
769 var $form = $td.find('.comment-inline-form');
770
771 if (!$form.length) {
772 var tmpl = $('#cb-comment-inline-form-template').html();
773 var $filediff = $node.closest('.filediff');
774 $filediff.removeClass('hide-comments');
775 var f_path = $filediff.attr('data-f-path');
776 var lineno = self.getLineNumber(node);
777 tmpl = tmpl.format(f_path, lineno);
778 $form = $(tmpl);
779
780 var $comments = $td.find('.inline-comments');
781 if (!$comments.length) {
782 $comments = $(
783 $('#cb-comments-inline-container-template').html());
784 $td.append($comments);
785 }
786
787 $td.find('.cb-comment-add-button').before($form);
788
789 var pullRequestId = templateContext.pull_request_data.pull_request_id;
790 var commitId = templateContext.commit_data.commit_id;
791 var _form = $form[0];
792 var commentForm = new CommentForm(_form, commitId, pullRequestId, lineno, false);
793 var cm = commentForm.getCmInstance();
794
795 // set a CUSTOM submit handler for inline comments.
796 commentForm.setHandleFormSubmit(function(o) {
797 var text = commentForm.cm.getValue();
798
799 if (text === "") {
800 return;
801 }
802
803 if (lineno === undefined) {
804 alert('missing line !');
805 return;
806 }
807 if (f_path === undefined) {
808 alert('missing file path !');
809 return;
810 }
811
812 var excludeCancelBtn = false;
813 var submitEvent = true;
814 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
815 commentForm.cm.setOption("readOnly", true);
816 var postData = {
817 'text': text,
818 'f_path': f_path,
819 'line': lineno,
820 'csrf_token': CSRF_TOKEN
821 };
822 var submitSuccessCallback = function(json_data) {
823 $form.remove();
824 console.log(json_data)
825 try {
826 var html = json_data.rendered_text;
827 var lineno = json_data.line_no;
828 var target_id = json_data.target_id;
829
830 $comments.find('.cb-comment-add-button').before(html);
831 console.log(lineno, target_id, $comments);
832
833 } catch (e) {
834 console.error(e);
835 }
836
837
838 // re trigger the linkification of next/prev navigation
839 linkifyComments($('.inline-comment-injected'));
840 timeagoActivate();
841 bindDeleteCommentButtons();
842 commentForm.setActionButtonsDisabled(false);
843
844 };
845 var submitFailCallback = function(){
846 commentForm.resetCommentFormState(text)
847 };
848 commentForm.submitAjaxPOST(
849 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
850 });
851
852 setTimeout(function() {
853 // callbacks
854 if (cm !== undefined) {
855 cm.focus();
856 }
857 }, 10);
858
859 $.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({
860 form: _form,
861 parent: $td[0],
862 lineno: lineno,
863 f_path: f_path}
864 );
865 }
866
867 $form.addClass('comment-inline-form-open');
868 }
869
870 this.renderInlineComments = function(file_comments) {
871 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
872
873 for (var i = 0; i < file_comments.length; i++) {
874 var box = file_comments[i];
875
876 var target_id = $(box).attr('target_id');
877
878 // actually comments with line numbers
879 var comments = box.children;
880
881 for (var j = 0; j < comments.length; j++) {
882 var data = {
883 'rendered_text': comments[j].outerHTML,
884 'line_no': $(comments[j]).attr('line'),
885 'target_id': target_id
886 };
887 }
888 }
889
890 // since order of injection is random, we're now re-iterating
891 // from correct order and filling in links
892 linkifyComments($('.inline-comment-injected'));
893 bindDeleteCommentButtons();
894 firefoxAnchorFix();
895 };
896
897 } No newline at end of file
@@ -115,217 +115,6 b" c.template_context['visual']['default_re"
115 }
115 }
116 };
116 };
117
117
118
119 Rhodecode = (function() {
120 function _Rhodecode() {
121 this.comments = new (function() { /* comments controller */
122 var self = this;
123
124 this.cancelComment = function(node) {
125 var $node = $(node);
126 var $td = $node.closest('td');
127 $node.closest('.comment-inline-form').removeClass('comment-inline-form-open');
128 return false;
129 }
130 this.getLineNumber = function(node) {
131 var $node = $(node);
132 return $node.closest('td').attr('data-line-number');
133 }
134 this.scrollToComment = function(node, offset) {
135 if (!node) {
136 node = $('.comment-selected');
137 if (!node.length) {
138 node = $('comment-current')
139 }
140 }
141 $comment = $(node).closest('.comment-current');
142 $comments = $('.comment-current');
143
144 $('.comment-selected').removeClass('comment-selected');
145
146 var nextIdx = $('.comment-current').index($comment) + offset;
147 if (nextIdx >= $comments.length) {
148 nextIdx = 0;
149 }
150 var $next = $('.comment-current').eq(nextIdx);
151 var $cb = $next.closest('.cb');
152 $cb.removeClass('cb-collapsed')
153
154 var $filediffCollapseState = $cb.closest('.filediff').prev();
155 $filediffCollapseState.prop('checked', false);
156 $next.addClass('comment-selected');
157 scrollToElement($next);
158 return false;
159 }
160 this.nextComment = function(node) {
161 return self.scrollToComment(node, 1);
162 }
163 this.prevComment = function(node) {
164 return self.scrollToComment(node, -1);
165 }
166 this.deleteComment = function(node) {
167 if (!confirm(_gettext('Delete this comment?'))) {
168 return false;
169 }
170 var $node = $(node);
171 var $td = $node.closest('td');
172 var $comment = $node.closest('.comment');
173 var comment_id = $comment.attr('data-comment-id');
174 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id);
175 var postData = {
176 '_method': 'delete',
177 'csrf_token': CSRF_TOKEN
178 };
179
180 $comment.addClass('comment-deleting');
181 $comment.hide('fast');
182
183 var success = function(response) {
184 $comment.remove();
185 return false;
186 };
187 var failure = function(data, textStatus, xhr) {
188 alert("error processing request: " + textStatus);
189 $comment.show('fast');
190 $comment.removeClass('comment-deleting');
191 return false;
192 };
193 ajaxPOST(url, postData, success, failure);
194 }
195 this.createComment = function(node) {
196 var $node = $(node);
197 var $td = $node.closest('td');
198 var $form = $td.find('.comment-inline-form');
199
200 if (!$form.length) {
201 var tmpl = $('#cb-comment-inline-form-template').html();
202 var f_path = $node.closest('.filediff').attr('data-f-path');
203 var lineno = self.getLineNumber(node);
204 tmpl = tmpl.format(f_path, lineno);
205 $form = $(tmpl);
206
207 var $comments = $td.find('.inline-comments');
208 if (!$comments.length) {
209 $comments = $(
210 $('#cb-comments-inline-container-template').html());
211 $td.append($comments);
212 }
213
214 $td.find('.cb-comment-add-button').before($form);
215
216 var pullRequestId = templateContext.pull_request_data.pull_request_id;
217 var commitId = templateContext.commit_data.commit_id;
218 var _form = $form[0];
219 var commentForm = new CommentForm(_form, commitId, pullRequestId, lineno, false);
220 var cm = commentForm.getCmInstance();
221
222 // set a CUSTOM submit handler for inline comments.
223 commentForm.setHandleFormSubmit(function(o) {
224 var text = commentForm.cm.getValue();
225
226 if (text === "") {
227 return;
228 }
229
230 if (lineno === undefined) {
231 alert('missing line !');
232 return;
233 }
234 if (f_path === undefined) {
235 alert('missing file path !');
236 return;
237 }
238
239 var excludeCancelBtn = false;
240 var submitEvent = true;
241 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
242 commentForm.cm.setOption("readOnly", true);
243 var postData = {
244 'text': text,
245 'f_path': f_path,
246 'line': lineno,
247 'csrf_token': CSRF_TOKEN
248 };
249 var submitSuccessCallback = function(json_data) {
250 $form.remove();
251 console.log(json_data)
252 try {
253 var html = json_data.rendered_text;
254 var lineno = json_data.line_no;
255 var target_id = json_data.target_id;
256
257 $comments.find('.cb-comment-add-button').before(html);
258 console.log(lineno, target_id, $comments);
259
260 } catch (e) {
261 console.error(e);
262 }
263
264
265 // re trigger the linkification of next/prev navigation
266 linkifyComments($('.inline-comment-injected'));
267 timeagoActivate();
268 bindDeleteCommentButtons();
269 commentForm.setActionButtonsDisabled(false);
270
271 };
272 var submitFailCallback = function(){
273 commentForm.resetCommentFormState(text)
274 };
275 commentForm.submitAjaxPOST(
276 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
277 });
278
279 setTimeout(function() {
280 // callbacks
281 if (cm !== undefined) {
282 cm.focus();
283 }
284 }, 10);
285
286 $.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({
287 form: _form,
288 parent: $td[0],
289 lineno: lineno,
290 f_path: f_path}
291 );
292 }
293
294 $form.addClass('comment-inline-form-open');
295 }
296
297 this.renderInlineComments = function(file_comments) {
298 show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true;
299
300 for (var i = 0; i < file_comments.length; i++) {
301 var box = file_comments[i];
302
303 var target_id = $(box).attr('target_id');
304
305 // actually comments with line numbers
306 var comments = box.children;
307
308 for (var j = 0; j < comments.length; j++) {
309 var data = {
310 'rendered_text': comments[j].outerHTML,
311 'line_no': $(comments[j]).attr('line'),
312 'target_id': target_id
313 };
314 }
315 }
316
317 // since order of injection is random, we're now re-iterating
318 // from correct order and filling in links
319 linkifyComments($('.inline-comment-injected'));
320 bindDeleteCommentButtons();
321 firefoxAnchorFix();
322 };
323
324 })();
325 }
326 return new _Rhodecode();
327 })();
328
329 </script>
118 </script>
330 <%include file="/base/plugins_base.html"/>
119 <%include file="/base/plugins_base.html"/>
331 <!--[if lt IE 9]>
120 <!--[if lt IE 9]>
@@ -342,6 +131,13 b' Rhodecode = (function() {'
342 ${self.js_extra()}
131 ${self.js_extra()}
343
132
344 <script type="text/javascript">
133 <script type="text/javascript">
134 Rhodecode = (function() {
135 function _Rhodecode() {
136 this.comments = new CommentsController();
137 }
138 return new _Rhodecode();
139 })();
140
345 $(document).ready(function(){
141 $(document).ready(function(){
346 show_more_event();
142 show_more_event();
347 timeagoActivate();
143 timeagoActivate();
@@ -192,7 +192,7 b' collapse_all = len(diffset.files) > coll'
192 %endif
192 %endif
193 %if over_lines_changed_limit:
193 %if over_lines_changed_limit:
194 <tr class="cb-warning cb-collapser">
194 <tr class="cb-warning cb-collapser">
195 <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}>
195 <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=4' or 'colspan=4'}>
196 ${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)}
196 ${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)}
197 <a href="#" class="cb-expand"
197 <a href="#" class="cb-expand"
198 onclick="$(this).closest('table').removeClass('cb-collapsed'); return false;">${_('Show them')}
198 onclick="$(this).closest('table').removeClass('cb-collapsed'); return false;">${_('Show them')}
@@ -205,20 +205,20 b' collapse_all = len(diffset.files) > coll'
205 %endif
205 %endif
206 %if filediff.patch['is_limited_diff']:
206 %if filediff.patch['is_limited_diff']:
207 <tr class="cb-warning cb-collapser">
207 <tr class="cb-warning cb-collapser">
208 <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}>
208 <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=4' or 'colspan=4'}>
209 ${_('The requested commit is too big and content was truncated.')} <a href="${link_for(fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
209 ${_('The requested commit is too big and content was truncated.')} <a href="${link_for(fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
210 </td>
210 </td>
211 </tr>
211 </tr>
212 %endif
212 %endif
213 %for hunk in filediff.hunks:
213 %for hunk in filediff.hunks:
214 <tr class="cb-hunk">
214 <tr class="cb-hunk">
215 <td ${c.diffmode == 'unified' and 'colspan=2' or ''}>
215 <td ${c.diffmode == 'unified' and 'colspan=3' or ''}>
216 ## TODO: dan: add ajax loading of more context here
216 ## TODO: dan: add ajax loading of more context here
217 ## <a href="#">
217 ## <a href="#">
218 <i class="icon-more"></i>
218 <i class="icon-more"></i>
219 ## </a>
219 ## </a>
220 </td>
220 </td>
221 <td ${c.diffmode == 'sideside' and 'colspan=3' or ''}>
221 <td ${c.diffmode == 'sideside' and 'colspan=5' or ''}>
222 @@
222 @@
223 -${hunk.source_start},${hunk.source_length}
223 -${hunk.source_start},${hunk.source_length}
224 +${hunk.target_start},${hunk.target_length}
224 +${hunk.target_start},${hunk.target_length}
@@ -377,7 +377,7 b' from rhodecode.lib.diffs import NEW_FILE'
377
377
378
378
379 %if use_comments:
379 %if use_comments:
380 <a href="#" onclick="$(this).closest('.filediff').toggleClass('hide-comments'); return false;">
380 <a href="#" onclick="return Rhodecode.comments.toggleComments(this);">
381 <span class="show-comment-button">${_('Show comments')}</span><span class="hide-comment-button">${_('Hide comments')}</span>
381 <span class="show-comment-button">${_('Show comments')}</span><span class="hide-comment-button">${_('Hide comments')}</span>
382 </a>
382 </a>
383 %endif
383 %endif
@@ -410,6 +410,15 b' from rhodecode.lib.diffs import NEW_FILE'
410 new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, line.modified.lineno, 'n')
410 new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, line.modified.lineno, 'n')
411 %>
411 %>
412 <tr class="cb-line">
412 <tr class="cb-line">
413 <td class="cb-data ${action_class(line.original.action)}"
414 data-line-number="${line.original.lineno}"
415 >
416 <div>
417 %if line.original.comments:
418 <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
419 %endif
420 </div>
421 </td>
413 <td class="cb-lineno ${action_class(line.original.action)}"
422 <td class="cb-lineno ${action_class(line.original.action)}"
414 data-line-number="${line.original.lineno}"
423 data-line-number="${line.original.lineno}"
415 %if old_line_anchor:
424 %if old_line_anchor:
@@ -431,6 +440,15 b' from rhodecode.lib.diffs import NEW_FILE'
431 ${inline_comments_container(line.original.comments)}
440 ${inline_comments_container(line.original.comments)}
432 %endif
441 %endif
433 </td>
442 </td>
443 <td class="cb-data ${action_class(line.modified.action)}"
444 data-line-number="${line.modified.lineno}"
445 >
446 <div>
447 %if line.modified.comments:
448 <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
449 %endif
450 </div>
451 </td>
434 <td class="cb-lineno ${action_class(line.modified.action)}"
452 <td class="cb-lineno ${action_class(line.modified.action)}"
435 data-line-number="${line.modified.lineno}"
453 data-line-number="${line.modified.lineno}"
436 %if new_line_anchor:
454 %if new_line_anchor:
@@ -467,6 +485,13 b' from rhodecode.lib.diffs import NEW_FILE'
467 new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, new_line_no, 'n')
485 new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, new_line_no, 'n')
468 %>
486 %>
469 <tr class="cb-line">
487 <tr class="cb-line">
488 <td class="cb-data ${action_class(action)}">
489 <div>
490 %if comments:
491 <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
492 %endif
493 </div>
494 </td>
470 <td class="cb-lineno ${action_class(action)}"
495 <td class="cb-lineno ${action_class(action)}"
471 data-line-number="${old_line_no}"
496 data-line-number="${old_line_no}"
472 %if old_line_anchor:
497 %if old_line_anchor:
@@ -506,7 +531,7 b' from rhodecode.lib.diffs import NEW_FILE'
506 <button
531 <button
507 class="btn btn-small btn-primary cb-comment-box-opener"
532 class="btn btn-small btn-primary cb-comment-box-opener"
508 onclick="return Rhodecode.comments.createComment(this)"
533 onclick="return Rhodecode.comments.createComment(this)"
509 >+</button>
534 ><span>+</span></button>
510 </%def>
535 </%def>
511
536
512 <%def name="render_diffset_menu()">
537 <%def name="render_diffset_menu()">
General Comments 0
You need to be logged in to leave comments. Login now