diff --git a/extension.json b/extension.json index 118674ac86..0136e1958f 100644 --- a/extension.json +++ b/extension.json @@ -364,6 +364,7 @@ "visualeditor-loadwarning", "visualeditor-loadwarning-token", "visualeditor-savedialog-identify-anon", + "visualeditor-savedialog-identify-trylogin", "visualeditor-savedialog-identify-user", "visualeditor-timeout" ] diff --git a/modules/ve-mw/i18n/en.json b/modules/ve-mw/i18n/en.json index b00bfa58d7..0eef90b9f4 100644 --- a/modules/ve-mw/i18n/en.json +++ b/modules/ve-mw/i18n/en.json @@ -285,8 +285,9 @@ "visualeditor-preference-tabs-prefer-wt": "Always give me the wikitext editor", "visualeditor-preference-tabs-remember-last": "Remember my last editor", "visualeditor-recreate": "The page has been deleted since you started editing. Press \"$1\" to recreate it.", - "visualeditor-savedialog-error-badtoken": "We could not process your edit because the session was no longer valid.", + "visualeditor-savedialog-error-badtoken": "We could not save your edit because the session was no longer valid.", "visualeditor-savedialog-identify-anon": "Do you want to save this page as an anonymous user instead? Your IP address will be recorded in this page's edit history.", + "visualeditor-savedialog-identify-trylogin": "You are no longer logged in. Please log back in from a different tab and try again.", "visualeditor-savedialog-identify-user": "You are now logged in as [[User:$1|$1]]. Your edit will be associated with this account if you save this edit.", "visualeditor-savedialog-label-create": "Create page", "visualeditor-savedialog-label-error": "Error", diff --git a/modules/ve-mw/i18n/qqq.json b/modules/ve-mw/i18n/qqq.json index 1c8bfd0b8b..9fda7447aa 100644 --- a/modules/ve-mw/i18n/qqq.json +++ b/modules/ve-mw/i18n/qqq.json @@ -298,6 +298,7 @@ "visualeditor-recreate": "Text shown when the editor fails to save the page due to it having been deleted since they opened VE. $1 is the message {{msg-mw|ooui-dialog-process-continue}}.", "visualeditor-savedialog-error-badtoken": "Error displayed in the save dialog if saving the edit failed due to an invalid edit token (likely due to the user having logged out in a separate window, or logged in again)", "visualeditor-savedialog-identify-anon": "Displayed in the save dialog if saving failed because the session expired and the session is now an anonymous user. Warning about IP address being recorded is based on {{msg-mw|anoneditwarning}}.\n\n{{format|jquerymsg}}", + "visualeditor-savedialog-identify-trylogin": "Displayed in the save dialog if saving failed because the session expired and we also encountered an error while trying to figure out for which user the current session. This is usually due to the user getting logged out on a private wiki.", "visualeditor-savedialog-identify-user": "Displayed in the save dialog if saving failed because the session expired and the session is now for a different user account.\n{{format|jquerymsg}}\nParameters:\n* $1 - username", "visualeditor-savedialog-label-create": "Label text for save button when the user is creating a new page\n{{Identical|Create page}}", "visualeditor-savedialog-label-error": "Label in front of a save dialog error sentence, separated by {{msg-mw|colon-separator}}.\n{{Identical|Error}}", diff --git a/modules/ve-mw/init/ve.init.mw.ArticleTarget.js b/modules/ve-mw/init/ve.init.mw.ArticleTarget.js index 8a6e234014..d95ea1a3d0 100644 --- a/modules/ve-mw/init/ve.init.mw.ArticleTarget.js +++ b/modules/ve-mw/init/ve.init.mw.ArticleTarget.js @@ -104,8 +104,9 @@ OO.inheritClass( ve.init.mw.ArticleTarget, ve.init.mw.Target ); /** * @event saveErrorBadToken - * Fired on save if we have to fetch a new edit token - * this is mainly for analytical purposes. + * @param {boolean} willRetry Whether an automatic retry will occur + * Fired on save if we have to fetch a new edit token. + * This is mainly for analytical purposes. */ /** @@ -423,9 +424,6 @@ ve.init.mw.ArticleTarget.prototype.saveFail = function ( doc, saveData, jqXHR, s indexpageids: '', intoken: 'edit' } ) - .always( function () { - target.saveErrorBadToken(); - } ) .done( function ( data ) { var userInfo = data.query && data.query.userinfo, @@ -443,7 +441,8 @@ ve.init.mw.ArticleTarget.prototype.saveFail = function ( doc, saveData, jqXHR, s // normalisation and against case where the user got renamed. mw.config.get( 'wgUserId' ) === userInfo.id ) { - // New session is the same user still + // New session is the same user still; retry + target.emit( 'saveErrorBadToken', true ); target.save( doc, saveData ); } else { // The now current session is a different user @@ -456,14 +455,17 @@ ve.init.mw.ArticleTarget.prototype.saveFail = function ( doc, saveData, jqXHR, s // functions like mw.user.isAnon rely on this. wgUserName: null } ); - target.saveErrorNewUser( null ); + target.saveErrorBadToken( null, false ); } else { // New session is a different user mw.config.set( { wgUserId: userInfo.id, wgUserName: userInfo.name } ); - target.saveErrorNewUser( userInfo.name ); + target.saveErrorBadToken( userInfo.name, false ); } } } + } ) + .fail( function () { + target.saveErrorBadToken( null, true ); } ); return; } else if ( data.error && data.error.code === 'editconflict' ) { @@ -629,24 +631,31 @@ ve.init.mw.ArticleTarget.prototype.saveErrorTitleBlacklist = function () { }; /** - * Handle token fetch indicating another user is logged in + * Handle token fetch indicating another user is logged in, and token fetch errors. * * @method * @param {string|null} username Name of newly logged-in user, or null if anonymous + * @param {boolean} [error=false] Whether there was an error trying to figure out who we're logged in as + * @fires saveErrorBadToken * @fires saveErrorNewUser */ -ve.init.mw.ArticleTarget.prototype.saveErrorNewUser = function ( username ) { - var badToken, userMsg; - badToken = document.createTextNode( mw.msg( 'visualeditor-savedialog-error-badtoken' ) + ' ' ); - if ( username === null ) { - userMsg = 'visualeditor-savedialog-identify-anon'; +ve.init.mw.ArticleTarget.prototype.saveErrorBadToken = function ( username, error ) { + var userMsg, + $msg = $( document.createTextNode( mw.msg( 'visualeditor-savedialog-error-badtoken' ) + ' ' ) ); + + if ( error ) { + this.emit( 'saveErrorBadToken', false ); + $msg = $msg.add( document.createTextNode( mw.msg( 'visualeditor-savedialog-identify-trylogin' ) ) ); } else { - userMsg = 'visualeditor-savedialog-identify-user'; + this.emit( 'saveErrorNewUser' ); + if ( username === null ) { + userMsg = 'visualeditor-savedialog-identify-anon'; + } else { + userMsg = 'visualeditor-savedialog-identify-user'; + } + $msg = $msg.add( $.parseHTML( mw.message( userMsg, username ).parse() ) ); } - this.showSaveError( - $( badToken ).add( $.parseHTML( mw.message( userMsg, username ).parse() ) ) - ); - this.emit( 'saveErrorNewUser' ); + this.showSaveError( $msg ); }; /** @@ -671,16 +680,6 @@ ve.init.mw.ArticleTarget.prototype.saveErrorUnknown = function ( editApi, data ) this.emit( 'saveErrorUnknown', errorMsg ); }; -/** - * Handle a bad token - * - * @method - * @fires saveErrorBadToken - */ -ve.init.mw.ArticleTarget.prototype.saveErrorBadToken = function () { - this.emit( 'saveErrorBadToken' ); -}; - /** * Handle captcha error *