Try to resolve edit conflicts

The most common case of edit conflicts on talk pages is several people
responding to the same comment at the same time.[citation needed]

We can easily resolve this case by fetching the latest revision of the
page and re-running our code to insert a reply on it.

When we can't insert a reply, that probably means the parent comment
was deleted or moved, so display an error message indicating that
instead of the generic one.

Bug: T240643
Change-Id: Ic686acc747580d46779960211a02e9830a6ae86f
This commit is contained in:
Bartosz Dziewoński 2020-02-15 05:31:06 +01:00
parent 6f404e5ce2
commit 7ea6cdf326
5 changed files with 32 additions and 2 deletions

View file

@ -58,6 +58,7 @@
"ext.discussionTools.modifier" "ext.discussionTools.modifier"
], ],
"messages": [ "messages": [
"discussiontools-error-comment-disappeared",
"discussiontools-defaultsummary-reply", "discussiontools-defaultsummary-reply",
"discussiontools-replylink", "discussiontools-replylink",
"discussiontools-replywidget-loading" "discussiontools-replywidget-loading"

View file

@ -12,6 +12,7 @@
"discussiontools-replywidget-preview": "Preview", "discussiontools-replywidget-preview": "Preview",
"discussiontools-replywidget-reply": "Reply", "discussiontools-replywidget-reply": "Reply",
"discussiontools-replywidget-terms-click": "By clicking \"$1\", you agree to the terms of use for this wiki.", "discussiontools-replywidget-terms-click": "By clicking \"$1\", you agree to the terms of use for this wiki.",
"discussiontools-error-comment-disappeared": "Could not find the comment you're replying to on the page. It might have been deleted or moved to another page. Please reload the page and try again.",
"tag-discussiontools": "DiscussionTools edit", "tag-discussiontools": "DiscussionTools edit",
"tag-discussiontools-description": "Edit made using DiscussionTools", "tag-discussiontools-description": "Edit made using DiscussionTools",
"tag-discussiontools-edit": "edited comment", "tag-discussiontools-edit": "edited comment",

View file

@ -16,6 +16,7 @@
"discussiontools-replywidget-preview": "Label for the preview area of the reply widget", "discussiontools-replywidget-preview": "Label for the preview area of the reply widget",
"discussiontools-replywidget-reply": "Label for the button to submit a reply in the reply widget", "discussiontools-replywidget-reply": "Label for the button to submit a reply in the reply widget",
"discussiontools-replywidget-terms-click": "Terms of use for posting a reply.\n\n* $1 is the label of the button to be clicked, e.g. {{msg-mw|discussiontools-replywidget-reply}}.", "discussiontools-replywidget-terms-click": "Terms of use for posting a reply.\n\n* $1 is the label of the button to be clicked, e.g. {{msg-mw|discussiontools-replywidget-reply}}.",
"discussiontools-error-comment-disappeared": "Error message.",
"tag-discussiontools": "Short description of the discussiontools tag.\n\nShown on lists of changes (history, recentchanges, etc.) for each edit made using DiscussionTools.\n\nSee also:\n* {{msg-mw|Tag-discussiontools-description}}", "tag-discussiontools": "Short description of the discussiontools tag.\n\nShown on lists of changes (history, recentchanges, etc.) for each edit made using DiscussionTools.\n\nSee also:\n* {{msg-mw|Tag-discussiontools-description}}",
"tag-discussiontools-description": "Long description of the discussiontools tag ({{msg-mw|Tag-discussiontools}}).\n\nShown on [[Special:Tags]].\n\nSee also:\n* {{msg-mw|Tag-discussiontools}}", "tag-discussiontools-description": "Long description of the discussiontools tag ({{msg-mw|Tag-discussiontools}}).\n\nShown on [[Special:Tags]].\n\nSee also:\n* {{msg-mw|Tag-discussiontools}}",
"tag-discussiontools-edit": "Short description of the discussiontools-edit tag.\n\nShown on lists of changes (history, recentchanges, etc.) for each edit to an existing comment made using DiscussionTools.\n\nThis message is always shown directly after {{msg-mw|tag-discussiontools}} and a comma.\n\nSee also:\n* {{msg-mw|Tag-discussiontools-edit-description}}\n* {{Related|tag-discussiontools}}", "tag-discussiontools-edit": "Short description of the discussiontools-edit tag.\n\nShown on lists of changes (history, recentchanges, etc.) for each edit to an existing comment made using DiscussionTools.\n\nThis message is always shown directly after {{msg-mw|tag-discussiontools}} and a comma.\n\nSee also:\n* {{msg-mw|Tag-discussiontools-edit-description}}\n* {{Related|tag-discussiontools}}",

View file

@ -212,7 +212,10 @@ function getParsoidCommentData( pageName, oldId, commentId ) {
parsoidCommentsById = commentsById( parsoidComments ); parsoidCommentsById = commentsById( parsoidComments );
if ( !parsoidCommentsById[ commentId ] ) { if ( !parsoidCommentsById[ commentId ] ) {
throw new Error( 'Could not find comment in Parsoid HTML' ); return $.Deferred().reject( 'comment-disappeared', { errors: [ {
code: 'comment-disappeared',
html: mw.message( 'discussiontools-error-comment-disappeared' ).parse()
} ] } ).promise();
} }
return { return {

View file

@ -253,6 +253,30 @@ ReplyWidget.prototype.onReplyClick = function () {
// We must get a new copy of the document every time, otherwise any unsaved replies will pile up // We must get a new copy of the document every time, otherwise any unsaved replies will pile up
this.getParsoidCommentData().then( function ( parsoidData ) { this.getParsoidCommentData().then( function ( parsoidData ) {
return controller.postReply( widget, parsoidData ); return controller.postReply( widget, parsoidData );
} ).catch( function ( code, data ) {
// Handle edit conflicts. Load the latest revision of the page, then try again. If the parent
// comment has been deleted from the page, or if retry also fails for some other reason, the
// error is handled as normal below.
if ( code === 'editconflict' ) {
return widget.api.get( {
action: 'query',
prop: 'revisions',
rvprop: 'ids',
rvlimit: 1,
titles: mw.config.get( 'wgRelevantPageName' ),
formatversion: 2
} ).then( function ( resp ) {
var latestRevId = resp.query.pages[ 0 ].revisions[ 0 ].revid;
mw.config.set( {
wgCurRevisionId: latestRevId,
wgRevisionId: latestRevId
} );
return widget.getParsoidCommentData().then( function ( parsoidData ) {
return controller.postReply( widget, parsoidData );
} );
} );
}
return $.Deferred().reject( code, data ).promise();
} ).then( function ( data ) { } ).then( function ( data ) {
// eslint-disable-next-line no-jquery/no-global-selector // eslint-disable-next-line no-jquery/no-global-selector
var $container = $( '#mw-content-text' ); var $container = $( '#mw-content-text' );
@ -279,7 +303,7 @@ ReplyWidget.prototype.onReplyClick = function () {
}, function ( code, data ) { }, function ( code, data ) {
widget.errorMessage = new OO.ui.MessageWidget( { widget.errorMessage = new OO.ui.MessageWidget( {
type: 'error', type: 'error',
label: ( new mw.Api() ).getErrorMessage( data ) label: widget.api.getErrorMessage( data )
} ); } );
widget.errorMessage.$element.insertBefore( widget.replyBodyWidget.$element ); widget.errorMessage.$element.insertBefore( widget.replyBodyWidget.$element );
} ).always( function () { } ).always( function () {