r95435 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r95434‎ | r95435 | r95436 >
Date:19:53, 24 August 2011
Author:hashar
Status:reverted (Comments)
Tags:needs-js-test, needs-php-test 
Comment:
add inline comments to the diff output

This patch rely on various previous revisions made to the CodeRevision
extension. It is mostly experimental, but there is an easy way to
disable it (will need to write a patch for this later so we use a global
variable like $wgEnableInlineComments).

To use it, simply click on a diff line to have a comment box opening.

Stuff that need fixing:
* the comment box is inserted above previous comments to a given line
* anonymous user (or people without the correct rights) will be show the
comment although the API did not save it in the DB. This is a bug in
the API code : it does not check the correct right and/or does not
return an error message if the comment was not inserted.
* Someone without the correct right should not be able to add a comment
* API call returns an HTML formatted comment, might be unneeded sometime
* JavaScript not reviewed for performance
* Not reviewed for security

A patch will come later on to easily disable this feature.
Modified paths:
  • /trunk/extensions/CodeReview/CodeReview.php (modified) (history)
  • /trunk/extensions/CodeReview/api/ApiCodeDiff.php (modified) (history)
  • /trunk/extensions/CodeReview/api/ApiRevisionUpdate.php (modified) (history)
  • /trunk/extensions/CodeReview/backend/DiffHighlighter.php (modified) (history)
  • /trunk/extensions/CodeReview/modules/ext.codereview.linecomment.js (added) (history)
  • /trunk/extensions/CodeReview/modules/ext.codereview.styles.css (modified) (history)
  • /trunk/extensions/CodeReview/ui/CodeRevisionView.php (modified) (history)

Diff [purge]

Index: trunk/extensions/CodeReview/modules/ext.codereview.linecomment.js
@@ -0,0 +1,99 @@
 2+( function( $ ) {
 3+var $rev = 0;
 4+
 5+window.CodeReview = $.extend( window.CodeReview, {
 6+
 7+ /* initialization from PHP */
 8+ lcInit: function( rev ) {
 9+ $rev = rev;
 10+ // Register click() event to each diff lines
 11+ $( 'table.mw-codereview-diff tr.commentable').click(
 12+ function () { CodeReview.lcShowForm( $(this) ); }
 13+ );
 14+ },
 15+
 16+ /**
 17+ * Show the line comment code below a line of code
 18+ * @param lineCode jQuery object
 19+ */
 20+ lcShowForm: function( lineCode ) {
 21+ lineCode.unbind( 'click' );
 22+ lineCode.click( function () {
 23+ $( '#lineComment' ).fadeOut( 200 ).remove();
 24+
 25+ lineCode.unbind( 'click' );
 26+ lineCode.click( function() {
 27+ CodeReview.lcShowForm( lineCode );
 28+ });
 29+ });
 30+
 31+ var lineComment =
 32+ $('<tr id="lineComment"><td colspan="3">'
 33+ +'<textarea id="lineCommentContent" rows="5"></textarea><br/>'
 34+ +'<input id="lineCommentSend" type="button" value="Send">'
 35+ +'</td></tr>');
 36+ lineComment.insertAfter( lineCode );
 37+ $( '#lineCommentContent' ).focus();
 38+
 39+ $( '#lineCommentSend' ).click( function() {
 40+ CodeReview.lcSubmitComment(
 41+ lineCode,
 42+ lineComment,
 43+ $( '#lineCommentContent' ).val()
 44+ );
 45+ });
 46+ },
 47+
 48+ lcSubmitComment: function( lineCode, lineComment, comment ) {
 49+
 50+ // retrieve line number from the code line id attribute:
 51+ var lineId = lineCode.attr('id');
 52+ lineId = lineId.substring( lineId.indexOf( '-' ) + 1);
 53+
 54+ $.ajax({
 55+ url: mw.util.wikiScript( 'api' ),
 56+ data: {
 57+ 'action': 'coderevisionupdate',
 58+
 59+ 'repo' : mw.config.get( 'wgCodeReviewRepository' ),
 60+ 'rev' : $rev,
 61+
 62+ 'comment': comment,
 63+ 'patchline' : lineId,
 64+
 65+ 'format': 'json',
 66+ },
 67+ dataType: 'json',
 68+ type: 'POST',
 69+ success: function( data ) {
 70+ // FIXME
 71+ console.log( data.coderevisionupdate );
 72+ //data.coderevisionupdate.commentid;
 73+
 74+ var text = data.coderevisionupdate.HTML
 75+ lineComment.fadeOut( 200 ).remove();
 76+
 77+ // check we have a list to insert the comment in.
 78+ var next = lineCode.next( '.inlineComment' );
 79+ if( next.length === 0 ) {
 80+ $( '<tr class="inlineComment"><td colspan="3"><ul><li>'+text+'</li></ul></td></tr>' ).insertAfter( lineCode )
 81+ } else {
 82+ lineCode.next('.inlineComment').find( 'ul' ).append(
 83+ $( '<li>' + text + '</li>' )
 84+ );
 85+ }
 86+
 87+
 88+ // rebind event handler
 89+ lineCode.click(
 90+ function () { CodeReview.lcShowForm( $(this) ); }
 91+ );
 92+ },
 93+ error: function() {
 94+ console.log( "AJAX ERROR" );
 95+ }
 96+ });
 97+ },
 98+
 99+}); // window.CodeReview
 100+})( jQuery );
