changeset 1677:7276b170ce8b beta

#71 code-review - simple inline comments
author Marcin Kuzminski <marcin@python-works.com>
date Sun, 13 Nov 2011 02:16:12 +0200
parents e86191684f4b
children aa6a1c6f2ac5
files rhodecode/controllers/changeset.py rhodecode/model/comment.py rhodecode/model/db.py rhodecode/public/css/diff.css rhodecode/public/css/style.css rhodecode/public/js/rhodecode.js rhodecode/templates/changeset/changeset.html rhodecode/templates/changeset/changeset_file_comment.html
diffstat 8 files changed, 220 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/controllers/changeset.py	Sat Nov 12 20:24:07 2011 +0200
+++ b/rhodecode/controllers/changeset.py	Sun Nov 13 02:16:12 2011 +0200
@@ -98,13 +98,17 @@
         c.cut_off = False  # defines if cut off limit is reached
 
         c.comments = []
-
+        c.inline_comments = []
+        c.inline_cnt = 0
         # Iterate over ranges (default changeset view is always one changeset)
         for changeset in c.cs_ranges:
             c.comments.extend(ChangesetCommentsModel()\
                               .get_comments(c.rhodecode_db_repo.repo_id,
                                             changeset.raw_id))
-
+            inlines = ChangesetCommentsModel()\
+                        .get_inline_comments(c.rhodecode_db_repo.repo_id,
+                                             changeset.raw_id)
+            c.inline_comments.extend(inlines)
             c.changes[changeset.raw_id] = []
             try:
                 changeset_parent = changeset.parents[0]
@@ -199,6 +203,11 @@
                     c.changes[changeset.raw_id].append(('removed', node, None,
                                                         None, None, (0, 0)))
 
+        # count inline comments
+        for path, lines in c.inline_comments:
+            for comments in lines.values():
+                c.inline_cnt += len(comments)
+
         if len(c.cs_ranges) == 1:
             c.changeset = c.cs_ranges[0]
             c.changes = c.changes[c.changeset.raw_id]
--- a/rhodecode/model/comment.py	Sat Nov 12 20:24:07 2011 +0200
+++ b/rhodecode/model/comment.py	Sun Nov 13 02:16:12 2011 +0200
@@ -49,18 +49,18 @@
         :param f_path:
         :param line_no:
         """
+        if text:
+            comment = ChangesetComment()
+            comment.repo_id = repo_id
+            comment.user_id = user_id
+            comment.revision = revision
+            comment.text = text
+            comment.f_path = f_path
+            comment.line_no = line_no
 
-        comment = ChangesetComment()
-        comment.repo_id = repo_id
-        comment.user_id = user_id
-        comment.revision = revision
-        comment.text = text
-        comment.f_path = f_path
-        comment.line_no = line_no
-
-        self.sa.add(comment)
-        self.sa.commit()
-        return comment
+            self.sa.add(comment)
+            self.sa.commit()
+            return comment
 
     def delete(self, comment_id):
         """
@@ -81,13 +81,13 @@
                 .filter(ChangesetComment.line_no == None)\
                 .filter(ChangesetComment.f_path == None).all()
 
-    def get_comments_for_file(self, repo_id, f_path, raw_id):
+    def get_inline_comments(self, repo_id, revision):
         comments = self.sa.query(ChangesetComment)\
             .filter(ChangesetComment.repo_id == repo_id)\
-            .filter(ChangesetComment.commit_id == raw_id)\
-            .filter(ChangesetComment.f_path == f_path).all()
+            .filter(ChangesetComment.revision == revision).all()
+
+        paths = defaultdict(lambda:defaultdict(list))
 
-        d = defaultdict(list)
         for co in comments:
-            d[co.line_no].append(co)
-        return d.items()
+            paths[co.f_path][co.line_no].append(co)
+        return paths.items()
--- a/rhodecode/model/db.py	Sat Nov 12 20:24:07 2011 +0200
+++ b/rhodecode/model/db.py	Sun Nov 13 02:16:12 2011 +0200
@@ -1101,11 +1101,11 @@
     comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
     repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
     revision = Column('revision', String(40), nullable=False)
-    line_no = Column('line_no', Integer(), nullable=True)
-    f_path = Column('f_path', String(1000), nullable=True)
+    line_no = Column('line_no', Unicode(10), nullable=True)
+    f_path = Column('f_path', Unicode(1000), nullable=True)
     user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
-    text = Column('text', String(25000), nullable=False)
-    modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
+    text = Column('text', Unicode(25000), nullable=False)
+    modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
 
     author = relationship('User')
     repo = relationship('Repository')
