/*!
* VisualEditor user interface FragmentWindow class.
*
* @copyright See AUTHORS.txt
*/
/**
* Mixin for window for working with fragments of content.
*
* @class
* @abstract
*
* @constructor
* @param {Object} [config] Configuration options
*/
ve.ui.FragmentWindow = function VeUiFragmentWindow() {
// Properties
this.fragment = null;
};
/* Inheritance */
OO.initClass( ve.ui.FragmentWindow );
/* Methods */
/**
* Get the surface fragment the window is for.
*
* @return {ve.dm.SurfaceFragment|null} Surface fragment the window is for, null if the
* window is closed
*/
ve.ui.FragmentWindow.prototype.getFragment = function () {
return this.fragment;
};
// eslint-disable-next-line jsdoc/require-param, jsdoc/require-returns
/**
* @see OO.ui.Dialog
*/
ve.ui.FragmentWindow.prototype.getActionWidgetConfig = function ( config ) {
if ( config.action === 'done' && OO.ui.isMobile() ) {
// Use label-less check icon on mobile (T228230)
config = ve.extendObject( {
icon: 'check',
invisibleLabel: true
}, config );
}
return config;
};
// eslint-disable-next-line jsdoc/require-param, jsdoc/require-returns
/**
* @see OO.ui.Window
* @throws {Error} If fragment was not provided through data parameter
*/
ve.ui.FragmentWindow.prototype.getSetupProcess = function ( data, process ) {
data = data || {};
return process.first( () => {
if ( !( data.fragment instanceof ve.dm.SurfaceFragment ) ) {
throw new Error( 'Cannot open dialog: opening data must contain a fragment' );
}
this.fragment = data.fragment;
this.initialFragment = data.fragment;
this.selectFragmentOnClose = data.selectFragmentOnClose !== false;
// Prefer this.initialFragment.getSelection() to this.previousSelection
this.previousSelection = this.fragment.getSelection();
} ).next( () => {
// Don't allow windows to be opened for insertion in readonly mode
if ( !this.isEditing() && this.isReadOnly() ) {
return ve.createDeferred().reject().promise();
}
this.actions.setMode( this.getMode() );
} );
};
// eslint-disable-next-line jsdoc/require-param, jsdoc/require-returns
/**
* @see OO.ui.Window
*/
ve.ui.FragmentWindow.prototype.getTeardownProcess = function ( data, process ) {
ve.track( 'activity.' + this.constructor.static.name, { action: 'dialog-' + ( data && data.action || 'abort' ) } );
return process.next( () => {
this.fragment = null;
this.initialFragment = null;
this.previousSelection = null;
} );
};
/**
* Check if the fragment's surface is readOnly
*
* @return {boolean} Fragment's surface is readOnly
*/
ve.ui.FragmentWindow.prototype.isReadOnly = function () {
const fragment = this.getFragment(),
surface = fragment && fragment.getSurface();
return surface && surface.isReadOnly();
};
/**
* Get a symbolic mode name.
*
* By default will return 'edit' if #isEditing is true, and 'insert' otherwise.
*
* If the surface model is in read-only mode, will return 'readonly'.
*
* @return {string} Symbolic mode name
*/
ve.ui.FragmentWindow.prototype.getMode = function () {
if ( this.isReadOnly() ) {
return 'readonly';
}
if ( this.getFragment() ) {
return this.isEditing() ? 'edit' : 'insert';
}
return '';
};
/**
* Check if the current fragment is editable by this window.
*
* @localdoc Returns true if the fragment being edited selects at least one model,
*
* @return {boolean} Fragment is editable by this window
*/
ve.ui.FragmentWindow.prototype.isEditing = function () {
return !!this.fragment.getSelectedModels().length;
};