Index: trunk/extensions/CodeReview/modules/ext.codereview.styles.css
@@ -58,6 +58,15 @@
5959 padding: 16px 16px 16px 48px;
6060 }
6161
 62+/** list containers to insert comments inside the diff table */
 63+.mw-codereview-inlineComment ul {
 64+ list-style-image: none; /* override Vector default */
 65+ list-style-type: none;
 66+ padding:0;
 67+ padding-left: 2em;
 68+ margin-bottom: 8px;
 69+}
 70+
6271 .mw-codereview-status-new,
6372 .mw-codereview-status-new td {
6473 background: #ffffc0 !important;
Index: trunk/extensions/CodeReview/api/ApiRevisionUpdate.php
@@ -59,10 +59,16 @@
6060 $params['patchline']
6161 );
6262
 63+ // Forge a response object
6364 $r = array( 'result' => 'Success' );
64 -
6565 if ( $commentID !== 0 ) {
 66+ // id inserted
6667 $r['commentid'] = intval($commentID);
 68+ // HTML Formatted comment
 69+ $view = new CodeRevisionView( $repo, $rev);
 70+ $comment = CodeComment::newFromID( $commentID, $rev );
 71+ $r['HTML'] = $view->formatComment( $comment );
 72+ //$r['HTML'] = print_r( $comment, true );
6773 }
6874
6975 $this->getResult()->addValue( null, $this->getModuleName(), $r );
Index: trunk/extensions/CodeReview/api/ApiCodeDiff.php
@@ -47,6 +47,7 @@
4848 $html = 'Diff too large.';
4949 } else {
5050 $hilite = new CodeDiffHighlighter();
 51+ # Fetch diff rendered without inline comments
5152 $html = $hilite->render( $diff );
5253 }
5354
Index: trunk/extensions/CodeReview/ui/CodeRevisionView.php
@@ -193,6 +193,12 @@
194194 }
195195 $html .= xml::closeElement( 'form' );
196196
 197+ $wgOut->addModules( 'ext.codereview.linecomment' );
 198+ $encRev = Xml::encodeJsVar( $this->mRev->getId() );
 199+ $wgOut->addInLineScript(
 200+ "CodeReview.lcInit( $encRev );"
 201+ );
 202+
197203 $wgOut->addHTML( $html );
198204 }
199205
@@ -441,7 +447,8 @@
442448 return htmlspecialchars( wfMsg( 'code-rev-diff-too-large' ) );
443449 } else {
444450 $hilite = new CodeDiffHighlighter();
445 - return $hilite->render( $diff );
 451+ # Diff rendered with inline comments
 452+ return $hilite->render( $diff, $this->mRepo, $this->mRev );
446453 }
447454 }
448455
Index: trunk/extensions/CodeReview/CodeReview.php
@@ -168,6 +168,10 @@
169169 'scripts' => 'ext.codereview.loaddiff.js'
170170 ) + $commonModuleInfo;
171171
 172+$wgResourceModules['ext.codereview.linecomment'] = array(
 173+ 'scripts' => 'ext.codereview.linecomment.js'
 174+) + $commonModuleInfo;
 175+
