Port MWSaveDialog to use ActionDialog

Relies on Id17d150d

Change-Id: I80dd89fa7ad55daa3ae7e9c01c4a78f6e54105ca
This commit is contained in:
Krenair 2014-05-28 23:05:17 +01:00 committed by Catrope
parent c92285e75f
commit 143c21999e
4 changed files with 98 additions and 65 deletions

View file

@ -522,6 +522,7 @@ $wgResourceModules += array(
'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',

View file

@ -88,8 +88,6 @@ ve.init.mw.ViewPageTarget = function VeInitMwViewPageTarget() {
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.onSurfaceReady = function () {
*/
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();
@ -477,34 +476,13 @@ ve.init.mw.ViewPageTarget.prototype.onSave = function ( html, categoriesHtml, ne
}
};
/**
* 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.onSaveErrorEmpty = function () {
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 @@ ve.init.mw.ViewPageTarget.prototype.onSaveErrorSpamBlacklist = function ( editAp
* @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 @@ ve.init.mw.ViewPageTarget.prototype.onSaveErrorNewUser = function ( isAnon ) {
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 @@ ve.init.mw.ViewPageTarget.prototype.onSaveErrorCaptcha = function ( editApi ) {
}
$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.onSaveErrorCaptcha = function ( editApi ) {
*/
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 @@ ve.init.mw.ViewPageTarget.prototype.onSaveErrorUnknown = function ( editApi, dat
* @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 @@ ve.init.mw.ViewPageTarget.prototype.onSaveDialogReviewComplete = function ( wiki
/**
* 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 @@ ve.init.mw.ViewPageTarget.prototype.saveDocument = function () {
{ wrap: false }
);
} else {
this.saveDialog.saveButton.setDisabled( true );
this.saveDialog.pushPending();
this.save( this.docToSave, saveOptions );
this.saveDeferred = saveDeferred;
}
};

View file

@ -556,8 +556,6 @@ ve.init.mw.Target.onSave = function ( doc, saveData, response ) {
* @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 @@ ve.init.mw.Target.prototype.onSaveError = function ( doc, saveData, jqXHR, statu
var api, editApi,
viewPage = this;
this.saving = false;
this.emit( 'saveAsyncComplete' );
// Handle empty response
if ( !data ) {
@ -595,7 +592,6 @@ ve.init.mw.Target.prototype.onSaveError = function ( doc, saveData, jqXHR, statu
// 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 @@ ve.init.mw.Target.prototype.onSaveError = function ( doc, saveData, jqXHR, statu
} )
.always( function () {
viewPage.emit( 'saveErrorBadToken' );
viewPage.emit( 'saveAsyncComplete' );
} )
.done( function ( data ) {
var userMsg,

View file

@ -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 @@ ve.ui.MWSaveDialog = function VeUiMWSaveDialog( config ) {
/* Inheritance */
OO.inheritClass( ve.ui.MWSaveDialog, ve.ui.Dialog );
OO.inheritClass( ve.ui.MWSaveDialog, ve.ui.ActionDialog );
/* Static Properties */
@ -46,6 +46,8 @@ ve.ui.MWSaveDialog.static.title =
/**
* @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 @@ ve.ui.MWSaveDialog.prototype.swapPanel = function ( panel ) {
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 @@ ve.ui.MWSaveDialog.prototype.swapPanel = function ( panel ) {
} );
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 @@ ve.ui.MWSaveDialog.prototype.swapPanel = function ( panel ) {
}
/* 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 @@ ve.ui.MWSaveDialog.prototype.initialize = function () {
/* 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 @@ ve.ui.MWSaveDialog.prototype.initialize = function () {
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 @@ ve.ui.MWSaveDialog.prototype.getReadyProcess = function ( data ) {
}, 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 );