--- a/rhodecode/public/css/diff.css	Sat Nov 12 20:24:07 2011 +0200
+++ b/rhodecode/public/css/diff.css	Sun Nov 13 02:16:12 2011 +0200
@@ -117,4 +117,13 @@
 .line{
 	padding:0;
 	margin:0;
-}
\ No newline at end of file
+}
+
+.line.highlight{
+	background-color:#FFFFCC;
+	cursor: pointer;
+	background-image:url("../images/icons/comment_add.png");
+	background-repeat:no-repeat;
+	background-position: right;
+	background-position: 100% 50%;
+}
--- a/rhodecode/public/css/style.css	Sat Nov 12 20:24:07 2011 +0200
+++ b/rhodecode/public/css/style.css	Sun Nov 13 02:16:12 2011 +0200
@@ -1853,20 +1853,24 @@
 
 .cs_files .changes {
 	float: right;
+	color:#003367;
+	
 }
 
 .cs_files .changes .added {
 	background-color: #BBFFBB;
 	float: left;
 	text-align: center;
-	font-size: 90%;
+	font-size: 9px;
+    padding: 2px 0px 2px 0px;
 }
 
 .cs_files .changes .deleted {
 	background-color: #FF8888;
 	float: left;
 	text-align: center;
-	font-size: 90%;
+	font-size: 9px;
+    padding: 2px 0px 2px 0px;
 }
 
 .cs_files .cs_added {
@@ -3270,7 +3274,10 @@
 .comments .comments-number{
 	padding:0px 0px 10px 0px;
 	font-weight: bold;
-}
+	color: #666;
+	font-size: 16px;
+}
+/** comment form **/
 
 .comment-form .clearfix{
 	background: #EEE;
@@ -3332,3 +3339,59 @@
     position: absolute;
     right:40px;
 }
+
+
+
+/** comment inline form **/
+
+.comment-inline-form .clearfix{
+    background: #EEE;
+    -webkit-border-radius: 4px;
+    -moz-border-radius: 4px;
+    border-radius: 4px;
+    padding: 5px;
+}
+
+div.comment-inline-form {
+    margin-top: 5px;
+    padding:2px 6px 8px 6px;
+}
+
+.comment-inline-form strong {
+    display: block;
+    margin-bottom: 15px;
+}
+
+.comment-inline-form textarea {
+    width: 100%;
+    height: 100px;
+    font-family: 'Monaco', 'Courier', 'Courier New', monospace;
+}
+
+form.comment-inline-form {
+    margin-top: 10px;
+    margin-left: 10px;
+}
+
+.comment-inline-form-submit {
+    margin-top: 5px;
+    margin-left: 525px;
+}
+
+.file-comments {
+    display: none;
+}
+
+.comment-inline-form .comment {
+    margin-left: 10px;
+}
+
+.comment-inline-form .comment-help{
+    padding: 0px 0px 2px 0px;
+    color: #666666;
+    font-size: 10px;
+}
+
+.comment-inline-form .comment-button{
+    padding-top:5px;
+}
\ No newline at end of file
--- a/rhodecode/public/js/rhodecode.js	Sat Nov 12 20:24:07 2011 +0200
+++ b/rhodecode/public/js/rhodecode.js	Sun Nov 13 02:16:12 2011 +0200
@@ -298,3 +298,41 @@
     var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
 };
 
+
+/** comments **/
+var removeInlineForm = function(form) {
+	form.parentNode.removeChild(form);
+}
+
+var createInlineForm = function(parent_tr, f_path, line) {
+	var form = document.createElement('tr');
+	YUD.addClass(form, 'comment-form-inline');
+	var tmpl = YUD.get('comment-inline-form-template').innerHTML;
+	tmpl = tmpl.format(f_path, line);
+	form.innerHTML = '<td class="lineno new"></td>'+
+		             '<td class="lineno old"></td>'+ 
+			         '<td>{0}</td>'.format(tmpl);
+
+	// create event for hide button
+	form = new YAHOO.util.Element(form);
+	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;
+		removeInlineForm(newtr);
+		YUD.removeClass(parent_tr, 'form-open');
+	});
+	return form
+}
+var getLineNo = function(tr) {
+	var line;
+	var o = tr.children[0].id.split('_');
+	var n = tr.children[1].id.split('_');
+
+	if (n.length == 2) {
+		line = n[1];
+	} else if (o.length == 2) {
+		line = o[1];
+	}
+
+	return line
+}
\ No newline at end of file
--- a/rhodecode/templates/changeset/changeset.html	Sat Nov 12 20:24:07 2011 +0200
+++ b/rhodecode/templates/changeset/changeset.html	Sun Nov 13 02:16:12 2011 +0200
@@ -114,38 +114,52 @@
 						${h.link_to_if(change!='removed',h.safe_unicode(filenode.path),h.url('files_home',repo_name=c.repo_name,
 						revision=filenode.changeset.raw_id,f_path=h.safe_unicode(filenode.path)))}
 					</span>