172176 // Revision tooltips CodeRevisionView:
173177 $wgResourceModules['ext.codereview.tooltips'] = array(
174178 'scripts' => 'ext.codereview.tooltips.js',
Index: trunk/extensions/CodeReview/backend/DiffHighlighter.php
@@ -13,19 +13,63 @@
1414 /* line number inside patch */
1515 private $lineNumber = 0;
1616
 17+ /* CodeRepository: The repository for this revision */
 18+ private $repo = null;
 19+ /* CodeRevision: revision the diff comes from */
 20+ private $rev = null;
 21+
1722 /**
 23+ * Comments inside the diff.
 24+ * initialized with fetchInlineComments()
 25+ */
 26+ private $inlineComments = null;
 27+
 28+ /**
1829 * Main entry point. Given a diff text, highlight it
1930 * and wrap it in a div
 31+ * Pass both $repos and $rev to have the diff rendered with inline comments
 32+ *
2033 * @param $text string Text to highlight
 34+ * @param $repo CodeRepository (default: null)
 35+ * @param $repo CodeRevision (default: null)
2136 * @return string
2237 */
23 - function render( $text ) {
 38+ function render( $text, CodeRepository $repo = null, CodeRevision $rev = null ) {
 39+ if( $repo xor $rev ) {
 40+ throw new MWException( __METHOD__ . " must have both repository and revision or none of them\n" );
 41+ } elseif( $repo && $rev ) {
 42+ $this->repo = $repo;
 43+ $this->rev = $rev;
 44+ $this->fetchInlineComments();
 45+ }
 46+
2447 return '<table class="mw-codereview-diff">' .
2548 $this->splitLines( $text ) .
2649 "</table>\n";
2750 }
2851
2952 /**
 53+ * Fetch comments attached to a patch line.
 54+ * Comments can be accessed through the array inlineComments. Its format is:
 55+ * array(
 56+ * line# => array(
 57+ * CodeComment, CodeComment ...
 58+ * ),
 59+ * line# => array(
 60+ * CodeComment, CodeComment ...
 61+ * ),
 62+ * ...
 63+ * );
 64+ */
 65+ private function fetchInlineComments() {
 66+ $inline = $this->rev->getComments( 'which are attached' );
 67+ foreach( $inline as $comment ) {
 68+ $line = $comment->patchLine; # absolute line number in the diff
 69+ $this->inlineComments[$line][] = $comment;
 70+ }
 71+ }
 72+
 73+ /**
3074 * Given a bunch of text, split it into individual
3175 * lines, color them, then put it back into one big
3276 * string
@@ -79,10 +123,34 @@
80124 $r = $this->handleLineFile( $line );
81125 }
82126
 127+ # Finally add up any lineComments that might apply to this line
 128+ $r .= $this->addLineComments();
 129+
83130 # Return HTML generated by one of the handler
84131 return $r;
85132 }
86133
 134+ function addLineComments() {
 135+ $return = '';
 136+ if( !isset( $this->inlineComments ) ) {
 137+ # No inline comments for this revision.
 138+ return $return;
 139+ }
 140+ if( !array_key_exists( $this->lineNumber, $this->inlineComments ) ) {
 141+ # Line does not have any comment applying to
 142+ return $return;
 143+ }
 144+
 145+ $comments = $this->inlineComments[$this->lineNumber];
 146+ # FIXME: comment formatting can only be handled by a view
 147+ # Would need abstraction, for example as a class of views helpers.
 148+ $view = new CodeRevisionView( $this->repo, $this->rev );
 149+ foreach( $comments as $comment ) {
 150+ $return .= "<li>{$view->formatComment( $comment )}</li>\n" ;
 151+ }
 152+ return "<tr class=\"mw-codereview-inlineComment\"><td colspan=\"3\"><ul>{$return}</ul></td></tr>\n";
 153+ }
 154+
87155 function formatLine( $content, $class = null ) {
88156 $formatLN =
89157 "<td class=\"linenumbers\">%s</td>"
@@ -91,7 +159,7 @@
92160
93161 $idAttr = $this->getLineIdAttr();
94162 if( is_null($class) ) {
95 - return sprintf( "<tr {$idAttr}>{$formatLN}<td>%s</td></tr>\n",
 163+ return sprintf( "<tr class=\"commentable\" {$idAttr}>{$formatLN}<td>%s</td></tr>\n",
96164 $this->left,
97165 $this->right,
98166 $content
@@ -121,7 +189,7 @@
122190 }
123191
124192 $classAttr = is_null($class) ? '' : " class=\"$class\"";
125 - return sprintf( "<tr {$idAttr}>{$formatLN}<td%s>%s</td></tr>\n",
 193+ return sprintf( "<tr class=\"commentable\" {$idAttr}>{$formatLN}<td%s>%s</td></tr>\n",
126194 $left, $right,
127195 $classAttr, $content
128196 );

Follow-up revisions

RevisionCommit summaryAuthorDate
r107068fix case of addInLineScript...hashar15:08, 22 December 2011
r107069wrap linecomment js initializer in a ready() block...hashar15:12, 22 December 2011
r108350Reverting inline commenting from CodeReview...johnduhart06:55, 8 January 2012

Comments

#Comment by Tim Starling (talk | contribs)   05:41, 8 December 2011
+		$wgOut->addInLineScript(
+			"CodeReview.lcInit( $encRev );"
+		);

I think the usual convention is to do this sort of initialisation in a ready event, created when the module loads, rather than inserting script tags. Also, it's spelt addInlineScript not addInLineScript.

#Comment by Hashar (talk | contribs)   15:14, 22 December 2011

Here are the fixes:

r107068 : fix case

r107069 : I have not found a resource loader method to register a ready() event. So I just wrapped the initializer in a $(document).ready() call.

Status & tagging log