diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py --- a/rhodecode/config/routing.py +++ b/rhodecode/config/routing.py @@ -500,6 +500,11 @@ def make_map(config): controller='changeset', revision='tip', action='comment', conditions=dict(function=check_repo)) + rmap.connect('changeset_comment_preview', + '/{repo_name:.*?}/changeset/comment/preview', + controller='changeset', action='preview_comment', + conditions=dict(function=check_repo, method=["POST"])) + rmap.connect('changeset_comment_delete', '/{repo_name:.*?}/changeset/comment/{comment_id}/delete', controller='changeset', action='delete_comment', diff --git a/rhodecode/controllers/changeset.py b/rhodecode/controllers/changeset.py --- a/rhodecode/controllers/changeset.py +++ b/rhodecode/controllers/changeset.py @@ -37,7 +37,8 @@ from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError import rhodecode.lib.helpers as h -from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator +from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\ + NotAnonymous from rhodecode.lib.base import BaseRepoController, render from rhodecode.lib.utils import action_logger from rhodecode.lib.compat import OrderedDict @@ -320,6 +321,7 @@ class ChangesetController(BaseRepoContro def changeset_download(self, revision): return self.index(revision, method='download') + @NotAnonymous() @jsonify def comment(self, repo_name, revision): status = request.POST.get('changeset_status') @@ -382,6 +384,16 @@ class ChangesetController(BaseRepoContro return data + @NotAnonymous() + def preview_comment(self): + if not request.environ.get('HTTP_X_PARTIAL_XHR'): + raise HTTPBadRequest() + text = request.POST.get('text') + if text: + return h.rst_w_mentions(text) + return '' + + @NotAnonymous() @jsonify def delete_comment(self, repo_name, comment_id): co = ChangesetComment.get(comment_id) diff --git a/rhodecode/public/css/style.css b/rhodecode/public/css/style.css --- a/rhodecode/public/css/style.css +++ b/rhodecode/public/css/style.css @@ -218,6 +218,8 @@ div.options a { a.permalink { visibility: hidden; + position: absolute; + margin: 3px 4px; } a.permalink:hover { @@ -4297,12 +4299,6 @@ div.rst-block pre { clear: both } -.comment-form .clearfix { - background: #EEE; - -webkit-border-radius: 4px; - border-radius: 4px; - padding: 10px; -} div.comment-form { margin-top: 20px; @@ -4324,6 +4320,13 @@ form.comment-form { margin-left: 10px; } +.comment-inline-form .comment-block-ta, +.comment-form .comment-block-ta { + border: 1px solid #ccc; + border-radius: 3px; + box-sizing: border-box; +} + .comment-form-submit { margin-top: 5px; margin-left: 525px; @@ -4338,9 +4341,22 @@ form.comment-form { } .comment-form .comment-help { - padding: 0px 0px 5px 0px; + padding: 5px 5px 5px 5px; color: #666; } +.comment-form .comment-help .preview-btn, +.comment-form .comment-help .edit-btn { + float: right; + margin: -6px 0px 0px 0px; +} + +.comment-form .preview-box.unloaded, +.comment-inline-form .preview-box.unloaded { + height: 50px; + text-align: center; + padding: 20px; + background-color: #fafafa; +} .comment-form .comment-button { padding-top: 5px; @@ -4354,7 +4370,7 @@ form.comment-form { .comment .buttons { float: right; - padding: 2px 2px 0px 0px; + margin: -1px 0px 0px 0px; } @@ -4364,6 +4380,9 @@ form.comment-form { } /** comment inline form **/ +.comment-inline-form { + margin: 4px; +} .comment-inline-form .overlay { display: none; } @@ -4382,11 +4401,13 @@ form.comment-form { margin-top: 5%; } -.comment-inline-form .clearfix { +.comment-inline-form .clearfix, +.comment-form .clearfix { background: #EEE; -webkit-border-radius: 4px; border-radius: 4px; padding: 5px; + margin: 0px; } div.comment-inline-form { @@ -4423,9 +4444,14 @@ form.comment-inline-form { } .comment-inline-form .comment-help { - padding: 0px 0px 2px 0px; - color: #666666; - font-size: 10px; + padding: 5px 5px 5px 5px; + color: #666; +} + +.comment-inline-form .comment-help .preview-btn, +.comment-inline-form .comment-help .edit-btn { + float: right; + margin: -6px 0px 0px 0px; } .comment-inline-form .comment-button { diff --git a/rhodecode/public/js/rhodecode.js b/rhodecode/public/js/rhodecode.js --- a/rhodecode/public/js/rhodecode.js +++ b/rhodecode/public/js/rhodecode.js @@ -865,6 +865,29 @@ var injectInlineForm = function(tr){ ajaxPOST(submit_url, postData, success); }); + + YUE.on('preview-btn_'+lineno, 'click', function(e){ + var _text = YUD.get('text_'+lineno).value; + if(!_text){ + return + } + var post_data = {'text': _text}; + YUD.addClass('preview-box_'+lineno, 'unloaded'); + YUD.get('preview-box_'+lineno).innerHTML = _TM['Loading ...']; + YUD.setStyle('edit-container_'+lineno, 'display', 'none'); + YUD.setStyle('preview-container_'+lineno, 'display', ''); + + var url = pyroutes.url('changeset_comment_preview', {'repo_name': REPO_NAME}); + ajaxPOST(url,post_data,function(o){ + YUD.get('preview-box_'+lineno).innerHTML = o.responseText; + YUD.removeClass('preview-box_'+lineno, 'unloaded'); + }) + }) + YUE.on('edit-btn_'+lineno, 'click', function(e){ + YUD.setStyle('edit-container_'+lineno, 'display', ''); + YUD.setStyle('preview-container_'+lineno, 'display', 'none'); + }) + setTimeout(function(){ // callbacks @@ -886,8 +909,11 @@ var deleteComment = function(comment_id) var root = prevElementSibling(prevElementSibling(n)); n.parentNode.removeChild(n); - // scann nodes, and attach add button to last one - placeAddButton(root); + // scann nodes, and attach add button to last one only for TR + // which are the inline comments + if(root && root.tagName == 'TR'){ + placeAddButton(root); + } } ajaxPOST(url,postData,success); } diff --git a/rhodecode/templates/base/root.html b/rhodecode/templates/base/root.html --- a/rhodecode/templates/base/root.html +++ b/rhodecode/templates/base/root.html @@ -60,6 +60,10 @@ var TOGGLE_FOLLOW_URL = "${h.url('toggle_following')}"; + var REPO_NAME = ""; + %if hasattr(c, 'repo_name'): + var REPO_NAME = "${c.repo_name}"; + %endif