All set, thanks Inline comments:
> --- lib/lp/app/javascript/comment.js 2014-04-04 05:23:48 +0000 > +++ lib/lp/app/javascript/comment.js 2014-05-15 03:58:24 +0000 > @@ -308,8 +308,6 @@ > initializer: function() { > this.vote_input = Y.one('[id="field.vote"]'); > this.review_type = Y.one('[id="field.review_type"]'); > - this.publish_inline_comments = Y.one( > - '[id="field.publish_inline_comments"]'); > this.in_reply_to = null; > }, > /** > @@ -334,6 +332,15 @@ > return selected.get('innerHTML'); > }, > /** > + * Whether or not the review comment has inline comments to be published > + * > + * @method has_inline > + */ > + has_inline: function() { > + var inline_cb = Y.one('[id="field.publish_inline_comments"]'); > + return inline_cb !== null && inline_cb.get('checked') > + }, fixed. > + /** > * Ensure that the widget's values are suitable for submission. > * > * This allows the vote to be submitted, even when no text is specified > @@ -345,6 +352,9 @@ > if (this.get_vote() !== null) { > return true; > } > + if (this.has_inline()) { > + return true > + } > return namespace.Comment.prototype.validate.apply(this); > }, > /** > @@ -357,9 +367,6 @@ > namespace.Comment.prototype.set_disabled.call(this, disabled); > this.vote_input.set('disabled', disabled); > this.review_type.set('disabled', disabled); > - if (this.publish_inline_comments) { > - this.publish_inline_comments.set('disabled', disabled); > - } > }, > /** > * Post the comment to the Launchpad API > @@ -383,8 +390,8 @@ > if (this.in_reply_to !== null) { > config.parameters.parent = this.in_reply_to.get('self_link'); > } > - if (this.publish_inline_comments && > - this.publish_inline_comments.get('checked')) { > + > + if (this.has_inline()) { > var ic = Y.lp.code.branchmergeproposal.inlinecomments; > config.parameters.inline_comments = ic.inlinecomments; > config.parameters.previewdiff_id = ic.current_previewdiff_id; > @@ -451,9 +458,6 @@ > */ > reset_contents: function() { > this.review_type.set('value', ''); > - if (this.publish_inline_comments) { > - this.publish_inline_comments.set('value', ''); > - } > this.vote_input.set('selectedIndex', 0); > this.in_reply_to = null; > namespace.Comment.prototype.reset_contents.apply(this); > @@ -490,6 +494,11 @@ > this.review_type.on('keyup', this.syncUI, this); > this.review_type.on('mouseup', this.syncUI, this); > Y.all('a.menu-link-reply').on('click', this.reply_clicked, this); > + Y.on('CodeReviewComment.SET_DISABLED', function(disabled) { > + // this.set_disabled() unfortunately does too much for the > + // current callsite (inlinecomment). > + this.submit_button.set('disabled', disabled); > + }, this); > }, > /** > * Implementation of Widget.syncUI: Update appearance according to state. > > === modified file 'lib/lp/code/browser/codereviewcomment.py' > --- lib/lp/code/browser/codereviewcomment.py 2014-04-04 05:23:48 +0000 > +++ lib/lp/code/browser/codereviewcomment.py 2014-05-15 03:58:24 +0000 > @@ -292,18 +292,9 @@ > """Create the comment...""" > vote = data.get('vote') > review_type = data.get('review_type') > - inline_comments = {} > - previewdiff_id = None > - if (getFeatureFlag('code.inline_diff_comments.enabled') and > - data.get('publish_inline_comments')): > - previewdiff_id = self.previewdiff.id > - inline_comments = ( > - self.branch_merge_proposal.getDraftInlineComments( > - previewdiff_id)) > self.branch_merge_proposal.createComment( > self.user, subject=None, content=data['comment'], > - parent=self.reply_to, vote=vote, review_type=review_type, > - previewdiff_id=previewdiff_id, inline_comments=inline_comments) > + parent=self.reply_to, vote=vote, review_type=review_type) > > @property > def next_url(self): > > === modified file > 'lib/lp/code/javascript/branchmergeproposal.inlinecomments.js' > --- lib/lp/code/javascript/branchmergeproposal.inlinecomments.js > 2014-05-07 06:16:12 +0000 > +++ lib/lp/code/javascript/branchmergeproposal.inlinecomments.js > 2014-05-15 03:58:24 +0000 > @@ -62,6 +62,11 @@ > content_row.remove(true); > } > var config = { > + on: { > + success: function () { > + Y.fire('inlinecomment.UPDATED'); > + } > + }, > parameters: { > previewdiff_id: namespace.current_previewdiff_id, > comments: namespace.inlinecomments > @@ -161,8 +166,8 @@ > namespace.cleanup_comments = function() { > // Cleanup previous inline review comments. > Y.all('.ict-header').each( function(line) { > - line.next().remove(); > - line.remove(); > + line.next().remove(true); > + line.remove(true); > }); > }; > > @@ -176,6 +181,7 @@ > comments.forEach( function (comment) { > namespace.create_row(comment); > }); > + Y.fire('inlinecomment.UPDATED'); > } > }, > parameters: { > @@ -203,6 +209,7 @@ > }; > namespace.create_row(comment); > }); > + Y.fire('inlinecomment.UPDATED'); > } > }, > parameters: { > @@ -237,6 +244,68 @@ > }; > > > +var PublishDrafts = function () { > + PublishDrafts.superclass.constructor.apply(this, arguments); > +}; > + > +Y.mix(PublishDrafts, { > + > + NAME: 'publishdrafts', > + > + ATTRS: { > + } > + > +}); > + > +Y.extend(PublishDrafts, Y.Widget, { > + > + /** > + * syncUI implementation for PublishDrafts. > + * > + * Modifies the CodeReviewComment widget, by enable/disable it and > + * adding/removing its 'publish_inline_comments' field according to > + * the presence of draft inline comments to be published. > + * > + * @method syncUI > + */ > + syncUI: function() { > + this.get('srcNode').empty(); > + var n_drafts = Y.all('.draft').size(); Makes sense, thanks. Most of our widgets are enhancers, but PublishDraft() surely isn't. > + if (n_drafts == 0) { > + Y.fire('CodeReviewComment.SET_DISABLED', true); > + return; > + } > + var text = 'Publish ' + n_drafts + ' inline comment'; > + if (n_drafts > 1) text += 's'; > + var label = Y.Node.create('<a />') > + .set('text', text); > + var checkbox = Y.Node.create( > + '<input id="field.publish_inline_comments"' + > + 'name="field.publish_inline_comments"' + > + 'type="checkbox" class="checkboxType"' + > + 'checked=""></input>') > + this.get('srcNode').append(checkbox); > + this.get('srcNode').append(label); > + Y.fire('CodeReviewComment.SET_DISABLED', false); > + }, > + > + /** > + * bindUI implementation for PublishDrafts. > + * > + * Simply hook syncUI() to 'inlinecomment.UPDATE' events. > + * > + * @method bindUI > + */ > + bindUI: function() { > + Y.detach('inlinecomment.UPDATED'); > + Y.on('inlinecomment.UPDATED', this.syncUI, this); > + } > + > +}); > + > +namespace.PublishDrafts = PublishDrafts; > + > + > var InlineCommentToggle = function () { > InlineCommentToggle.superclass.constructor.apply(this, arguments); > }; > @@ -383,7 +452,7 @@ > * @method cleanup_status > */ > cleanup_status: function() { > - this.get('srcNode').all('h2 img').remove(); > + this.get('srcNode').all('h2 img').remove(true); > }, > > /** > @@ -395,6 +464,7 @@ > if (LP.cache.inline_diff_comments !== true) { > return; > } > + namespace.cleanup_comments(); > namespace.populate_comments(); > this._connectScrollers(); > }, > @@ -408,10 +478,25 @@ > _connectScrollers: function() { > var self = this; > var rc = Y.lp.code.branchmergeproposal.reviewcomment; > - Y.all('.inline-comment-scroller').each( function(node) { > - rc.link_scroller(node, '#review-diff', function() { > - self._showPreviewDiff( > - node.getAttribute('data-previewdiff-id')); > + Y.all('td[data-previewdiff-id]').each( function(td) { > + // Comments from superseded MPs should be ignored. > + if (td.getData('from-superseded') === 'True') { > + return; > + } > + var previewdiff_id = td.getData('previewdiff-id'); > + var comment_id = td.getData('comment-id'); > + // We have to remove the old scrollers otherwise they will > + // fire multiple 'click' handlers (and animations). > + var scroller = td.one('.ic-scroller'); > + if (scroller !== null) { > + scroller.remove(true); > + } > + scroller = Y.Node.create( > + '<a href="" class="ic-scroller" style="float: right;">' + > + 'View inline comments</a>'); > + td.append(scroller); > + rc.link_scroller(scroller, '#review-diff', function() { > + self._showPreviewDiff(previewdiff_id); > }); > }); > }, > @@ -488,6 +573,14 @@ > self._updateDiff(preview_diff_uri); > return; > } > + > + var pub_drafts_container = Y.Node.create( > + '<div class="publish_drafts_container">'); > + Y.one('[id="field.review_type"]').insert( > + pub_drafts_container, 'after'); > + (new namespace.PublishDrafts( > + {'srcNode': pub_drafts_container})).render(); > + > var container = this.get('srcNode').one('.diff-navigator'); > container.empty(); > var preview_diffs_uri = > LP.cache.context.preview_diffs_collection_link; > > === modified file > 'lib/lp/code/javascript/tests/test_branchmergeproposal.inlinecomments.html' > --- lib/lp/code/javascript/tests/test_branchmergeproposal.inlinecomments.html > 2014-04-03 20:33:08 +0000 > +++ lib/lp/code/javascript/tests/test_branchmergeproposal.inlinecomments.html > 2014-05-15 03:58:24 +0000 > @@ -72,11 +72,30 @@ > <li>lp.code.branchmergeproposal.inlinecomments.test</li> > </ul> > > - <a id="scroll-one" class="inline-comment-scroller" href="" > - data-previewdiff-id="101">Go to One</a> > + <div> > + <input id="field.review_type" type="text"></input> > + <input id="field.actions.add" type="submit" value="Save"></input> > + </div> > > - <a id="scroll-two" class="inline-comment-scroller" href="" > - data-previewdiff-id="202">Go to Two</a> > + <table class="conversation"> > + <tr> > + <td data-previewdiff-id="102" data-from-superseded="True" > + data-comment-id="10"> > + Comment from superseded </td> > + </tr><tr> > + <td data-previewdiff-id="101" data-from-superseded="False" > + data-comment-id="1"> > + Comment One </td> > + </tr><tr> > + <td data-previewdiff-id="202" data-from-superseded="False" > + data-comment-id="2"> > + Comment Two </td> > + </tr><tr> > + <td data-from-superseded="False" > + data-comment-id="3"> > + No inlines </td> > + </tr> > + </table> > > <div id="review-diff"> > > > === modified file > 'lib/lp/code/javascript/tests/test_branchmergeproposal.inlinecomments.js' > --- lib/lp/code/javascript/tests/test_branchmergeproposal.inlinecomments.js > 2014-05-07 06:16:12 +0000 > +++ lib/lp/code/javascript/tests/test_branchmergeproposal.inlinecomments.js > 2014-05-15 03:58:24 +0000 > @@ -408,6 +408,31 @@ > 'table-row', Y.one('tr.ict-header').getStyle('display')); > }, > > + test_publish_drafts: function() { > + // PublishDraft() widget modifies the add-comment form > + // (adding/removing 'publish_inlines' checkbox) according > + // to the existence of draft inline comments. > + var container = Y.one('.publish_drafts_container') > + Y.Assert.areEqual('', container.get('text')); > + Y.Assert.isNull(container.one('[type=checkbox]')); > + // A event is fired when the inlinecomments set changes. > + Y.fire('inlinecomment.UPDATED'); > + Y.Assert.areEqual( > + 'Publish 1 inline comment', container.get('text')); > + Y.Assert.isNotNull(container.one('[type=checkbox]')); > + // Adding another draft. > + module.create_row({'line_number': '2', 'text': 'another'}); > + Y.fire('inlinecomment.UPDATED'); > + Y.Assert.areEqual( > + 'Publish 2 inline comments', container.get('text')); > + Y.Assert.isNotNull(container.one('[type=checkbox]')); > + // Removing all drafts. > + module.cleanup_comments(); > + Y.fire('inlinecomment.UPDATED'); > + Y.Assert.areEqual('', container.get('text')); > + Y.Assert.isNull(container.one('[type=checkbox]')); > + }, > + > test_diff_nav_scrollers: function() { > // The Diff Navigator review comment *scrollers* are connected > // upon widget rendering and when clicked trigger the diff > @@ -417,10 +442,26 @@ > this.reply_diffcontent(); > var mockio = this.diffnav.get('lp_client').io_provider; > Y.Assert.areEqual(2, mockio.requests.length); > + // The needed review-comment scrollers (View inline comments) > + // are created. Only 'current' (non-superseded) comments > + // associated with inline comments get a scroller. > + var lines = [] > + Y.one('.conversation').get('text').split('\n').forEach( > + function(line) { if (line.trim()) lines.push(line.trim()); } > + ); > + Y.ArrayAssert.itemsAreEqual( > + ['Comment from superseded', > + 'Comment One View inline comments', > + 'Comment Two View inline comments', > + 'No inlines'], > + lines); > + // Scroller are identified as: > + // 'ic-scroller-<previewdiff_id>-<comment_id>'. > + var comment = Y.one('[data-comment-id="2"]'); > + var scroller = comment.one('.ic-scroller') > // We need to re-instrument the scroller in other to > // instantly fire the 'end' event (which runs the code > // that matters to us). > - scroller = Y.one('#scroll-two'); > scroller.on('click', function() { > var rc = Y.lp.code.branchmergeproposal.reviewcomment; > rc.window_scroll_anim.fire('end'); > @@ -446,20 +487,27 @@ > // hook new inline-comment scroller links. > this.diffnav.set('navigator', Y.one('select')); > // Let's create add a new scroller to the page. > - var new_scroller = Y.Node.create( > - '<a id="scroll-three" class="inline-comment-scroller" ' + > - 'href="" data-previewdiff-id="202">Another scroller</a>'); > - Y.one('#scroll-two').insert(new_scroller, 'after'); > - // and instrument the inline-comment updated function. > + var new_comment = Y.Node.create( > + '<tr><td data-previewdiff-id="202" data-comment-id="3">' + > + 'Comment Three</td></tr>'); > + Y.one('.conversation').append(new_comment); > + // and instrument the inline-comment functions to remove > + // and populate comments. > + var cleaned = false; > var populated = false; > + module.cleanup_comments = function () { > + cleaned = true; > + }; > module.populate_comments = function () { > populated = true; > }; > - // Once called, update_on_new_comment() integrates the > - // just-added scroller and updates the inline comments. > + // Once called, update_on_new_comment() creates the scroller > + // for the just-added comment and refreshes the inline comments. > this.diffnav.update_on_new_comment(); > + var new_scroller = new_comment.one('.ic-scroller'); > Y.Assert.isTrue(new_scroller.hasClass('js-action')); > Y.Assert.isTrue(populated); > + Y.Assert.isTrue(cleaned); > // Instrument the new scroller, so it will instantly fire > // the diff navigator hook and register the requested diff. > new_scroller.on('click', function() { > > === modified file 'lib/lp/code/stories/branches/xx-code-review-comments.txt' > --- lib/lp/code/stories/branches/xx-code-review-comments.txt 2012-01-15 > 13:32:27 +0000 > +++ lib/lp/code/stories/branches/xx-code-review-comments.txt 2014-05-15 > 03:58:24 +0000 > @@ -189,3 +189,84 @@ > Testing commits in conversation > 4. By ... on 2009-09-12 > and it works! > + > + > +Inline Comments > +--------------- > + > +The code review inline comments support is entirely implemented in > +Javascript. The current implementation relies on comments being > +rendered with the following 'data-' attributes: > + > + # Created a new review comment with associated inline comments > + # on the superseded and on the new MP. > + >>> from lp.services.features.testing import FeatureFixture > + >>> fixture = FeatureFixture( > + ... {'code.inline_diff_comments.enabled': 'enabled'}) > + > + >>> login('foo....@canonical.com') > + >>> fixture.setUp() > + >>> previewdiff = factory.makePreviewDiff(merge_proposal=merge_proposal) > + >>> new_previewdiff = factory.makePreviewDiff( > + ... merge_proposal=new_merge_proposal) > + >>> transaction.commit() > + >>> comment = merge_proposal.createComment( > + ... eric, None, content='a_content', > + ... previewdiff_id=previewdiff.id, > + ... inline_comments={'1': 'No!'} > + ... ) > + >>> transaction.commit() > + >>> comment = new_merge_proposal.createComment( > + ... eric, None, content='a_content', > + ... previewdiff_id=new_previewdiff.id, > + ... inline_comments={'1': 'Yes!'} > + ... ) > + >>> fixture.cleanUp() > + >>> logout() > + > + # helper for printing review comment 'data-' attributes. > + >>> def print_comment_attributes(contents): > + ... comments = find_tags_by_class(contents, 'boardCommentDetails') > + ... print 'Text', 'Comment', 'Diff', 'Superseded' > + ... for comment in comments: > + ... tds = comment.findAll('td') > + ... if len(tds) == 0: > + ... continue > + ... td = tds[0] > + ... print ' '.join( > + ... (extract_text(td), > + ... td['data-comment-id'], > + ... td.get('data-previewdiff-id', '-'), > + ... td.get('data-from-superseded', '-'))) > + > +The 'data-' attributes: > + > + * 'comment-id': The review comment ID, used to highlight related > + * inline comments. > + * 'previewdiff-id': used to load the corresponding `PreviewDiff`. > + * 'from_superseded': 'True' or 'False' whether the context MP is > + superseded by another. Used to supress context > + handlers on superseded comments. > + > +They are always available in `BranchMergeProposal` pages. > + > + >>> anon_browser.open(merge_proposal_url) > + >>> print_comment_attributes(anon_browser.contents) > + Text Comment Diff Superseded > + Eric... 1 - False > + Eric... 2 - False > + Eric... 3 - False > + Eric... 4 1 False > + > +When visualized in the new merge proposal the comments from the original > +merge proposal are marked as 'superseded' and there is a new and > +non-superseded local comment. > + > + >>> anon_browser.open(new_merge_proposal_url) > + >>> print_comment_attributes(anon_browser.contents) > + Text Comment Diff Superseded > + Eric... 1 - True > + Eric... 2 - True > + Eric... 3 - True > + Eric... 4 1 True > + Eric... 5 2 False > > === modified file 'lib/lp/code/templates/branchmergeproposal-index.pt' > --- lib/lp/code/templates/branchmergeproposal-index.pt 2014-04-04 > 04:47:15 +0000 > +++ lib/lp/code/templates/branchmergeproposal-index.pt 2014-05-15 > 03:58:24 +0000 > @@ -144,7 +144,6 @@ > <div id="add-comment-review-fields"> > Review: <tal:review replace="structure > comment_form/widgets/vote"/> > Review type: <tal:review replace="structure > comment_form/widgets/review_type"/> > - <tal:publish_inline_comments > condition="features/code.inline_diff_comments.enabled">Publish inline > comments: <tal:review replace="structure > comment_form/widgets/publish_inline_comments" > tal:condition="features/code.inline_diff_comments.enabled"/></tal:publish_inline_comments> > <div class="actions" > tal:content="structure > comment_form/actions/field.actions.add/render" /> > </div> > > === modified file 'lib/lp/code/templates/codereviewcomment-header.pt' > --- lib/lp/code/templates/codereviewcomment-header.pt 2014-04-03 20:33:08 > +0000 > +++ lib/lp/code/templates/codereviewcomment-header.pt 2014-05-15 03:58:24 > +0000 > @@ -6,7 +6,9 @@ > <table> > <tbody> > <tr> > - <td> > + <td tal:attributes="data-previewdiff-id context/previewdiff_id; > + data-from-superseded context/from_superseded; > + data-comment-id context/id"> > <span > itemprop="creator" > tal:content="structure > context/comment_author/fmt:link-display-name-id"/> > @@ -26,11 +28,6 @@ > tal:attributes="href context/branch_merge_proposal/fmt:url">a > previous version</a> > of this proposal</span> > - <span style="float: right;" tal:condition="context/previewdiff_id"> > - <a class="inline-comment-scroller" href="" > - tal:attributes="data-previewdiff-id context/previewdiff_id" > - >View inline comments</a> > - </span> > </td> > > <td class="bug-comment-index"> > -- https://code.launchpad.net/~cprov/launchpad/ic-superseded-mps/+merge/219431 Your team Launchpad code reviewers is subscribed to branch lp:launchpad. _______________________________________________ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp