2013-12-02 20:10:55 +00:00
|
|
|
/*
|
2013-06-11 19:16:04 +00:00
|
|
|
* VisualEditor user interface MWTransclusionDialog class.
|
|
|
|
*
|
2014-01-05 12:05:05 +00:00
|
|
|
* @copyright 2011-2014 VisualEditor Team and others; see AUTHORS.txt
|
2013-06-11 19:16:04 +00:00
|
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
Single-click insertion
Objectives:
* Reduce the number of clicks and mouse maneuvers required to insert
media, references or template parameters
* Make use of highlighting with mouse movement or arrow key presses,
similar to menus, to suggest action when clicked
* Improve the way media search results look and feel
Changes:
ve.ui.SelectWidget.js
* Add mouseleave handler to un-highlight when the mouse exits the widget
* Document highlight events (already being emitted)
ve.ui.SearchWidget.js
* Propagate both select and highlight events from results widget
* Make arrow keys change highlight instead of selection
* Get rid of enter event, make enter key select highlighted item instead
* Provide direct access to results widget through getResults method
ve.ui.MenuWidget.js
* Use the selected item as a starting point if nothing is currently
highlighted when adjusting the highlight position
ve.ui.Dialog.js
* Add footless option to hide the foot element and make the body extend
all the way down to the bottom
* Remove applyButton, which only some dialogs need, and should be creating
themselves, along with other buttons as needed
ve.ui.Widget.css
* Change highlight and selected colors of option widgets to match other
selection colors used elsewhere
* Leave selected and highlighted widget looking selected
ve.ui.Frame.css
* Add background color to combat any color that might have been applied to
the frame body in the imported CSS from the parent frame
ve.ui.Dialog.css
* Add rules for footless mode
ve.ui.MWReferenceResultWidget.js,
ve.ui.MWParameterResultWidget.js,
ve.ui.MWMediaResultWidget.js
* Allow highlighting
ve.ui.MWParamterSearchWidget.js
* Switch from selecting the first item when filtering to highlighting
ve-mw/ve.ui.Widget.js
* Adjust media result widget styling to better match other elements
ve.ui.MWTransclusionDialog.js,
ve.ui.MWReferenceListDialog.js,
ve.ui.MWReferenceEditDialog.js,
ve.ui.MWMetaDialog.js
ve.ui.MWMediaEditDialog.js
* Add apply button, as per it being removed from parent class
ve.ui.MWTransclusionDialog.js,
ve.ui.MWReferenceInsertDialog.js,
ve.ui.MWMediaInsertDialog.js
* Insert parameter/reference/media on select, instead of clicking an
insert button
* Use 'insert' instead of 'apply' as argument for close method
Bug: 50774
Bug: 51143
Change-Id: Ia18e79f1f8df2540f465468edb01f5ce989bf843
2013-07-15 21:07:53 +00:00
|
|
|
* Dialog for inserting and editing MediaWiki transclusions.
|
2013-06-11 19:16:04 +00:00
|
|
|
*
|
|
|
|
* @class
|
2014-04-10 19:07:40 +00:00
|
|
|
* @extends ve.ui.MWTemplateDialog
|
2013-06-11 19:16:04 +00:00
|
|
|
*
|
|
|
|
* @constructor
|
2013-09-25 10:21:09 +00:00
|
|
|
* @param {Object} [config] Configuration options
|
2013-06-11 19:16:04 +00:00
|
|
|
*/
|
2014-04-04 17:42:13 +00:00
|
|
|
ve.ui.MWTransclusionDialog = function VeUiMWTransclusionDialog( config ) {
|
2013-06-11 19:16:04 +00:00
|
|
|
// Parent constructor
|
2014-04-10 19:07:40 +00:00
|
|
|
ve.ui.MWTransclusionDialog.super.call( this, config );
|
2013-07-03 01:30:10 +00:00
|
|
|
|
2013-06-11 19:16:04 +00:00
|
|
|
// Properties
|
2014-03-04 22:56:14 +00:00
|
|
|
this.mode = null;
|
2013-06-11 19:16:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Inheritance */
|
|
|
|
|
2014-04-10 19:07:40 +00:00
|
|
|
OO.inheritClass( ve.ui.MWTransclusionDialog, ve.ui.MWTemplateDialog );
|
2013-07-03 01:30:10 +00:00
|
|
|
|
2013-06-11 19:16:04 +00:00
|
|
|
/* Static Properties */
|
|
|
|
|
2014-03-04 22:56:14 +00:00
|
|
|
ve.ui.MWTransclusionDialog.static.name = 'transclusion';
|
|
|
|
|
2014-04-30 21:34:45 +00:00
|
|
|
ve.ui.MWTransclusionDialog.static.title =
|
|
|
|
OO.ui.deferMsg( 'visualeditor-dialog-transclusion-title' );
|
|
|
|
|
2014-03-04 22:56:14 +00:00
|
|
|
/**
|
|
|
|
* Map of symbolic mode names and CSS classes.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @property {Object}
|
2014-04-24 00:22:45 +00:00
|
|
|
* @inheritable
|
2014-03-04 22:56:14 +00:00
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.static.modeCssClasses = {
|
|
|
|
'single': 've-ui-mwTransclusionDialog-single',
|
|
|
|
'multiple': 've-ui-mwTransclusionDialog-multiple'
|
|
|
|
};
|
|
|
|
|
2014-04-10 19:07:40 +00:00
|
|
|
ve.ui.MWTransclusionDialog.static.bookletLayoutConfig = ve.extendObject(
|
|
|
|
{},
|
|
|
|
ve.ui.MWTemplateDialog.static.bookletLayoutConfig,
|
2014-04-25 23:50:21 +00:00
|
|
|
{ 'outlined': true, 'editable': true }
|
2014-04-10 19:07:40 +00:00
|
|
|
);
|
|
|
|
|
2013-06-11 19:16:04 +00:00
|
|
|
/* Methods */
|
|
|
|
|
2014-04-10 19:07:40 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.prototype.onTransclusionReady = function () {
|
2014-04-24 00:22:45 +00:00
|
|
|
// Parent method
|
2014-04-10 19:07:40 +00:00
|
|
|
ve.ui.MWTransclusionDialog.super.prototype.onTransclusionReady.call( this );
|
2014-04-24 00:22:45 +00:00
|
|
|
|
2014-04-10 19:07:40 +00:00
|
|
|
this.setMode( 'auto' );
|
|
|
|
};
|
|
|
|
|
2014-03-04 22:56:14 +00:00
|
|
|
/**
|
|
|
|
* Handle outline controls move events.
|
|
|
|
*
|
|
|
|
* @param {number} places Number of places to move the selected item
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.prototype.onOutlineControlsMove = function ( places ) {
|
|
|
|
var part, promise,
|
2014-04-24 00:22:45 +00:00
|
|
|
parts = this.transclusionModel.getParts(),
|
2014-03-04 22:56:14 +00:00
|
|
|
item = this.bookletLayout.getOutline().getSelectedItem();
|
|
|
|
|
|
|
|
if ( item ) {
|
2014-04-24 00:22:45 +00:00
|
|
|
part = this.transclusionModel.getPartFromId( item.getData() );
|
2014-03-04 22:56:14 +00:00
|
|
|
// Move part to new location, and if dialog is loaded switch to new part page
|
2014-04-24 00:22:45 +00:00
|
|
|
promise = this.transclusionModel.addPart( part, ve.indexOf( part, parts ) + places );
|
2014-03-04 22:56:14 +00:00
|
|
|
if ( this.loaded && !this.preventReselection ) {
|
|
|
|
promise.done( ve.bind( this.setPageByName, this, part.getId() ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle outline controls remove events.
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.prototype.onOutlineControlsRemove = function () {
|
|
|
|
var id, part, param,
|
|
|
|
item = this.bookletLayout.getOutline().getSelectedItem();
|
|
|
|
|
|
|
|
if ( item ) {
|
|
|
|
id = item.getData();
|
2014-04-24 00:22:45 +00:00
|
|
|
part = this.transclusionModel.getPartFromId( id );
|
2014-03-04 22:56:14 +00:00
|
|
|
// Check if the part is the actual template, or one of its parameters
|
|
|
|
if ( part instanceof ve.dm.MWTemplateModel && id !== part.getId() ) {
|
|
|
|
param = part.getParameterFromId( id );
|
|
|
|
if ( param instanceof ve.dm.MWParameterModel ) {
|
|
|
|
part.removeParameter( param );
|
|
|
|
}
|
|
|
|
} else if ( part instanceof ve.dm.MWTransclusionPartModel ) {
|
2014-04-24 00:22:45 +00:00
|
|
|
this.transclusionModel.removePart( part );
|
2014-03-04 22:56:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle add template button click events.
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.prototype.onAddTemplateButtonClick = function () {
|
2014-04-24 00:22:45 +00:00
|
|
|
this.addPart( new ve.dm.MWTemplatePlaceholderModel( this.transclusionModel ) );
|
2014-03-04 22:56:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle add content button click events.
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.prototype.onAddContentButtonClick = function () {
|
2014-04-24 00:22:45 +00:00
|
|
|
this.addPart( new ve.dm.MWTransclusionContentModel( this.transclusionModel, '' ) );
|
2014-03-04 22:56:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle add parameter button click events.
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.prototype.onAddParameterButtonClick = function () {
|
|
|
|
var part, param,
|
|
|
|
item = this.bookletLayout.getOutline().getSelectedItem();
|
|
|
|
|
|
|
|
if ( item ) {
|
2014-04-24 00:22:45 +00:00
|
|
|
part = this.transclusionModel.getPartFromId( item.getData() );
|
2014-03-04 22:56:14 +00:00
|
|
|
if ( part instanceof ve.dm.MWTemplateModel ) {
|
|
|
|
param = new ve.dm.MWParameterModel( part, '', null );
|
|
|
|
part.addParameter( param );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle mode button click events.
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.prototype.onModeButtonClick = function () {
|
|
|
|
this.setMode( this.mode === 'single' ? 'multiple' : 'single' );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle booklet layout page set events.
|
|
|
|
*
|
|
|
|
* @param {OO.ui.PageLayout} page Active page
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.prototype.onBookletLayoutSet = function ( page ) {
|
|
|
|
this.addParameterButton.setDisabled(
|
|
|
|
!( page instanceof ve.ui.MWTemplatePage || page instanceof ve.ui.MWParameterPage )
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2013-06-11 19:16:04 +00:00
|
|
|
/**
|
2014-04-10 19:07:40 +00:00
|
|
|
* @inheritdoc
|
2013-06-11 19:16:04 +00:00
|
|
|
*/
|
2013-12-02 20:10:55 +00:00
|
|
|
ve.ui.MWTransclusionDialog.prototype.onReplacePart = function ( removed, added ) {
|
2014-04-10 19:07:40 +00:00
|
|
|
ve.ui.MWTransclusionDialog.super.prototype.onReplacePart.call( this, removed, added );
|
2014-03-24 23:54:05 +00:00
|
|
|
this.modeButton.setDisabled( !this.isSingleTemplateTransclusion() );
|
2013-06-11 19:16:04 +00:00
|
|
|
};
|
|
|
|
|
2013-06-18 21:24:16 +00:00
|
|
|
/**
|
2014-03-04 22:56:14 +00:00
|
|
|
* Checks if transclusion only contains a single template or template placeholder.
|
2013-06-18 21:24:16 +00:00
|
|
|
*
|
2014-03-06 23:39:40 +00:00
|
|
|
* @returns {boolean} Transclusion only contains a single template or template placeholder
|
2013-06-18 21:24:16 +00:00
|
|
|
*/
|
2014-03-06 23:39:40 +00:00
|
|
|
ve.ui.MWTransclusionDialog.prototype.isSingleTemplateTransclusion = function () {
|
2014-04-24 00:22:45 +00:00
|
|
|
var parts = this.transclusionModel && this.transclusionModel.getParts();
|
2014-03-04 22:56:14 +00:00
|
|
|
|
|
|
|
return parts && parts.length === 1 && (
|
|
|
|
parts[0] instanceof ve.dm.MWTemplateModel ||
|
|
|
|
parts[0] instanceof ve.dm.MWTemplatePlaceholderModel
|
2014-02-26 00:22:26 +00:00
|
|
|
);
|
2013-06-18 21:24:16 +00:00
|
|
|
};
|
|
|
|
|
2014-03-06 23:39:40 +00:00
|
|
|
/**
|
2014-04-10 19:07:40 +00:00
|
|
|
* @inheritdoc
|
2014-03-04 22:56:14 +00:00
|
|
|
*/
|
2014-04-10 19:07:40 +00:00
|
|
|
ve.ui.MWTransclusionDialog.prototype.getPageFromPart = function ( part ) {
|
|
|
|
var page = ve.ui.MWTransclusionDialog.super.prototype.getPageFromPart.call( this, part );
|
|
|
|
if ( !page && part instanceof ve.dm.MWTransclusionContentModel ) {
|
|
|
|
return new ve.ui.MWTransclusionContentPage( part, part.getId(), { '$': this.$ } );
|
|
|
|
}
|
|
|
|
return page;
|
2014-03-04 22:56:14 +00:00
|
|
|
};
|
|
|
|
|
2014-03-24 23:54:05 +00:00
|
|
|
/**
|
|
|
|
* Get a label for the apply button.
|
|
|
|
*
|
|
|
|
* @returns {string} Apply button label
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.prototype.getApplyButtonLabel = function () {
|
2014-04-24 00:22:45 +00:00
|
|
|
return !this.selectedNode && !this.isSingleTemplateTransclusion() ?
|
2014-04-10 19:07:40 +00:00
|
|
|
ve.msg( 'visualeditor-dialog-transclusion-insert-transclusion' ) :
|
|
|
|
ve.ui.MWTransclusionDialog.super.prototype.getApplyButtonLabel.call( this );
|
2013-11-05 00:29:50 +00:00
|
|
|
};
|
|
|
|
|
2014-03-04 22:56:14 +00:00
|
|
|
/**
|
|
|
|
* Set dialog mode.
|
|
|
|
*
|
|
|
|
* Auto mode will choose single if possible.
|
|
|
|
*
|
|
|
|
* @param {string} [mode='multiple'] Symbolic name of dialog mode, `multiple`, `single` or 'auto'
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.prototype.setMode = function ( mode ) {
|
|
|
|
var name, parts, part, single,
|
|
|
|
modeCssClasses = ve.ui.MWTransclusionDialog.static.modeCssClasses;
|
|
|
|
|
2014-04-24 00:22:45 +00:00
|
|
|
if ( this.transclusionModel ) {
|
|
|
|
parts = this.transclusionModel.getParts();
|
2014-03-04 22:56:14 +00:00
|
|
|
part = parts.length && parts[0];
|
|
|
|
if ( mode === 'auto' ) {
|
2014-03-06 23:39:40 +00:00
|
|
|
mode = this.isSingleTemplateTransclusion() ? 'single' : 'multiple';
|
2014-03-04 22:56:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !modeCssClasses[mode] ) {
|
|
|
|
mode = 'multiple';
|
|
|
|
}
|
|
|
|
this.mode = mode;
|
|
|
|
single = mode === 'single';
|
|
|
|
if ( this.frame.$content ) {
|
|
|
|
for ( name in modeCssClasses ) {
|
|
|
|
this.frame.$content.toggleClass( modeCssClasses[name], name === mode );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.setSize( single ? 'medium' : 'large' );
|
|
|
|
this.bookletLayout.toggleOutline( !single );
|
2014-04-25 23:50:21 +00:00
|
|
|
this.modeButton
|
|
|
|
.setLabel( ve.msg(
|
|
|
|
single ?
|
|
|
|
'visualeditor-dialog-transclusion-multiple-mode' :
|
|
|
|
'visualeditor-dialog-transclusion-single-mode'
|
|
|
|
) )
|
|
|
|
.setDisabled( !this.isSingleTemplateTransclusion() );
|
2014-03-06 23:39:40 +00:00
|
|
|
this.updateTitle();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the dialog title.
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.prototype.updateTitle = function () {
|
2014-04-30 21:34:45 +00:00
|
|
|
if ( this.mode === 'multiple' ) {
|
|
|
|
this.setTitle( this.constructor.static.title );
|
|
|
|
} else {
|
|
|
|
// Parent method
|
|
|
|
ve.ui.MWTransclusionDialog.super.prototype.updateTitle.call( this );
|
|
|
|
}
|
2014-03-04 22:56:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a part to the transclusion.
|
|
|
|
*
|
|
|
|
* @param {ve.dm.MWTransclusionPartModel} part Part to add
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.prototype.addPart = function ( part ) {
|
|
|
|
var index, promise,
|
2014-04-24 00:22:45 +00:00
|
|
|
parts = this.transclusionModel.getParts(),
|
2014-03-04 22:56:14 +00:00
|
|
|
item = this.bookletLayout.getOutline().getSelectedItem();
|
|
|
|
|
|
|
|
if ( part ) {
|
|
|
|
// Insert after selected part, or at the end if nothing is selected
|
|
|
|
index = item ?
|
2014-04-24 00:22:45 +00:00
|
|
|
ve.indexOf( this.transclusionModel.getPartFromId( item.getData() ), parts ) + 1 :
|
2014-03-04 22:56:14 +00:00
|
|
|
parts.length;
|
|
|
|
// Add the part, and if dialog is loaded switch to part page
|
2014-04-24 00:22:45 +00:00
|
|
|
promise = this.transclusionModel.addPart( part, index );
|
2014-03-04 22:56:14 +00:00
|
|
|
if ( this.loaded && !this.preventReselection ) {
|
|
|
|
promise.done( ve.bind( this.setPageByName, this, part.getId() ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-11-05 00:29:50 +00:00
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.prototype.initialize = function () {
|
|
|
|
// Parent method
|
2014-04-10 19:07:40 +00:00
|
|
|
ve.ui.MWTransclusionDialog.super.prototype.initialize.call( this );
|
2013-11-05 00:29:50 +00:00
|
|
|
|
|
|
|
// Properties
|
2014-03-04 22:56:14 +00:00
|
|
|
this.modeButton = new OO.ui.ButtonWidget( { '$': this.$ } );
|
|
|
|
this.addTemplateButton = new OO.ui.ButtonWidget( {
|
|
|
|
'$': this.$,
|
|
|
|
'frameless': true,
|
|
|
|
'icon': 'template',
|
|
|
|
'title': ve.msg( 'visualeditor-dialog-transclusion-add-template' )
|
|
|
|
} );
|
|
|
|
this.addContentButton = new OO.ui.ButtonWidget( {
|
|
|
|
'$': this.$,
|
|
|
|
'frameless': true,
|
|
|
|
'icon': 'source',
|
|
|
|
'title': ve.msg( 'visualeditor-dialog-transclusion-add-content' )
|
|
|
|
} );
|
|
|
|
this.addParameterButton = new OO.ui.ButtonWidget( {
|
|
|
|
'$': this.$,
|
|
|
|
'frameless': true,
|
|
|
|
'icon': 'parameter',
|
|
|
|
'title': ve.msg( 'visualeditor-dialog-transclusion-add-param' )
|
|
|
|
} );
|
2013-11-05 00:29:50 +00:00
|
|
|
|
|
|
|
// Events
|
2014-03-04 22:56:14 +00:00
|
|
|
this.modeButton.connect( this, { 'click': 'onModeButtonClick' } );
|
|
|
|
this.bookletLayout.connect( this, { 'set': 'onBookletLayoutSet' } );
|
|
|
|
this.addTemplateButton.connect( this, { 'click': 'onAddTemplateButtonClick' } );
|
|
|
|
this.addContentButton.connect( this, { 'click': 'onAddContentButtonClick' } );
|
|
|
|
this.addParameterButton.connect( this, { 'click': 'onAddParameterButtonClick' } );
|
|
|
|
this.bookletLayout.getOutlineControls()
|
|
|
|
.addItems( [ this.addTemplateButton, this.addContentButton, this.addParameterButton ] )
|
|
|
|
.connect( this, {
|
|
|
|
'move': 'onOutlineControlsMove',
|
|
|
|
'remove': 'onOutlineControlsRemove'
|
|
|
|
} );
|
2013-11-05 00:29:50 +00:00
|
|
|
|
|
|
|
// Initialization
|
2014-04-10 19:07:40 +00:00
|
|
|
this.$foot.append( this.modeButton.$element );
|
2014-04-17 22:03:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionDialog.prototype.setup = function ( data ) {
|
2014-03-04 22:56:14 +00:00
|
|
|
this.setMode( 'single' );
|
2014-04-17 22:03:43 +00:00
|
|
|
this.modeButton.setDisabled( true );
|
|
|
|
|
|
|
|
// Parent method
|
|
|
|
ve.ui.MWTransclusionDialog.super.prototype.setup.call( this, data );
|
2013-11-05 00:29:50 +00:00
|
|
|
};
|
|
|
|
|
2014-03-04 22:56:14 +00:00
|
|
|
/* Registration */
|
|
|
|
|
2014-04-21 22:31:21 +00:00
|
|
|
ve.ui.windowFactory.register( ve.ui.MWTransclusionDialog );
|