jenkins-bot has submitted this change and it was merged. Change subject: Port MWSaveDialog to use ActionDialog ......................................................................
Port MWSaveDialog to use ActionDialog Relies on Id17d150d Change-Id: I80dd89fa7ad55daa3ae7e9c01c4a78f6e54105ca --- M VisualEditor.php M modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js M modules/ve-mw/init/ve.init.mw.Target.js M modules/ve-mw/ui/dialogs/ve.ui.MWSaveDialog.js 4 files changed, 98 insertions(+), 65 deletions(-) Approvals: Catrope: Looks good to me, approved jenkins-bot: Verified diff --git a/VisualEditor.php b/VisualEditor.php index 64e1cd4..c20fdd3 100644 --- a/VisualEditor.php +++ b/VisualEditor.php @@ -522,6 +522,7 @@ 'visualeditor-dialog-action-goback', 'visualeditor-dialog-command-help-title', 'visualeditor-dialog-error', + 'visualeditor-dialog-error-dismiss', 'visualeditor-dialog-media-size-originalsize-error', 'visualeditor-dimensionswidget-px', 'visualeditor-dimensionswidget-times', diff --git a/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js b/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js index 9b42d50..32bba16 100644 --- a/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js +++ b/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js @@ -88,8 +88,6 @@ this.connect( this, { 'save': 'onSave', 'saveErrorEmpty': 'onSaveErrorEmpty', - 'saveAsyncBegin': 'onSaveAsyncBegin', - 'saveAsyncComplete': 'onSaveAsyncComplete', 'saveErrorSpamBlacklist': 'onSaveErrorSpamBlacklist', 'saveErrorAbuseFilter': 'onSaveErrorAbuseFilter', 'saveErrorBadToken': 'onSaveErrorBadToken', @@ -425,6 +423,7 @@ */ ve.init.mw.ViewPageTarget.prototype.onSave = function ( html, categoriesHtml, newid, isRedirect ) { var newUrlParams, watchChecked; + this.saveDeferred.resolve(); if ( !this.pageExists || this.restoring ) { // This is a page creation or restoration, refresh the page this.tearDownBeforeUnloadHandler(); @@ -478,33 +477,12 @@ }; /** - * Update save dialog when async begins - * - * @method - */ -ve.init.mw.ViewPageTarget.prototype.onSaveAsyncBegin = function () { - this.saveDialog.saveButton.setDisabled( true ); - this.saveDialog.pushPending(); -}; - -/** - * Update save dialog when async completes - * - * @method - */ -ve.init.mw.ViewPageTarget.prototype.onSaveAsyncComplete = function () { - this.saveDialog.saveButton.setDisabled( false ); - this.saveDialog.popPending(); -}; - -/** * Update save dialog message on general error * * @method */ ve.init.mw.ViewPageTarget.prototype.onSaveErrorEmpty = function () { - this.showSaveError( ve.msg( 'visualeditor-saveerror', 'Empty server response' ) ); - this.saveDialog.saveButton.setDisabled( true ); + this.showSaveError( ve.msg( 'visualeditor-saveerror', 'Empty server response' ), false /* prevents reapply */ ); this.events.trackSaveError( 'empty' ); }; @@ -517,9 +495,9 @@ ve.init.mw.ViewPageTarget.prototype.onSaveErrorSpamBlacklist = function ( editApi ) { this.showSaveError( // TODO: Use mediawiki.language equivalant of Language.php::listToText once it exists - ve.msg( 'spamprotectiontext' ) + ' ' + ve.msg( 'spamprotectionmatch', editApi.spamblacklist.split( '|' ).join( ', ' ) ) + ve.msg( 'spamprotectiontext' ) + ' ' + ve.msg( 'spamprotectionmatch', editApi.spamblacklist.split( '|' ).join( ', ' ) ), + false // prevents reapply ); - this.saveDialog.saveButton.setDisabled( true ); this.events.trackSaveError( 'spamblacklist' ); }; @@ -530,7 +508,7 @@ * @param {Object} editApi */ ve.init.mw.ViewPageTarget.prototype.onSaveErrorAbuseFilter = function ( editApi ) { - this.showSaveError( $.parseHTML( editApi.warning ), false ); + this.showSaveError( $( $.parseHTML( editApi.warning ) ) ); // Don't disable the save button. If the action is not disallowed the user may save the // edit by pressing Save again. The AbuseFilter API currently has no way to distinguish // between filter triggers that are and aren't disallowing the action. @@ -563,10 +541,8 @@ userMsg = 'visualeditor-savedialog-identify-user---' + mw.config.get( 'wgUserName' ); } this.showSaveError( - $( badToken ).add( $.parseHTML( mw.message( userMsg ).parse() ) ), - 'warning' + $( badToken ).add( $.parseHTML( mw.message( userMsg ).parse() ) ) ); - this.saveDialog.saveButton.setDisabled( false ); }; /** @@ -612,7 +588,13 @@ } $captchaDiv.append( this.captcha.input.$element ); - this.showSaveError( $captchaDiv, false ); + + // ActionDialog's error system isn't great for this yet. + //this.showSaveError( $captchaDiv ); + this.saveDialog.clearMessage( 'api-save-error' ); + this.saveDialog.showMessage( 'api-save-error', $captchaDiv ); + this.saveDialog.popPending(); + this.events.trackSaveError( 'captcha' ); }; @@ -625,15 +607,15 @@ */ ve.init.mw.ViewPageTarget.prototype.onSaveErrorUnknown = function ( editApi, data ) { this.showSaveError( - document.createTextNode( + $( document.createTextNode( ( editApi && editApi.info ) || ( data.error && data.error.info ) || ( editApi && editApi.code ) || ( data.error && data.error.code ) || 'Unknown error' - ) + ) ), + false // prevents reapply ); - this.saveDialog.saveButton.setDisabled( true ); this.events.trackSaveError( 'unknown' ); }; @@ -643,13 +625,11 @@ * @method * @param {string|jQuery|Node[]} msg Message content (string of HTML, jQuery object or array of * Node objects) - * @param {string|boolean} wrap Whether to wrap the message in a paragraph and if - * so, how. One of "warning", "error" or false. + * @param {boolean} [allowReapply=true] Whether or not to allow the user to reapply. + * Reset when swapping panels. Assumed to be true unless explicitly set to false. */ -ve.init.mw.ViewPageTarget.prototype.showSaveError = function ( msg, wrap ) { - wrap = wrap || 'error'; - this.saveDialog.clearMessage( 'api-save-error' ); - this.saveDialog.showMessage( 'api-save-error', msg, { 'wrap': wrap } ); +ve.init.mw.ViewPageTarget.prototype.showSaveError = function ( msg, allowReapply ) { + this.saveDeferred.reject( [ msg ], allowReapply ); }; /** @@ -870,8 +850,10 @@ /** * Try to save the current document. * @fires saveInitiated + * @param {jQuery.Deferred} saveDeferred Deferred object to resolve/reject when the save + * succeeds/fails. */ -ve.init.mw.ViewPageTarget.prototype.saveDocument = function () { +ve.init.mw.ViewPageTarget.prototype.saveDocument = function ( saveDeferred ) { var saveOptions = this.getSaveOptions(); this.emit( 'saveInitiated' ); @@ -893,9 +875,8 @@ { wrap: false } ); } else { - this.saveDialog.saveButton.setDisabled( true ); - this.saveDialog.pushPending(); this.save( this.docToSave, saveOptions ); + this.saveDeferred = saveDeferred; } }; diff --git a/modules/ve-mw/init/ve.init.mw.Target.js b/modules/ve-mw/init/ve.init.mw.Target.js index bc11bed..4f1b553 100644 --- a/modules/ve-mw/init/ve.init.mw.Target.js +++ b/modules/ve-mw/init/ve.init.mw.Target.js @@ -556,8 +556,6 @@ * @param {Object} jqXHR * @param {string} status Text status message * @param {Object|null} data API response data - * @fires saveAsyncBegin - * @fires saveAsyncComplete * @fires saveErrorEmpty * @fires saveErrorSpamBlacklist * @fires saveErrorAbuseFilter @@ -570,7 +568,6 @@ var api, editApi, viewPage = this; this.saving = false; - this.emit( 'saveAsyncComplete' ); // Handle empty response if ( !data ) { @@ -595,7 +592,6 @@ // Handle token errors if ( data.error && data.error.code === 'badtoken' ) { api = new mw.Api(); - this.emit( 'saveAsyncBegin' ); api.get( { // action=query&meta=userinfo and action=tokens&type=edit can't be combined // but action=query&meta=userinfo and action=query&prop=info can, however @@ -611,7 +607,6 @@ } ) .always( function () { viewPage.emit( 'saveErrorBadToken' ); - viewPage.emit( 'saveAsyncComplete' ); } ) .done( function ( data ) { var userMsg, diff --git a/modules/ve-mw/ui/dialogs/ve.ui.MWSaveDialog.js b/modules/ve-mw/ui/dialogs/ve.ui.MWSaveDialog.js index 7a23807..97e072d 100644 --- a/modules/ve-mw/ui/dialogs/ve.ui.MWSaveDialog.js +++ b/modules/ve-mw/ui/dialogs/ve.ui.MWSaveDialog.js @@ -14,14 +14,14 @@ * noted otherwise. * * @class - * @extends ve.ui.Dialog + * @extends ve.ui.ActionDialog * * @constructor * @param {Object} [config] Config options */ ve.ui.MWSaveDialog = function VeUiMWSaveDialog( config ) { // Parent constructor - ve.ui.Dialog.call( this, config ); + ve.ui.MWSaveDialog.super.call( this, config ); // Properties this.sanityCheckVerified = false; @@ -33,7 +33,7 @@ /* Inheritance */ -OO.inheritClass( ve.ui.MWSaveDialog, ve.ui.Dialog ); +OO.inheritClass( ve.ui.MWSaveDialog, ve.ui.ActionDialog ); /* Static Properties */ @@ -46,6 +46,8 @@ /** * @event save + * @param {jQuery.Deferred} saveDeferred Deferred object to resolve/reject when the save + * succeeds/fails. * Emitted when the user clicks the save button */ @@ -111,14 +113,15 @@ this.setTitle( ve.msg( 'visualeditor-savedialog-title-' + panel ) ); // Reset save button if we disabled it for e.g. unrecoverable spam error - this.saveButton.setDisabled( false ); + this.applyButton.setDisabled( false ); switch ( panel ) { case 'save': + this.isApplyable = true; if ( !this.sanityCheckVerified ) { this.showMessage( 'dirtywarning', mw.msg( 'visualeditor-savedialog-warning-dirty' ) ); } - this.saveButton.$element.show(); + this.applyButton.$element.show(); this.reviewButton.$element.show(); this.reviewGoodButton.$element.hide(); this.resolveConflictButton.$element.hide(); @@ -133,7 +136,7 @@ } ); break; case 'conflict': - this.saveButton.setDisabled( true ).$element.hide(); + this.applyButton.setDisabled( true ).$element.hide(); this.reviewButton.$element.hide(); this.reviewGoodButton.$element.hide(); this.resolveConflictButton.$element.show(); @@ -165,7 +168,7 @@ } /* falls through */ case 'nochanges': - this.saveButton.$element.hide(); + this.applyButton.$element.hide(); this.reviewButton.$element.hide(); this.reviewGoodButton.$element.show(); this.resolveConflictButton.$element.hide(); @@ -379,17 +382,9 @@ /* Buttons */ // Save button for "save" panel - this.saveButton = new OO.ui.ButtonWidget( { - 'label': ve.msg( - // visualeditor-savedialog-label-restore, visualeditor-savedialog-label-save - 'visualeditor-savedialog-label-' + ( this.restoring ? 'restore' : 'save' ) - ), - 'flags': ['constructive'] - } ); if ( ve.msg( 'accesskey-save' ) !== '-' && ve.msg( 'accesskey-save' ) !== '' ) { - this.saveButton.$button.attr( 'accesskey', ve.msg( 'accesskey-save' ) ); + this.applyButton.$button.attr( 'accesskey', ve.msg( 'accesskey-save' ) ); } - this.saveButton.connect( this, { 'click': [ 'emit', 'save' ] } ); // Review button for "save" panel this.reviewButton = new OO.ui.ButtonWidget( { @@ -413,7 +408,7 @@ this.$body.append( this.panel.$element ); this.$foot.append( this.reviewButton.$element, - this.saveButton.$element, + this.applyButton.$element, this.reviewGoodButton.$element, this.resolveConflictButton.$element ); @@ -443,6 +438,67 @@ }, this ); }; +/** + * @inheritdoc + */ +ve.ui.MWSaveDialog.prototype.getApplyButtonFlags = function () { + return [ 'constructive' ]; +}; + +/** + * @inheritdoc + */ +ve.ui.MWSaveDialog.prototype.getApplyButtonLabel = function () { + return ve.msg( + // visualeditor-savedialog-label-restore, visualeditor-savedialog-label-save + 'visualeditor-savedialog-label-' + ( this.restoring ? 'restore' : 'save' ) + ); +}; + +/** + * @inheritdoc + */ +ve.ui.MWSaveDialog.prototype.pushPending = function () { + // Parent method + ve.ui.MWSaveDialog.super.prototype.pushPending.call( this ); + + this.applyButton.setDisabled( !this.isApplyable || this.isPending() ); +}; + +/** + * @inheritdoc + */ +ve.ui.MWSaveDialog.prototype.popPending = function () { + // Parent method + ve.ui.MWSaveDialog.super.prototype.popPending.call( this ); + + this.applyButton.setDisabled( !this.isApplyable || this.isPending() ); +}; + +/** + * @inheritdoc + */ +ve.ui.MWSaveDialog.prototype.applyChanges = function () { + var saveDeferred = $.Deferred(); + this.emit( 'save', saveDeferred ); + return saveDeferred.promise(); +}; + +/* + * @inheritdoc + * @param {boolean} [allowReapply=true] Whether or not to allow the user to reapply. + * Reset when swapping panels. Assumed to be true unless explicitly set to false. + */ +ve.ui.MWSaveDialog.prototype.onApplyChangesFail = function ( errors, allowReapply ) { + if ( allowReapply === false ) { + this.isApplyable = false; + } + this.dismissErrors(); + + // Parent method + ve.ui.MWSaveDialog.super.prototype.onApplyChangesFail.call( this, errors ); +}; + /* Registration */ ve.ui.windowFactory.register( ve.ui.MWSaveDialog ); -- To view, visit https://gerrit.wikimedia.org/r/135945 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I80dd89fa7ad55daa3ae7e9c01c4a78f6e54105ca Gerrit-PatchSet: 11 Gerrit-Project: mediawiki/extensions/VisualEditor Gerrit-Branch: master Gerrit-Owner: Alex Monk <kren...@wikimedia.org> Gerrit-Reviewer: Alex Monk <kren...@wikimedia.org> Gerrit-Reviewer: Catrope <roan.katt...@gmail.com> Gerrit-Reviewer: Trevor Parscal <tpars...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits