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 = ''.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)">
-