Mercurial > kallithea
changeset 2187:b61e540122f2 beta
#415: Adding comment to changeset causes reload
- comments are now added via ajax and doesn't reload the page
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Sat, 14 Apr 2012 22:13:07 +0200 |
parents | 7b52c2351231 |
children | 56e96d4e9f6e |
files | rhodecode/controllers/changeset.py rhodecode/model/comment.py rhodecode/public/css/style.css rhodecode/public/js/rhodecode.js rhodecode/templates/base/root.html rhodecode/templates/changeset/changeset.html rhodecode/templates/changeset/changeset_comment_block.html rhodecode/templates/changeset/changeset_file_comment.html |
diffstat | 8 files changed, 305 insertions(+), 90 deletions(-) [+] |
line wrap: on
line diff
--- a/rhodecode/controllers/changeset.py Fri Apr 13 21:12:42 2012 +0200 +++ b/rhodecode/controllers/changeset.py Sat Apr 14 22:13:07 2012 +0200 @@ -359,16 +359,25 @@ 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):
--- a/rhodecode/model/comment.py Fri Apr 13 21:12:42 2012 +0200 +++ b/rhodecode/model/comment.py Sat Apr 14 22:13:07 2012 +0200 @@ -142,7 +142,9 @@ .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))
--- a/rhodecode/public/css/style.css Fri Apr 13 21:12:42 2012 +0200 +++ b/rhodecode/public/css/style.css Sat Apr 14 22:13:07 2012 +0200 @@ -3966,6 +3966,7 @@ .comment .buttons { float: right; + padding:2px 2px 0px 0px; } @@ -3975,6 +3976,23 @@ } /** 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 @@ div.comment-inline-form { margin-top: 5px; padding:2px 6px 8px 6px; + } .comment-inline-form strong { @@ -4047,6 +4066,10 @@ 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 @@ 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;
--- a/rhodecode/public/js/rhodecode.js Fri Apr 13 21:12:42 2012 +0200 +++ b/rhodecode/public/js/rhodecode.js Sat Apr 14 22:13:07 2012 +0200 @@ -195,6 +195,31 @@ }; +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 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 = '<td class="lineno-inline new-inline"></td>'+ + '<td class="lineno-inline old-inline"></td>'+ + '<td>{0}</td>'.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 = '<td class="lineno-inline new-inline"></td>'+ - '<td class="lineno-inline old-inline"></td>'+ - '<td>{0}</td>'.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 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 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 = '<div class="add-comment"><span class="ui-btn">{0}</span></div>'.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 = '<span class="ui-btn">{0}</span>'.format(label); + + var add = new YAHOO.util.Element(html_el); add.on('click', function(e) { injectInlineForm(tr); }); @@ -384,6 +488,103 @@ 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<comment_add_buttons.length;i++){ + var b = comment_add_buttons[i]; + b.parentNode.removeChild(b); + } + } + else{ + break; + } + } + + var add = createInlineAddButton(target_tr); + // get the comment div + var comment_block = last_node.getElementsByClassName('comment')[0]; + // attach add button + YUD.insertAfter(add,comment_block); +} + +/** + * Places the inline comment into the changeset block in proper line position + */ +var placeInline = function(target_container,lineno,html){ + var lineid = "{0}_{1}".format(target_container,lineno); + var target_line = YUD.get(lineid); + var comment = new YAHOO.util.Element(tableTr('inline-comments',html)) + + // check if there are comments already ! + var parent = target_line.parentNode; + var root_parent = parent; + while (1){ + var n = parent.nextElementSibling; + // next element are comments ! + if(YUD.hasClass(n,'inline-comments')){ + parent = n; + } + else{ + break; + } + } + // put in the comment at the bottom + YUD.insertAfter(comment,parent); + + // scann nodes, and attach add button to last one + placeAddButton(root_parent); + + return target_line; +} + +/** + * make a single inline comment and place it inside + */ +var renderInlineComment = function(json_data){ + try{ + var html = json_data['rendered_text']; + var lineno = json_data['line_no']; + var target_id = json_data['target_id']; + placeInline(target_id, lineno, html); + + }catch(e){ + console.log(e); + } +} + +/** + * Iterates over all the inlines, and places them inside proper blocks of data + */ +var renderInlineComments = function(file_comments){ + for (f in file_comments){ + // holding all comments for a FILE + var box = file_comments[f]; + + var target_id = YUD.getAttribute(box,'target_id'); + // actually comments with line numbers + var comments = box.children; + for(var i=0; i<comments.length; i++){ + var data = { + 'rendered_text': comments[i].outerHTML, + 'line_no': YUD.getAttribute(comments[i],'line'), + 'target_id': target_id + } + renderInlineComment(data); + } + } +} + var fileBrowserListeners = function(current_url, node_list_url, url_base, truncated_lbl, nomatch_lbl){
--- a/rhodecode/templates/base/root.html Fri Apr 13 21:12:42 2012 +0200 +++ b/rhodecode/templates/base/root.html Sat Apr 14 22:13:07 2012 +0200 @@ -47,9 +47,13 @@ <script type="text/javascript"> 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;
--- a/rhodecode/templates/changeset/changeset.html Fri Apr 13 21:12:42 2012 +0200 +++ b/rhodecode/templates/changeset/changeset.html Sat Apr 14 22:13:07 2012 +0200 @@ -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)} - <script type="text/javascript"> - var deleteComment = function(comment_id){ - - var url = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}".replace('__COMMENT_ID__',comment_id); - var postData = '_method=delete'; - var success = function(o){ - var n = YUD.get('comment-'+comment_id); - n.parentNode.removeChild(n); - } - ajaxPOST(url,postData,success); - } - YUE.onDOMReady(function(){ - + AJAX_COMMENT_URL = "${url('changeset_comment',repo_name=c.repo_name,revision=c.changeset.raw_id)}"; + AJAX_COMMENT_DELETE_URL = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}" YUE.on(YUQ('.show-inline-comments'),'change',function(e){ var show = 'none'; var target = e.currentTarget; @@ -162,28 +152,7 @@ // inject comments into they proper positions var file_comments = YUQ('.inline-comment-placeholder'); - - for (f in file_comments){ - var box = file_comments[f]; - var inlines = box.children; - for(var i=0; i<inlines.length; i++){ - try{ - - var inline = inlines[i]; - var lineno = YUD.getAttribute(inlines[i],'line'); - var lineid = "{0}_{1}".format(YUD.getAttribute(inline,'target_id'),lineno); - var target_line = YUD.get(lineid); - - var add = createInlineAddButton(target_line.parentNode,'${_("add another comment")}'); - YUD.insertAfter(add,target_line.parentNode); - - var comment = new YAHOO.util.Element(tableTr('inline-comments',inline.innerHTML)) - YUD.insertAfter(comment,target_line.parentNode); - }catch(e){ - console.log(e); - } - } - } + renderInlineComments(file_comments); }) </script>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rhodecode/templates/changeset/changeset_comment_block.html Sat Apr 14 22:13:07 2012 +0200 @@ -0,0 +1,2 @@ +<%namespace name="comment" file="/changeset/changeset_file_comment.html"/> +${comment.comment_block(c.co)} \ No newline at end of file
--- a/rhodecode/templates/changeset/changeset_file_comment.html Fri Apr 13 21:12:42 2012 +0200 +++ b/rhodecode/templates/changeset/changeset_file_comment.html Sat Apr 14 22:13:07 2012 +0200 @@ -4,7 +4,7 @@ ## ${comment.comment_block(co)} ## <%def name="comment_block(co)"> - <div class="comment" id="comment-${co.comment_id}"> + <div class="comment" id="comment-${co.comment_id}" line="${co.line_no}"> <div class="comment-wrapp"> <div class="meta"> <span class="user"> @@ -32,7 +32,8 @@ <div id='comment-inline-form-template' style="display:none"> <div class="comment-inline-form"> %if c.rhodecode_user.username != 'default': - ${h.form(h.url('changeset_comment', repo_name=c.repo_name, revision=changeset.raw_id))} + <div class="overlay"><div class="overlay-text">${_('Submitting...')}</div></div> + ${h.form(h.url('changeset_comment', repo_name=c.repo_name, revision=changeset.raw_id),class_='inline-form')} <div class="clearfix"> <div class="comment-help">${_('Commenting on line')} {1}. ${_('Comments parsed using')} <a href="${h.url('rst_help')}">RST</a> ${_('syntax')} ${_('with')} @@ -43,7 +44,7 @@ <div class="comment-button"> <input type="hidden" name="f_path" value="{0}"> <input type="hidden" name="line" value="{1}"> - ${h.submit('save', _('Comment'), class_='ui-btn')} + ${h.submit('save', _('Comment'), class_='ui-btn save-inline-form')} ${h.reset('hide-inline-form', _('Hide'), class_='ui-btn hide-inline-form')} </div> ${h.end_form()} @@ -64,23 +65,27 @@ </%def> -<%def name="comments(changeset)"> - -<div class="comments"> +<%def name="inlines(changeset)"> <div class="comments-number">${len(c.comments)} comment(s) (${c.inline_cnt} ${_('inline')})</div> - %for path, lines in c.inline_comments: - <div style="display:none" class="inline-comment-placeholder" path="${path}" target_id="${h.FID(changeset.raw_id,path)}"> % for line,comments in lines.iteritems(): - <div class="inline-comment-placeholder-line" line="${line}" target_id="${h.safeid(h.safe_unicode(path))}"> + <div style="display:none" class="inline-comment-placeholder" path="${path}" target_id="${h.safeid(h.safe_unicode(path))}"> %for co in comments: ${comment_block(co)} %endfor </div> %endfor - </div> %endfor + +</%def> +<%def name="comments(changeset)"> + +<div class="comments"> + <div id="inline-comments-container"> + ${inlines(changeset)} + </div> + %for co in c.comments: ${comment_block(co)} %endfor