2013-10-07 10:01:43 +00:00
|
|
|
/*!
|
|
|
|
* VisualEditor UserInterface MWSaveDialog class.
|
|
|
|
*
|
2016-01-03 22:56:59 +00:00
|
|
|
* @copyright 2011-2016 VisualEditor Team and others; see AUTHORS.txt
|
2013-10-07 10:01:43 +00:00
|
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2014-07-14 21:32:49 +00:00
|
|
|
* Dialog for saving MediaWiki pages.
|
2013-10-07 10:01:43 +00:00
|
|
|
*
|
2013-11-14 23:14:16 +00:00
|
|
|
* Note that most methods are not safe to call before the dialog has initialized, except where
|
|
|
|
* noted otherwise.
|
|
|
|
*
|
2013-10-07 10:01:43 +00:00
|
|
|
* @class
|
2015-07-31 12:15:31 +00:00
|
|
|
* @extends ve.ui.FragmentDialog
|
2013-10-07 10:01:43 +00:00
|
|
|
*
|
|
|
|
* @constructor
|
|
|
|
* @param {Object} [config] Config options
|
|
|
|
*/
|
2015-08-05 21:43:23 +00:00
|
|
|
ve.ui.MWSaveDialog = function VeUiMwSaveDialog( config ) {
|
2013-10-07 10:01:43 +00:00
|
|
|
// Parent constructor
|
2014-08-21 00:50:54 +00:00
|
|
|
ve.ui.MWSaveDialog.super.call( this, config );
|
2013-10-07 10:01:43 +00:00
|
|
|
|
|
|
|
// Properties
|
|
|
|
this.editSummaryByteLimit = 255;
|
|
|
|
this.restoring = false;
|
|
|
|
this.messages = {};
|
2013-11-14 23:14:16 +00:00
|
|
|
this.setupDeferred = $.Deferred();
|
2015-07-31 12:15:31 +00:00
|
|
|
this.target = null;
|
2015-08-13 16:39:24 +00:00
|
|
|
this.checkboxesByName = null;
|
2016-02-21 08:35:05 +00:00
|
|
|
this.changedEditSummary = false;
|
2015-08-05 21:43:23 +00:00
|
|
|
|
|
|
|
// Initialization
|
|
|
|
this.$element.addClass( 've-ui-mwSaveDialog' );
|
2013-10-07 10:01:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Inheritance */
|
|
|
|
|
2015-07-31 12:15:31 +00:00
|
|
|
OO.inheritClass( ve.ui.MWSaveDialog, ve.ui.FragmentDialog );
|
2013-10-07 10:01:43 +00:00
|
|
|
|
|
|
|
/* Static Properties */
|
|
|
|
|
|
|
|
ve.ui.MWSaveDialog.static.name = 'mwSave';
|
|
|
|
|
2014-02-12 21:45:37 +00:00
|
|
|
ve.ui.MWSaveDialog.static.title =
|
|
|
|
OO.ui.deferMsg( 'visualeditor-savedialog-title-save' );
|
2013-10-07 10:01:43 +00:00
|
|
|
|
2014-07-14 21:32:49 +00:00
|
|
|
ve.ui.MWSaveDialog.static.actions = [
|
|
|
|
{
|
2014-08-22 20:50:48 +00:00
|
|
|
action: 'save',
|
2016-06-30 14:01:24 +00:00
|
|
|
// May be overridden by config.saveButtonLabel
|
|
|
|
label: OO.ui.deferMsg( 'visualeditor-savedialog-label-review' ),
|
2014-08-22 20:50:48 +00:00
|
|
|
flags: [ 'primary', 'constructive' ],
|
2015-07-24 00:34:13 +00:00
|
|
|
modes: [ 'save', 'review' ],
|
2014-12-15 21:06:09 +00:00
|
|
|
accessKey: 's'
|
2014-07-14 21:32:49 +00:00
|
|
|
},
|
|
|
|
{
|
2014-09-11 18:52:21 +00:00
|
|
|
label: OO.ui.deferMsg( 'visualeditor-savedialog-label-resume-editing' ),
|
2015-08-06 13:34:32 +00:00
|
|
|
flags: [ 'safe', 'back' ],
|
2016-09-01 23:54:56 +00:00
|
|
|
modes: [ 'save', 'review', 'preview', 'conflict' ]
|
2014-07-14 21:32:49 +00:00
|
|
|
},
|
|
|
|
{
|
2014-08-22 20:50:48 +00:00
|
|
|
action: 'review',
|
|
|
|
label: OO.ui.deferMsg( 'visualeditor-savedialog-label-review' ),
|
2016-09-01 23:54:56 +00:00
|
|
|
modes: [ 'save', 'preview' ]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
action: 'preview',
|
|
|
|
label: OO.ui.deferMsg( 'showpreview' ),
|
|
|
|
modes: [ 'save', 'review' ]
|
2014-07-14 21:32:49 +00:00
|
|
|
},
|
|
|
|
{
|
2014-08-22 20:50:48 +00:00
|
|
|
action: 'approve',
|
|
|
|
label: OO.ui.deferMsg( 'visualeditor-savedialog-label-review-good' ),
|
2016-09-01 23:54:56 +00:00
|
|
|
modes: [ 'review', 'preview' ]
|
2014-07-14 21:32:49 +00:00
|
|
|
},
|
|
|
|
{
|
2014-08-22 20:50:48 +00:00
|
|
|
action: 'resolve',
|
|
|
|
label: OO.ui.deferMsg( 'visualeditor-savedialog-label-resolve-conflict' ),
|
|
|
|
flags: [ 'primary', 'constructive' ],
|
|
|
|
modes: 'conflict'
|
2014-07-14 21:32:49 +00:00
|
|
|
}
|
|
|
|
];
|
|
|
|
|
2013-11-14 23:14:16 +00:00
|
|
|
/* Events */
|
2013-10-07 10:01:43 +00:00
|
|
|
|
2013-11-14 23:14:16 +00:00
|
|
|
/**
|
|
|
|
* @event save
|
2014-05-28 22:05:17 +00:00
|
|
|
* @param {jQuery.Deferred} saveDeferred Deferred object to resolve/reject when the save
|
|
|
|
* succeeds/fails.
|
2013-11-14 23:14:16 +00:00
|
|
|
* Emitted when the user clicks the save button
|
|
|
|
*/
|
2013-10-07 10:01:43 +00:00
|
|
|
|
2013-11-14 23:14:16 +00:00
|
|
|
/**
|
|
|
|
* @event review
|
|
|
|
* Emitted when the user clicks the review changes button
|
|
|
|
*/
|
2013-10-07 10:01:43 +00:00
|
|
|
|
2016-09-01 23:54:56 +00:00
|
|
|
/**
|
|
|
|
* @event preview
|
|
|
|
* Emitted when the user clicks the show preview button
|
|
|
|
*/
|
|
|
|
|
2013-11-14 23:14:16 +00:00
|
|
|
/**
|
|
|
|
* @event resolve
|
|
|
|
* Emitted when the user clicks the resolve conflict button
|
|
|
|
*/
|
2013-10-07 10:01:43 +00:00
|
|
|
|
2014-10-30 00:36:02 +00:00
|
|
|
/**
|
|
|
|
* @event retry
|
|
|
|
* Emitted when the user clicks the retry/continue save button after an error.
|
|
|
|
*/
|
|
|
|
|
2013-11-14 23:14:16 +00:00
|
|
|
/* Methods */
|
2013-10-07 10:01:43 +00:00
|
|
|
|
2013-11-05 00:29:50 +00:00
|
|
|
/**
|
2013-11-14 23:14:16 +00:00
|
|
|
* Set review content and show review panel.
|
2013-11-05 00:29:50 +00:00
|
|
|
*
|
|
|
|
* @param {string} content Diff HTML or wikitext
|
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.setDiffAndReview = function ( content ) {
|
|
|
|
this.$reviewViewer.empty().append( content );
|
2014-08-22 20:50:48 +00:00
|
|
|
this.actions.setAbilities( { approve: true } );
|
2014-04-18 20:32:25 +00:00
|
|
|
this.popPending();
|
2013-11-05 00:29:50 +00:00
|
|
|
this.swapPanel( 'review' );
|
|
|
|
};
|
|
|
|
|
2016-09-01 23:54:56 +00:00
|
|
|
/**
|
|
|
|
* Set preview content and show preview panel.
|
|
|
|
*
|
|
|
|
* @param {string} content Preview HTML
|
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.showPreview = function ( content ) {
|
|
|
|
this.$previewViewer.html( content );
|
|
|
|
mw.hook( 'wikipage.content' ).fire( this.$previewViewer );
|
|
|
|
this.actions.setAbilities( { approve: true } );
|
|
|
|
this.popPending();
|
|
|
|
this.swapPanel( 'preview' );
|
|
|
|
};
|
|
|
|
|
2014-11-05 23:23:48 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.pushPending = function () {
|
2016-09-01 23:54:56 +00:00
|
|
|
this.getActions().setAbilities( { review: false, preview: false } );
|
2014-11-05 23:23:48 +00:00
|
|
|
return ve.ui.MWSaveDialog.super.prototype.pushPending.call( this );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.popPending = function () {
|
|
|
|
var ret = ve.ui.MWSaveDialog.super.prototype.popPending.call( this );
|
|
|
|
if ( !this.isPending() ) {
|
2016-09-01 23:54:56 +00:00
|
|
|
this.getActions().setAbilities( { review: true, preview: true } );
|
2014-11-05 23:23:48 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
};
|
|
|
|
|
2013-11-14 23:14:16 +00:00
|
|
|
/**
|
|
|
|
* Clear the diff displayed in the review panel, if any.
|
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.clearDiff = function () {
|
|
|
|
this.$reviewViewer.empty();
|
2016-09-01 23:54:56 +00:00
|
|
|
this.$previewViewer.empty();
|
2013-11-14 23:14:16 +00:00
|
|
|
};
|
|
|
|
|
2013-10-07 10:01:43 +00:00
|
|
|
/**
|
|
|
|
* Swap state in the save dialog.
|
|
|
|
*
|
|
|
|
* @param {string} panel One of 'save', 'review', 'conflict' or 'nochanges'
|
2015-08-19 18:09:34 +00:00
|
|
|
* @return {jQuery} The now active panel
|
2013-10-07 10:01:43 +00:00
|
|
|
* @throws {Error} Unknown saveDialog panel
|
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.swapPanel = function ( panel ) {
|
2014-02-10 18:33:13 +00:00
|
|
|
var currentEditSummaryWikitext,
|
2016-10-27 00:56:18 +00:00
|
|
|
mode = panel,
|
2015-09-21 17:19:53 +00:00
|
|
|
size = 'medium',
|
2014-02-10 18:33:13 +00:00
|
|
|
dialog = this,
|
2015-08-19 17:33:02 +00:00
|
|
|
panelObj = dialog[ panel + 'Panel' ];
|
2013-10-07 10:01:43 +00:00
|
|
|
|
2016-09-01 23:54:56 +00:00
|
|
|
if ( ( [ 'save', 'review', 'preview', 'conflict', 'nochanges' ].indexOf( panel ) ) === -1 ) {
|
2013-10-07 10:01:43 +00:00
|
|
|
throw new Error( 'Unknown saveDialog panel: ' + panel );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the window title
|
2014-07-28 12:08:39 +00:00
|
|
|
// The following messages can be used here:
|
|
|
|
// visualeditor-savedialog-title-conflict
|
|
|
|
// visualeditor-savedialog-title-nochanges
|
2016-09-01 23:54:56 +00:00
|
|
|
// visualeditor-savedialog-title-preview
|
|
|
|
// visualeditor-savedialog-title-review
|
|
|
|
// visualeditor-savedialog-title-save
|
2014-07-14 21:32:49 +00:00
|
|
|
this.title.setLabel( ve.msg( 'visualeditor-savedialog-title-' + panel ) );
|
2013-10-07 10:01:43 +00:00
|
|
|
|
|
|
|
// Reset save button if we disabled it for e.g. unrecoverable spam error
|
2014-08-22 20:50:48 +00:00
|
|
|
this.actions.setAbilities( { save: true } );
|
2013-10-07 10:01:43 +00:00
|
|
|
|
2015-09-21 17:19:53 +00:00
|
|
|
// On panels without inputs, ensure the dialog is focused so events
|
|
|
|
// are captured, e.g. 'Esc' to close
|
|
|
|
this.$content[ 0 ].focus();
|
|
|
|
|
2013-12-06 02:34:44 +00:00
|
|
|
switch ( panel ) {
|
2013-10-07 10:01:43 +00:00
|
|
|
case 'save':
|
2014-06-06 13:18:22 +00:00
|
|
|
// HACK: FF needs *another* defer
|
2013-10-17 13:29:03 +00:00
|
|
|
setTimeout( function () {
|
2015-08-20 18:20:41 +00:00
|
|
|
dialog.editSummaryInput.moveCursorToEnd();
|
2013-10-17 13:29:03 +00:00
|
|
|
} );
|
2013-10-07 10:01:43 +00:00
|
|
|
break;
|
|
|
|
case 'conflict':
|
2016-10-27 00:56:18 +00:00
|
|
|
this.actions.setAbilities( { save: false } );
|
2013-10-07 10:01:43 +00:00
|
|
|
break;
|
2016-09-01 23:54:56 +00:00
|
|
|
case 'preview':
|
|
|
|
size = 'full';
|
|
|
|
break;
|
2013-10-07 10:01:43 +00:00
|
|
|
case 'review':
|
2015-09-21 17:19:53 +00:00
|
|
|
size = 'larger';
|
2014-02-10 18:33:13 +00:00
|
|
|
currentEditSummaryWikitext = this.editSummaryInput.getValue();
|
|
|
|
if ( this.lastEditSummaryWikitext === undefined || this.lastEditSummaryWikitext !== currentEditSummaryWikitext ) {
|
|
|
|
if ( this.editSummaryXhr ) {
|
|
|
|
this.editSummaryXhr.abort();
|
|
|
|
}
|
|
|
|
this.lastEditSummaryWikitext = currentEditSummaryWikitext;
|
2014-08-03 02:12:25 +00:00
|
|
|
this.$reviewEditSummary.empty();
|
|
|
|
|
|
|
|
if ( !currentEditSummaryWikitext || currentEditSummaryWikitext.trim() === '' ) {
|
|
|
|
// Don't bother with an API request for an empty summary
|
2015-01-29 23:09:47 +00:00
|
|
|
this.$reviewEditSummary.parent().addClass( 'oo-ui-element-hidden' );
|
2014-08-03 02:12:25 +00:00
|
|
|
} else {
|
2015-01-29 23:09:47 +00:00
|
|
|
this.$reviewEditSummary.parent()
|
|
|
|
.removeClass( 'oo-ui-element-hidden' )
|
|
|
|
.addClass( 'mw-ajax-loader' );
|
2014-08-03 02:12:25 +00:00
|
|
|
this.editSummaryXhr = new mw.Api().post( {
|
|
|
|
action: 'parse',
|
|
|
|
summary: currentEditSummaryWikitext
|
|
|
|
} ).done( function ( result ) {
|
2015-08-19 17:33:02 +00:00
|
|
|
if ( result.parse.parsedsummary[ '*' ] === '' ) {
|
2015-01-29 23:09:47 +00:00
|
|
|
dialog.$reviewEditSummary.parent().addClass( 'oo-ui-element-hidden' );
|
2014-08-03 02:12:25 +00:00
|
|
|
} else {
|
2015-08-19 17:33:02 +00:00
|
|
|
dialog.$reviewEditSummary.html( ve.msg( 'parentheses', result.parse.parsedsummary[ '*' ] ) );
|
2014-08-03 02:12:25 +00:00
|
|
|
}
|
|
|
|
} ).fail( function () {
|
2015-01-29 23:09:47 +00:00
|
|
|
dialog.$reviewEditSummary.parent().addClass( 'oo-ui-element-hidden' );
|
2014-08-03 02:12:25 +00:00
|
|
|
} ).always( function () {
|
|
|
|
dialog.$reviewEditSummary.parent().removeClass( 'mw-ajax-loader' );
|
2015-09-21 16:52:19 +00:00
|
|
|
dialog.updateSize();
|
2014-08-03 02:12:25 +00:00
|
|
|
} );
|
|
|
|
}
|
2014-02-10 18:33:13 +00:00
|
|
|
}
|
2016-10-27 00:56:18 +00:00
|
|
|
break;
|
2013-10-07 10:01:43 +00:00
|
|
|
case 'nochanges':
|
2016-10-27 00:56:18 +00:00
|
|
|
mode = 'review';
|
2013-10-07 10:01:43 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-10-27 00:56:18 +00:00
|
|
|
// Show the target panel
|
|
|
|
this.panels.setItem( panelObj );
|
|
|
|
this.setSize( size );
|
|
|
|
|
|
|
|
// Set mode after setting size so that the footer is measured correctly
|
|
|
|
this.actions.setMode( mode );
|
|
|
|
|
2016-09-01 23:54:56 +00:00
|
|
|
// Only show preview in source mode
|
|
|
|
this.actions.forEach( { actions: 'preview' }, function ( action ) {
|
2016-11-30 12:03:56 +00:00
|
|
|
action.toggle( ve.init.target.getSurface().mode === 'source' );
|
2016-09-01 23:54:56 +00:00
|
|
|
} );
|
|
|
|
|
2013-10-07 10:01:43 +00:00
|
|
|
mw.hook( 've.saveDialog.stateChanged' ).fire();
|
|
|
|
|
|
|
|
return dialog;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Show a message in the save dialog.
|
|
|
|
*
|
|
|
|
* @param {string} name Message's unique name
|
|
|
|
* @param {string|jQuery|Array} message Message content (string of HTML, jQuery object or array of
|
|
|
|
* Node objects)
|
|
|
|
* @param {Object} [options]
|
|
|
|
* @param {boolean} [options.wrap="warning"] Whether to wrap the message in a paragraph and if
|
|
|
|
* so, how. One of "warning", "error" or false.
|
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.showMessage = function ( name, message, options ) {
|
|
|
|
var $message;
|
2015-08-19 17:33:02 +00:00
|
|
|
if ( !this.messages[ name ] ) {
|
2013-10-07 10:01:43 +00:00
|
|
|
options = options || {};
|
|
|
|
if ( options.wrap === undefined ) {
|
|
|
|
options.wrap = 'warning';
|
|
|
|
}
|
2015-04-09 23:47:15 +00:00
|
|
|
$message = $( '<div class="ve-ui-mwSaveDialog-message"></div>' );
|
2013-10-07 10:01:43 +00:00
|
|
|
if ( options.wrap !== false ) {
|
2015-04-09 23:47:15 +00:00
|
|
|
$message.append( $( '<p>' ).append(
|
2014-05-15 16:12:43 +00:00
|
|
|
// visualeditor-savedialog-label-error
|
|
|
|
// visualeditor-savedialog-label-warning
|
2015-04-09 23:47:15 +00:00
|
|
|
$( '<strong>' ).text( mw.msg( 'visualeditor-savedialog-label-' + options.wrap ) ),
|
2013-10-07 10:01:43 +00:00
|
|
|
document.createTextNode( mw.msg( 'colon-separator' ) ),
|
|
|
|
message
|
|
|
|
) );
|
|
|
|
} else {
|
|
|
|
$message.append( message );
|
|
|
|
}
|
|
|
|
this.$saveMessages.append( $message );
|
|
|
|
|
2015-08-19 17:33:02 +00:00
|
|
|
this.messages[ name ] = $message;
|
2013-10-07 10:01:43 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove a message from the save dialog.
|
2015-08-19 18:21:01 +00:00
|
|
|
*
|
2013-10-07 10:01:43 +00:00
|
|
|
* @param {string} name Message's unique name
|
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.clearMessage = function ( name ) {
|
2015-08-19 17:33:02 +00:00
|
|
|
if ( this.messages[ name ] ) {
|
|
|
|
this.messages[ name ].remove();
|
|
|
|
delete this.messages[ name ];
|
2013-10-07 10:01:43 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove all messages from the save dialog.
|
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.clearAllMessages = function () {
|
|
|
|
this.$saveMessages.empty();
|
|
|
|
this.messages = {};
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reset the fields of the save dialog.
|
|
|
|
*
|
|
|
|
* @method
|
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.reset = function () {
|
|
|
|
// Reset summary input
|
2014-10-08 20:14:53 +00:00
|
|
|
this.editSummaryInput.setValue( '' );
|
2013-10-07 10:01:43 +00:00
|
|
|
// Uncheck minoredit
|
2015-08-13 16:39:24 +00:00
|
|
|
if ( this.checkboxesByName.wpMinoredit ) {
|
|
|
|
this.checkboxesByName.wpMinoredit.setSelected( false );
|
|
|
|
}
|
2016-09-01 23:54:56 +00:00
|
|
|
this.clearDiff();
|
2013-10-07 10:01:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2013-11-14 23:14:16 +00:00
|
|
|
* Initialize MediaWiki page specific checkboxes.
|
|
|
|
*
|
|
|
|
* This method is safe to call even when the dialog hasn't been initialized yet.
|
2013-10-07 10:01:43 +00:00
|
|
|
*
|
2015-08-13 16:39:24 +00:00
|
|
|
* @param {OO.ui.FieldLayout[]} checkboxFields Checkbox fields
|
2013-10-07 10:01:43 +00:00
|
|
|
*/
|
2015-08-13 16:39:24 +00:00
|
|
|
ve.ui.MWSaveDialog.prototype.setupCheckboxes = function ( checkboxFields ) {
|
2014-12-16 21:14:01 +00:00
|
|
|
var dialog = this;
|
2013-11-14 23:14:16 +00:00
|
|
|
this.setupDeferred.done( function () {
|
2015-08-13 16:39:24 +00:00
|
|
|
checkboxFields.forEach( function ( field ) {
|
|
|
|
dialog.$saveCheckboxes.append( field.$element );
|
|
|
|
} );
|
2014-12-16 21:14:01 +00:00
|
|
|
} );
|
2013-11-14 23:14:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Change the edit summary prefilled in the save dialog.
|
|
|
|
*
|
|
|
|
* This method is safe to call even when the dialog hasn't been initialized yet.
|
|
|
|
*
|
|
|
|
* @param {string} summary Edit summary to prefill
|
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.setEditSummary = function ( summary ) {
|
2014-12-16 21:14:01 +00:00
|
|
|
var dialog = this;
|
2013-11-14 23:14:16 +00:00
|
|
|
this.setupDeferred.done( function () {
|
2014-12-16 21:14:01 +00:00
|
|
|
dialog.editSummaryInput.setValue( summary );
|
|
|
|
} );
|
2013-10-07 10:01:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2013-11-05 00:29:50 +00:00
|
|
|
* @inheritdoc
|
2013-10-07 10:01:43 +00:00
|
|
|
*/
|
2013-11-05 00:29:50 +00:00
|
|
|
ve.ui.MWSaveDialog.prototype.initialize = function () {
|
2014-12-16 21:14:01 +00:00
|
|
|
var saveAccessKey,
|
|
|
|
dialog = this;
|
2014-07-14 21:32:49 +00:00
|
|
|
|
2013-11-05 00:29:50 +00:00
|
|
|
// Parent method
|
2014-05-31 04:47:08 +00:00
|
|
|
ve.ui.MWSaveDialog.super.prototype.initialize.call( this );
|
2013-10-07 10:01:43 +00:00
|
|
|
|
2013-11-05 00:29:50 +00:00
|
|
|
// Properties
|
2015-04-09 23:47:15 +00:00
|
|
|
this.panels = new OO.ui.StackLayout( { scrollable: true } );
|
2014-05-19 17:41:06 +00:00
|
|
|
this.savePanel = new OO.ui.PanelLayout( {
|
2015-09-21 16:52:19 +00:00
|
|
|
expanded: false,
|
2014-08-22 20:50:48 +00:00
|
|
|
scrollable: true,
|
2015-01-31 02:14:07 +00:00
|
|
|
padded: true,
|
2015-07-22 22:13:09 +00:00
|
|
|
classes: [ 've-ui-mwSaveDialog-savePanel' ]
|
2014-05-19 17:41:06 +00:00
|
|
|
} );
|
2013-11-05 00:29:50 +00:00
|
|
|
|
2014-10-09 20:52:51 +00:00
|
|
|
// Byte counter in edit summary
|
2015-01-05 21:05:42 +00:00
|
|
|
this.editSummaryCountLabel = new OO.ui.LabelWidget( {
|
2014-10-09 20:52:51 +00:00
|
|
|
classes: [ 've-ui-mwSaveDialog-editSummary-count' ],
|
2014-10-09 22:37:52 +00:00
|
|
|
label: String( this.editSummaryByteLimit ),
|
|
|
|
title: ve.msg( 'visualeditor-editsummary-bytes-remaining' )
|
2014-10-09 20:52:51 +00:00
|
|
|
} );
|
|
|
|
|
2013-11-05 00:29:50 +00:00
|
|
|
// Save panel
|
2015-04-09 23:47:15 +00:00
|
|
|
this.$editSummaryLabel = $( '<div>' ).addClass( 've-ui-mwSaveDialog-summaryLabel' )
|
2013-11-05 00:29:50 +00:00
|
|
|
.html( ve.init.platform.getParsedMessage( 'summary' ) )
|
|
|
|
.find( 'a' ).attr( 'target', '_blank' ).end();
|
2015-07-20 11:51:38 +00:00
|
|
|
this.editSummaryInput = new OO.ui.TextInputWidget( {
|
|
|
|
multiline: true,
|
|
|
|
placeholder: ve.msg( 'visualeditor-editsummary' ),
|
|
|
|
classes: [ 've-ui-mwSaveDialog-summary' ],
|
|
|
|
inputFilter: function ( value ) {
|
|
|
|
// Prevent the user from inputting newlines (this kicks in on paste, etc.)
|
|
|
|
return value.replace( /\r?\n/g, ' ' );
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
// Prevent the user from inputting newlines from keyboard
|
|
|
|
this.editSummaryInput.$input.on( 'keypress', function ( e ) {
|
|
|
|
if ( e.which === OO.ui.Keys.ENTER ) {
|
|
|
|
e.preventDefault();
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
// Limit byte length, and display the remaining bytes
|
|
|
|
this.editSummaryInput.$input.byteLimit( this.editSummaryByteLimit );
|
2013-11-19 07:50:55 +00:00
|
|
|
this.editSummaryInput.on( 'change', function () {
|
2016-02-21 08:35:05 +00:00
|
|
|
dialog.changedEditSummary = true;
|
2013-11-05 00:29:50 +00:00
|
|
|
// TODO: This looks a bit weird, there is no unit in the UI, just numbers
|
|
|
|
// Users likely assume characters but then it seems to count down quicker
|
|
|
|
// than expected. Facing users with the word "byte" is bad? (bug 40035)
|
2014-12-16 21:14:01 +00:00
|
|
|
dialog.editSummaryCountLabel.setLabel(
|
|
|
|
String( dialog.editSummaryByteLimit - $.byteLength( dialog.editSummaryInput.getValue() ) )
|
2013-11-19 07:50:55 +00:00
|
|
|
);
|
2014-12-16 21:14:01 +00:00
|
|
|
} );
|
2013-11-05 00:29:50 +00:00
|
|
|
|
2015-08-13 16:39:24 +00:00
|
|
|
this.$saveCheckboxes = $( '<div>' ).addClass( 've-ui-mwSaveDialog-checkboxes' );
|
2015-04-09 23:47:15 +00:00
|
|
|
this.$saveOptions = $( '<div>' ).addClass( 've-ui-mwSaveDialog-options' ).append(
|
2015-08-13 16:39:24 +00:00
|
|
|
this.$saveCheckboxes,
|
2014-10-09 20:52:51 +00:00
|
|
|
this.editSummaryCountLabel.$element
|
2013-11-05 00:29:50 +00:00
|
|
|
);
|
2015-04-09 23:47:15 +00:00
|
|
|
this.$saveMessages = $( '<div>' );
|
|
|
|
this.$saveActions = $( '<div>' );
|
|
|
|
this.$saveFoot = $( '<div>' ).addClass( 've-ui-mwSaveDialog-foot' ).append(
|
|
|
|
$( '<p>' ).addClass( 've-ui-mwSaveDialog-license' )
|
2013-11-05 00:29:50 +00:00
|
|
|
.html( ve.init.platform.getParsedMessage( 'copyrightwarning' ) )
|
|
|
|
.find( 'a' ).attr( 'target', '_blank' ).end()
|
|
|
|
);
|
|
|
|
this.savePanel.$element.append(
|
|
|
|
this.$editSummaryLabel,
|
|
|
|
this.editSummaryInput.$element,
|
|
|
|
this.$saveOptions,
|
|
|
|
this.$saveMessages,
|
|
|
|
this.$saveActions,
|
|
|
|
this.$saveFoot
|
|
|
|
);
|
|
|
|
|
|
|
|
// Review panel
|
2015-01-31 02:14:07 +00:00
|
|
|
this.reviewPanel = new OO.ui.PanelLayout( {
|
2015-09-21 16:52:19 +00:00
|
|
|
expanded: false,
|
2015-01-31 02:14:07 +00:00
|
|
|
scrollable: true,
|
|
|
|
padded: true
|
|
|
|
} );
|
2015-04-09 23:47:15 +00:00
|
|
|
this.$reviewViewer = $( '<div>' ).addClass( 've-ui-mwSaveDialog-viewer' );
|
|
|
|
this.$reviewEditSummary = $( '<span>' ).addClass( 've-ui-mwSaveDialog-summaryPreview' ).addClass( 'comment' );
|
|
|
|
this.$reviewActions = $( '<div>' ).addClass( 've-ui-mwSaveDialog-actions' );
|
2014-02-10 18:33:13 +00:00
|
|
|
this.reviewPanel.$element.append(
|
|
|
|
$( '<div>' )
|
|
|
|
.addClass( 'mw-summary-preview' )
|
|
|
|
.text( ve.msg( 'summary-preview' ) )
|
|
|
|
.append( $( '<br>' ), this.$reviewEditSummary ),
|
|
|
|
this.$reviewViewer,
|
|
|
|
this.$reviewActions
|
|
|
|
);
|
2013-11-05 00:29:50 +00:00
|
|
|
|
2016-09-01 23:54:56 +00:00
|
|
|
// Preview panel
|
|
|
|
this.previewPanel = new OO.ui.PanelLayout( {
|
|
|
|
expanded: false,
|
|
|
|
scrollable: true,
|
|
|
|
padded: true
|
|
|
|
} );
|
|
|
|
this.$previewViewer = $( '<div>' ).addClass( 'mw-body-content mw-content-' + mw.config.get( 'wgVisualEditor' ).pageLanguageDir );
|
|
|
|
this.previewPanel.$element.append( this.$previewViewer );
|
|
|
|
|
2013-11-05 00:29:50 +00:00
|
|
|
// Conflict panel
|
2015-01-31 02:14:07 +00:00
|
|
|
this.conflictPanel = new OO.ui.PanelLayout( {
|
2015-09-21 16:52:19 +00:00
|
|
|
expanded: false,
|
2015-01-31 02:14:07 +00:00
|
|
|
scrollable: true,
|
|
|
|
padded: true
|
|
|
|
} );
|
2015-04-09 23:47:15 +00:00
|
|
|
this.$conflict = $( '<div>' ).addClass( 've-ui-mwSaveDialog-conflict' )
|
2013-11-05 00:29:50 +00:00
|
|
|
.html( ve.init.platform.getParsedMessage( 'visualeditor-editconflict' ) )
|
|
|
|
.find( 'a' ).attr( 'target', '_blank' ).end();
|
|
|
|
this.conflictPanel.$element.append( this.$conflict );
|
|
|
|
|
|
|
|
// No changes panel
|
2015-01-31 02:14:07 +00:00
|
|
|
this.nochangesPanel = new OO.ui.PanelLayout( {
|
2015-09-21 16:52:19 +00:00
|
|
|
expanded: false,
|
2015-01-31 02:14:07 +00:00
|
|
|
scrollable: true,
|
|
|
|
padded: true
|
|
|
|
} );
|
2015-04-09 23:47:15 +00:00
|
|
|
this.$noChanges = $( '<div>' ).addClass( 've-ui-mwSaveDialog-nochanges' )
|
2013-11-05 00:29:50 +00:00
|
|
|
.html( ve.init.platform.getParsedMessage( 'visualeditor-diff-nochanges' ) )
|
|
|
|
.find( 'a' ).attr( 'target', '_blank' ).end();
|
|
|
|
this.nochangesPanel.$element.append( this.$noChanges );
|
|
|
|
|
|
|
|
// Panel stack
|
2014-07-14 21:32:49 +00:00
|
|
|
this.panels.addItems( [
|
|
|
|
this.savePanel,
|
|
|
|
this.reviewPanel,
|
2016-09-01 23:54:56 +00:00
|
|
|
this.previewPanel,
|
2014-07-14 21:32:49 +00:00
|
|
|
this.conflictPanel,
|
|
|
|
this.nochangesPanel
|
|
|
|
] );
|
2013-11-05 00:29:50 +00:00
|
|
|
|
|
|
|
// Save button for "save" panel
|
2014-07-14 21:32:49 +00:00
|
|
|
saveAccessKey = ve.msg( 'accesskey-save' );
|
|
|
|
if ( saveAccessKey !== '-' && saveAccessKey !== '' ) {
|
2014-08-22 20:50:48 +00:00
|
|
|
this.actions.forEach( { actions: 'save' }, function ( action ) {
|
2014-07-14 21:32:49 +00:00
|
|
|
action.setAccessKey( saveAccessKey );
|
|
|
|
} );
|
2014-01-30 19:33:30 +00:00
|
|
|
}
|
2013-11-05 00:29:50 +00:00
|
|
|
|
|
|
|
// Initialization
|
2014-07-14 21:32:49 +00:00
|
|
|
this.$body.append( this.panels.$element );
|
2013-11-14 23:14:16 +00:00
|
|
|
|
|
|
|
this.setupDeferred.resolve();
|
|
|
|
};
|
|
|
|
|
2014-06-12 00:35:46 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
2016-06-30 14:01:24 +00:00
|
|
|
* @param {Object} [data]
|
|
|
|
* @param {Function|string} [data.saveButtonLabel] Label for the save button
|
2014-06-12 00:35:46 +00:00
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.getSetupProcess = function ( data ) {
|
|
|
|
return ve.ui.MWSaveDialog.super.prototype.getSetupProcess.call( this, data )
|
2014-07-14 21:32:49 +00:00
|
|
|
.next( function () {
|
2016-02-21 08:35:05 +00:00
|
|
|
if ( !this.changedEditSummary ) {
|
2015-08-11 19:36:10 +00:00
|
|
|
this.setEditSummary( data.editSummary );
|
|
|
|
}
|
2015-08-18 20:10:37 +00:00
|
|
|
this.setupCheckboxes( data.checkboxFields || [] );
|
2015-08-13 16:39:24 +00:00
|
|
|
this.checkboxesByName = data.checkboxesByName || {};
|
2014-07-25 18:39:03 +00:00
|
|
|
// Old messages should not persist
|
2014-06-12 00:35:46 +00:00
|
|
|
this.clearAllMessages();
|
2016-11-30 17:21:38 +00:00
|
|
|
this.swapPanel( data.initialPanel || 'save' );
|
2014-07-14 21:32:49 +00:00
|
|
|
// Update save button label
|
2016-06-30 14:01:24 +00:00
|
|
|
if ( data.saveButtonLabel ) {
|
|
|
|
this.actions.forEach( { actions: 'save' }, function ( action ) {
|
|
|
|
action.setLabel( data.saveButtonLabel );
|
|
|
|
} );
|
|
|
|
}
|
2014-06-12 00:35:46 +00:00
|
|
|
}, this );
|
|
|
|
};
|
|
|
|
|
2015-01-06 00:51:38 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.getReadyProcess = function ( data ) {
|
|
|
|
return ve.ui.MWSaveDialog.super.prototype.getReadyProcess.call( this, data )
|
|
|
|
.next( function () {
|
|
|
|
this.editSummaryInput.focus();
|
|
|
|
}, this );
|
|
|
|
};
|
|
|
|
|
2015-07-31 12:15:31 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.getTeardownProcess = function ( data ) {
|
|
|
|
return ve.ui.MWSaveDialog.super.prototype.getTeardownProcess.call( this, data )
|
|
|
|
.next( function () {
|
|
|
|
this.emit( 'close' );
|
|
|
|
this.target = null;
|
|
|
|
}, this );
|
|
|
|
};
|
|
|
|
|
2014-05-28 22:05:17 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
2014-07-14 21:32:49 +00:00
|
|
|
ve.ui.MWSaveDialog.prototype.getActionProcess = function ( action ) {
|
|
|
|
if ( action === 'save' ) {
|
|
|
|
return new OO.ui.Process( function () {
|
|
|
|
var saveDeferred = $.Deferred();
|
2015-07-29 16:47:32 +00:00
|
|
|
this.swapPanel( 'save' );
|
2014-07-14 21:32:49 +00:00
|
|
|
this.emit( 'save', saveDeferred );
|
|
|
|
return saveDeferred.promise();
|
|
|
|
}, this );
|
|
|
|
}
|
2016-09-01 23:54:56 +00:00
|
|
|
if ( action === 'review' || action === 'preview' || action === 'resolve' ) {
|
2014-07-14 21:32:49 +00:00
|
|
|
return new OO.ui.Process( function () {
|
|
|
|
this.emit( action );
|
|
|
|
}, this );
|
|
|
|
}
|
|
|
|
if ( action === 'approve' ) {
|
|
|
|
return new OO.ui.Process( function () {
|
|
|
|
this.swapPanel( 'save' );
|
|
|
|
}, this );
|
|
|
|
}
|
2014-05-28 22:05:17 +00:00
|
|
|
|
2014-07-14 21:32:49 +00:00
|
|
|
return ve.ui.MWSaveDialog.super.prototype.getActionProcess.call( this, action );
|
2014-05-28 22:05:17 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
2014-07-14 21:32:49 +00:00
|
|
|
ve.ui.MWSaveDialog.prototype.getBodyHeight = function () {
|
|
|
|
// Don't vary the height when the foot is made visible or not
|
2015-09-21 16:52:19 +00:00
|
|
|
return this.panels.getCurrentItem().$element.outerHeight( true );
|
2014-05-28 22:05:17 +00:00
|
|
|
};
|
|
|
|
|
2014-10-30 00:36:02 +00:00
|
|
|
/**
|
|
|
|
* Handle retry button click events.
|
|
|
|
*
|
|
|
|
* Hides errors and then tries again.
|
|
|
|
*/
|
|
|
|
ve.ui.MWSaveDialog.prototype.onRetryButtonClick = function () {
|
|
|
|
this.emit( 'retry' );
|
|
|
|
ve.ui.MWSaveDialog.super.prototype.onRetryButtonClick.apply( this, arguments );
|
|
|
|
};
|
|
|
|
|
2013-10-07 10:01:43 +00:00
|
|
|
/* Registration */
|
|
|
|
|
2014-04-21 22:31:21 +00:00
|
|
|
ve.ui.windowFactory.register( ve.ui.MWSaveDialog );
|