+2011-02-09 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ save overall comments when saving drafts in the review tool
+ https://bugs.webkit.org/show_bug.cgi?id=54165
+
+ -save overall comments in localstorage as well
+ -save all draft comments as you type
+ -give a *subtle* indicator of saved state
+
+ The latter should also make it super easy if someone wanted to do
+ the work to store draft comments in appengine/s3/bugzilla/etc.
+
+ * PrettyPatch/PrettyPatch.rb:
+ * code-review-test.html:
+ * code-review.js:
+
2011-02-08 Ojan Vafai <ojan@chromium.org>
Reviewed by Adam Barth.
'draft-comments-for-attachment-1': '{"born-on": 100, "comments":[]}',
'draft-comments-for-attachment-2': '{"born-on": 100, "comments":[{"start_line_id": 1, "end_line_id": 2, "contents": "DUMMY CONTENTS"}, {"start_line_id": 3, "end_line_id": 4, "contents": "DUMMY CONTENTS 2"}]}'
};
-var comments = new MockDraftCommentSaver('2', ls).saved_comments();
+var comments = new MockDraftCommentSaver('2', ls).saved_comments().comments;
ASSERT_EQUAL(comments.length, 2);
ASSERT_EQUAL(ls.log_string(), 'getItem:draft-comments-for-attachment-2');
ls.localStorageStore = {
'draft-comments-for-attachment-1': 'corrupt comments'
};
-var comments = new MockDraftCommentSaver('1', ls).saved_comments();
+var comments = new MockDraftCommentSaver('1', ls).saved_comments().comments;
ASSERT_EQUAL(ls.log_string(), 'getItem:draft-comments-for-attachment-1\nremoveItem:draft-comments-for-attachment-1');
var ls = new MockLocalStorage();
ls.localStorageStore = {
'draft-comments-for-attachment-1': '["also corrupt comments"]'
};
-var comments = new MockDraftCommentSaver('1', ls).saved_comments();
+var comments = new MockDraftCommentSaver('1', ls).saved_comments().comments;
ASSERT_EQUAL(ls.log_string(), 'getItem:draft-comments-for-attachment-1\nremoveItem:draft-comments-for-attachment-1');
g_displayed_draft_comments = true;
var comments = g_draftCommentSaver.saved_comments();
- $(comments).each(function() {
+ $(comments.comments).each(function() {
addDraftComment(this.start_line_id, this.end_line_id, this.contents);
});
+
+ var overall_comments = comments['overall-comments'];
+ if (overall_comments) {
+ openOverallComments();
+ $('.overallComments textarea').val(overall_comments);
+ }
}
function DraftCommentSaver(opt_attachment_id, opt_localStorage) {
});
});
- return JSON.stringify({'born-on': Date.now(), 'comments': comment_store});
+ var overall_comments = $('.overallComments textarea').val().trim();
+ return JSON.stringify({'born-on': Date.now(), 'comments': comment_store, 'overall-comments': overall_comments});
}
DraftCommentSaver.prototype.saved_comments = function() {
if (!serialized_comments)
return [];
- var comments = [];
+ var comments = {};
try {
- comments = JSON.parse(serialized_comments).comments;
+ comments = JSON.parse(serialized_comments);
} catch (e) {
this._erase_corrupt_comments();
- return [];
+ return {};
}
- if (comments && !comments.length)
+ var individual_comments = comments.comments;
+ if (comments && !individual_comments.length)
return comments;
// Sanity check comments are as expected.
- if (!comments || !comments[0].contents) {
+ if (!comments || !individual_comments[0].contents) {
this._erase_corrupt_comments();
- return [];
+ return {};
}
return comments;
function saveDraftComments() {
ensureDraftCommentsDisplayed();
g_draftCommentSaver.save();
+ setAutoSaveStateIndicator('saved');
+ }
+
+ function setAutoSaveStateIndicator(state) {
+ var container = $('.autosave-state');
+ container.text(state);
+
+ if (state == 'saving')
+ container.addClass(state);
+ else
+ container.removeClass('saving');
}
function createCommentFor(line) {
line.addClass('commentContext');
var comment_block = $('<div class="comment"><textarea data-comment-for="' + line.attr('id') + '"></textarea><div class="actions"><button class="ok">OK</button><button class="discard">Discard</button></div></div>');
+ $('textarea', comment_block).bind('input', handleOverallCommentsInput);
insertCommentFor(line, comment_block);
return comment_block;
}
$('#statusBubbleContainer').addClass('wrap');
}
+ var g_overallCommentsInputTimer;
+
+ function handleOverallCommentsInput() {
+ setAutoSaveStateIndicator('saving');
+ // Save draft comments after we haven't received an input event in 1 second.
+ if (g_overallCommentsInputTimer)
+ clearTimeout(g_overallCommentsInputTimer);
+ g_overallCommentsInputTimer = setTimeout(saveDraftComments, 1000);
+ }
+
function onBodyResize() {
updateToolbarAnchorState();
}
'<a href="javascript:" class="side-by-side-link">side-by-side</a>';
}
-
$(document).ready(function() {
crawlDiff();
fetchHistory();
'<button id="post_comments">Publish</button> ' +
'</span>' +
'</div>' +
+ '<div class="autosave-state"></div>' +
'</div>');
$('.overallComments textarea').bind('click', openOverallComments);
+ $('.overallComments textarea').bind('input', handleOverallCommentsInput);
$(document.body).prepend('<div id="comment_form" class="inactive"><div class="winter"></div><div class="lightbox"><iframe id="reviewform" src="attachment.cgi?id=' + attachment_id + '&action=reviewform"></iframe></div></div>');
$('#reviewform').bind('load', handleReviewFormLoad);