# HG changeset patch # User Marcin Kuzminski # Date 2012-04-14 20:13:07 # Node ID b61e540122f2b36e151d1c04b0f1eff54823a7fb # Parent 7b52c2351231d331d8d4753673500dfaaadb4e38 #415: Adding comment to changeset causes reload - comments are now added via ajax and doesn't reload the page diff --git a/rhodecode/controllers/changeset.py b/rhodecode/controllers/changeset.py --- a/rhodecode/controllers/changeset.py +++ b/rhodecode/controllers/changeset.py @@ -359,16 +359,25 @@ class ChangesetController(BaseRepoContro return render('changeset/raw_changeset.html') + @jsonify def comment(self, repo_name, revision): - ChangesetCommentsModel().create(text=request.POST.get('text'), - repo_id=c.rhodecode_db_repo.repo_id, - user_id=c.rhodecode_user.user_id, - revision=revision, - f_path=request.POST.get('f_path'), - line_no=request.POST.get('line')) + comm = ChangesetCommentsModel().create( + text=request.POST.get('text'), + repo_id=c.rhodecode_db_repo.repo_id, + user_id=c.rhodecode_user.user_id, + revision=revision, + f_path=request.POST.get('f_path'), + line_no=request.POST.get('line') + ) Session.commit() - return redirect(h.url('changeset_home', repo_name=repo_name, - revision=revision)) + data = { + 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))), + } + if comm: + c.co = comm + data.update(comm.get_dict()) + data.update({'rendered_text': render('changeset/changeset_comment_block.html')}) + return data @jsonify def delete_comment(self, repo_name, comment_id): diff --git a/rhodecode/model/comment.py b/rhodecode/model/comment.py --- a/rhodecode/model/comment.py +++ b/rhodecode/model/comment.py @@ -142,7 +142,9 @@ class ChangesetCommentsModel(BaseModel): .filter(ChangesetComment.repo_id == repo_id)\ .filter(ChangesetComment.revision == revision)\ .filter(ChangesetComment.line_no != None)\ - .filter(ChangesetComment.f_path != None).all() + .filter(ChangesetComment.f_path != None)\ + .order_by(ChangesetComment.comment_id.asc())\ + .all() paths = defaultdict(lambda: defaultdict(list)) 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 @@ -3966,6 +3966,7 @@ form.comment-form { .comment .buttons { float: right; + padding:2px 2px 0px 0px; } @@ -3975,6 +3976,23 @@ form.comment-form { } /** comment inline form **/ +.comment-inline-form .overlay{ + display: none; +} +.comment-inline-form .overlay.submitting{ + display:block; + background: none repeat scroll 0 0 white; + font-size: 16px; + opacity: 0.5; + position: absolute; + text-align: center; + vertical-align: top; + +} +.comment-inline-form .overlay.submitting .overlay-text{ + width:100%; + margin-top:5%; +} .comment-inline-form .clearfix{ background: #EEE; @@ -3987,6 +4005,7 @@ form.comment-form { div.comment-inline-form { margin-top: 5px; padding:2px 6px 8px 6px; + } .comment-inline-form strong { @@ -4047,6 +4066,10 @@ form.comment-inline-form { margin: 3px 3px 5px 5px; background-color: #FAFAFA; } +.inline-comments .add-comment { + padding: 2px 4px 8px 5px; +} + .inline-comments .comment-wrapp{ padding:1px; } @@ -4078,7 +4101,7 @@ form.comment-inline-form { font-size: 16px; } .inline-comments-button .add-comment{ - margin:10px 5px !important; + margin:2px 0px 8px 5px !important } .notifications{ border-radius: 4px 4px 4px 4px; 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 @@ -195,6 +195,31 @@ function ypjax(url,container,s_call,f_ca }; +var ajaxPOST = function(url,postData,success) { + var toQueryString = function(o) { + if(typeof o !== 'object') { + return false; + } + var _p, _qs = []; + for(_p in o) { + _qs.push(encodeURIComponent(_p) + '=' + encodeURIComponent(o[_p])); + } + return _qs.join('&'); + }; + + var sUrl = url; + var callback = { + success: success, + failure: function (o) { + alert("error"); + }, + }; + var postData = toQueryString(postData); + var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData); + return request; +}; + + /** * tooltip activate */ @@ -300,33 +325,25 @@ var q_filter = function(target,nodes,dis } }; -var ajaxPOST = function(url,postData,success) { - var sUrl = url; - var callback = { - success: success, - failure: function (o) { - alert("error"); - }, - }; - var postData = postData; - var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData); +var tableTr = function(cls,body){ + var tr = document.createElement('tr'); + YUD.addClass(tr, cls); + + + var cont = new YAHOO.util.Element(body); + var comment_id = fromHTML(body).children[0].id.split('comment-')[1]; + tr.id = 'comment-tr-{0}'.format(comment_id); + tr.innerHTML = ''+ + ''+ + '{0}'.format(body); + return tr; }; - /** comments **/ var removeInlineForm = function(form) { form.parentNode.removeChild(form); }; -var tableTr = function(cls,body){ - var form = document.createElement('tr'); - YUD.addClass(form, cls); - form.innerHTML = ''+ - ''+ - '{0}'.format(body); - return form; -}; - var createInlineForm = function(parent_tr, f_path, line) { var tmpl = YUD.get('comment-inline-form-template').innerHTML; tmpl = tmpl.format(f_path, line); @@ -337,12 +354,27 @@ var createInlineForm = function(parent_t var form_hide_button = new YAHOO.util.Element(form.getElementsByClassName('hide-inline-form')[0]); form_hide_button.on('click', function(e) { var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode; + if(YUD.hasClass(newtr.nextElementSibling,'inline-comments-button')){ + YUD.setStyle(newtr.nextElementSibling,'display',''); + } removeInlineForm(newtr); YUD.removeClass(parent_tr, 'form-open'); + }); + return form }; + +/** + * Inject inline comment for on given TR this tr should be always an .line + * tr containing the line. Code will detect comment, and always put the comment + * block at the very bottom + */ var injectInlineForm = function(tr){ + if(!YUD.hasClass(tr, 'line')){ + return + } + var submit_url = AJAX_COMMENT_URL; if(YUD.hasClass(tr,'form-open') || YUD.hasClass(tr,'context') || YUD.hasClass(tr,'no-comment')){ return } @@ -350,20 +382,92 @@ var injectInlineForm = function(tr){ var node = tr.parentNode.parentNode.parentNode.getElementsByClassName('full_f_path')[0]; var f_path = YUD.getAttribute(node,'path'); var lineno = getLineNo(tr); - var form = createInlineForm(tr, f_path, lineno); - var target_tr = tr; - if(YUD.hasClass(YUD.getNextSibling(tr),'inline-comments')){ - target_tr = YUD.getNextSibling(tr); - } - YUD.insertAfter(form,target_tr); + var form = createInlineForm(tr, f_path, lineno, submit_url); + + var parent = tr; + while (1){ + var n = parent.nextElementSibling; + // next element are comments ! + if(YUD.hasClass(n,'inline-comments')){ + parent = n; + } + else{ + break; + } + } + YUD.insertAfter(form,parent); + YUD.get('text_'+lineno).focus(); + var f = YUD.get(form); + + var overlay = f.getElementsByClassName('overlay')[0]; + var _form = f.getElementsByClassName('inline-form')[0]; + + form.on('submit',function(e){ + YUE.preventDefault(e); + + //ajax submit + var text = YUD.get('text_'+lineno).value; + var postData = { + 'text':text, + 'f_path':f_path, + 'line':lineno + }; + + if(lineno === undefined){ + alert('missing line !'); + return + } + if(f_path === undefined){ + alert('missing file path !'); + return + } + + var success = function(o){ + YUD.removeClass(tr, 'form-open'); + removeInlineForm(f); + var json_data = JSON.parse(o.responseText); + renderInlineComment(json_data); + }; + + if (YUD.hasClass(overlay,'overlay')){ + var w = _form.offsetWidth; + var h = _form.offsetHeight; + YUD.setStyle(overlay,'width',w+'px'); + YUD.setStyle(overlay,'height',h+'px'); + } + YUD.addClass(overlay, 'submitting'); + + ajaxPOST(submit_url, postData, success); + }); + tooltip_activate(); }; -var createInlineAddButton = function(tr,label){ - var html = '
{0}
'.format(label); - - var add = new YAHOO.util.Element(tableTr('inline-comments-button',html)); +var deleteComment = function(comment_id){ + var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__',comment_id); + var postData = {'_method':'delete'}; + var success = function(o){ + var n = YUD.get('comment-tr-'+comment_id); + var root = n.previousElementSibling.previousElementSibling; + n.parentNode.removeChild(n); + + // scann nodes, and attach add button to last one + placeAddButton(root); + } + ajaxPOST(url,postData,success); +} + + +var createInlineAddButton = function(tr){ + + var label = TRANSLATION_MAP['add another comment']; + + var html_el = document.createElement('div'); + YUD.addClass(html_el, 'add-comment'); + html_el.innerHTML = '{0}'.format(label); + + var add = new YAHOO.util.Element(html_el); add.on('click', function(e) { injectInlineForm(tr); }); @@ -384,6 +488,103 @@ var getLineNo = function(tr) { return line }; +var placeAddButton = function(target_tr){ + if(!target_tr){ + return + } + var last_node = target_tr; + //scann + while (1){ + var n = last_node.nextElementSibling; + // next element are comments ! + if(YUD.hasClass(n,'inline-comments')){ + last_node = n; + //also remove the comment button from previos + var comment_add_buttons = last_node.getElementsByClassName('add-comment'); + for(var i=0;i var follow_base_url = "${h.url('toggle_following')}"; - var stop_follow_text = "${_('Stop following this repository')}"; - var start_follow_text = "${_('Start following this repository')}"; - + + //JS translations map + var TRANSLATION_MAP = { + 'add another comment':'${_("add another comment")}', + 'Stop following this repository':"${_('Stop following this repository')}", + 'Start following this repository':"${_('Start following this repository')}", + }; var onSuccessFollow = function(target){ var f = YUD.get(target.id); @@ -57,7 +61,7 @@ if(f.getAttribute('class')=='follow'){ f.setAttribute('class','following'); - f.setAttribute('title',stop_follow_text); + f.setAttribute('title',TRANSLATION_MAP['Stop following this repository']); if(f_cnt){ var cnt = Number(f_cnt.innerHTML)+1; @@ -66,7 +70,7 @@ } else{ f.setAttribute('class','follow'); - f.setAttribute('title',start_follow_text); + f.setAttribute('title',TRANSLATION_MAP['Start following this repository']); if(f_cnt){ var cnt = Number(f_cnt.innerHTML)+1; f_cnt.innerHTML = cnt; diff --git a/rhodecode/templates/changeset/changeset.html b/rhodecode/templates/changeset/changeset.html --- a/rhodecode/templates/changeset/changeset.html +++ b/rhodecode/templates/changeset/changeset.html @@ -122,22 +122,12 @@ <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> ${comment.comment_inline_form(c.changeset)} + ## render comments ${comment.comments(c.changeset)} - diff --git a/rhodecode/templates/changeset/changeset_comment_block.html b/rhodecode/templates/changeset/changeset_comment_block.html new file mode 100644 --- /dev/null +++ b/rhodecode/templates/changeset/changeset_comment_block.html @@ -0,0 +1,2 @@ +<%namespace name="comment" file="/changeset/changeset_file_comment.html"/> +${comment.comment_block(c.co)} \ No newline at end of file diff --git a/rhodecode/templates/changeset/changeset_file_comment.html b/rhodecode/templates/changeset/changeset_file_comment.html --- a/rhodecode/templates/changeset/changeset_file_comment.html +++ b/rhodecode/templates/changeset/changeset_file_comment.html @@ -4,7 +4,7 @@ ## ${comment.comment_block(co)} ## <%def name="comment_block(co)"> -
+
@@ -32,7 +32,8 @@