-					%if 1:
 					&raquo; <span>${h.link_to(_('diff'),
 					h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='diff'))}</span>
 					&raquo; <span>${h.link_to(_('raw diff'),
 					h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='raw'))}</span>
 					&raquo; <span>${h.link_to(_('download diff'),
 					h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='download'))}</span>
-					%endif
 				</div>
 			</div>
-			<div class="code-body">        
-					%if diff:
-						${diff|n}
-					%else:
-						${_('No changes in this file')}
-					%endif
+			<div class="code-body">
+                <div class="full_f_path" path="${filenode.path}"></div>        
+				%if diff:
+					${diff|n}
+				%else:
+					${_('No changes in this file')}
+				%endif
 			</div>
 		</div>
 		%endif
 	%endfor
   
     <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
+    ## template for inline comment form
+    ${comment.comment_inline_form()}
     
     <div class="comments">
-        <div class="comments-number">${len(c.comments)} comment(s)</div>
+        <div class="comments-number">${len(c.comments)} comment(s) (${c.inline_cnt} ${_('inline')})</div>
+        
+        %for path, lines in c.inline_comments:
+            <div class="inline-comment-placeholder" path="${path} ">
+            % for line,comments in lines.iteritems():
+                <div class="inline-comment-placeholder-line" line="${line}"> 
+                %for co in comments:
+                    ${comment.comment_block(co)}
+                %endfor
+                </div>
+            %endfor
+            </div>
+        %endfor        
+        
         %for co in c.comments:
             ${comment.comment_block(co)}
         %endfor
         %if c.rhodecode_user.username != 'default':
         <div class="comment-form">
             ${h.form(h.url('changeset_comment', repo_name=c.repo_name, revision=c.changeset.raw_id))}
-            <strong>Leave a comment</strong>
+            <strong>${_('Leave a comment')}</strong>
             <div class="clearfix">
                 <div class="comment-help">${_('Comments parsed using RST syntax')}</div>
                     ${h.textarea('text')}
@@ -167,7 +181,34 @@
               n.parentNode.removeChild(n);
           }
           ajaxPOST(url,postData,success);
-      } 
+      }
+
+      YUE.onDOMReady(function(){
+    	  YUE.on(YUQ('.line'),'mouseenter',function(e){
+    		  var tr = e.currentTarget;
+              if(YUD.hasClass(tr,'form-open') || YUD.hasClass(tr,'context')){
+                  return
+              }    		  
+    		  YUD.addClass(tr,'highlight');
+    	  });
+          YUE.on(YUQ('.line'),'mouseleave',function(e){
+              YUD.removeClass(e.currentTarget,'highlight');
+          });
+          
+          YUE.on(YUQ('.line'),'click',function(e){
+        	  var tr = e.currentTarget;
+        	  if(YUD.hasClass(tr,'form-open') || YUD.hasClass(tr,'context')){
+        		  return
+        	  }
+        	  YUD.addClass(tr,'form-open');
+        	  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);
+        	  YUD.insertAfter(form,tr);
+          })
+      })
+      
     </script> 
   </div>	
 </%def>
--- a/rhodecode/templates/changeset/changeset_file_comment.html	Sat Nov 12 20:24:07 2011 +0200
+++ b/rhodecode/templates/changeset/changeset_file_comment.html	Sun Nov 13 02:16:12 2011 +0200
@@ -13,7 +13,7 @@
   		${h.short_id(co.revision)}
   		%if co.f_path:
   			${_(' in file ')}
-  			${co.f_path}:L${co.line_no}
+  			${co.f_path}:L ${co.line_no}
   		%endif
   		<span class="date">
   			${h.age(co.modified_at)}
@@ -28,4 +28,25 @@
   		${h.rst(co.text)|n}
   	</div>
   </div>
+</%def>
+
+
+
+<%def name="comment_inline_form()">
+<div id='comment-inline-form-template' style="display:none">
+  <div class="comment-inline-form">
+      ${h.form(h.url('changeset_comment', repo_name=c.repo_name, revision=c.changeset.raw_id))}
+      <div class="clearfix">
+          <div class="comment-help">${_('Commenting on line')} {1} ${_('comments parsed using RST syntax')}</div>
+              ${h.textarea('text')}
+      </div>
+      <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-button-small')}
+      ${h.reset('hide-inline-form', _('Hide'), class_='ui-button-small hide-inline-form')}
+      </div>
+      ${h.end_form()}
+  </div>
+</div>  
 </%def>
\ No newline at end of file