2021-05-17 15:43:49 +00:00
|
|
|
/*!
|
|
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Container for template, as rendered in the template dialog sidebar.
|
|
|
|
*
|
|
|
|
* @class
|
2021-07-09 15:04:14 +00:00
|
|
|
* @extends ve.ui.MWTransclusionOutlinePartWidget
|
2021-05-17 15:43:49 +00:00
|
|
|
*
|
|
|
|
* @constructor
|
2021-07-09 15:33:16 +00:00
|
|
|
* @param {ve.dm.MWTemplateModel} template
|
2021-05-17 15:43:49 +00:00
|
|
|
*/
|
2021-07-13 09:00:57 +00:00
|
|
|
ve.ui.MWTransclusionOutlineTemplateWidget = function VeUiMWTransclusionOutlineTemplateWidget( template ) {
|
2021-08-04 14:34:54 +00:00
|
|
|
var spec = template.getSpec();
|
|
|
|
|
2021-07-13 09:00:57 +00:00
|
|
|
// Parent constructor
|
|
|
|
ve.ui.MWTransclusionOutlineTemplateWidget.super.call( this, template, {
|
2021-07-09 14:47:01 +00:00
|
|
|
icon: 'puzzle',
|
2021-10-27 09:39:03 +00:00
|
|
|
label: spec.getLabel(),
|
|
|
|
ariaDescriptionSelected: ve.msg( 'visualeditor-dialog-transclusion-template-widget-aria-selected' ),
|
|
|
|
ariaDescriptionUnselected: ve.msg( 'visualeditor-dialog-transclusion-template-widget-aria' )
|
2021-07-13 09:00:57 +00:00
|
|
|
} );
|
2021-05-17 15:43:49 +00:00
|
|
|
|
|
|
|
// Initialization
|
2021-07-09 15:33:16 +00:00
|
|
|
this.templateModel = template.connect( this, {
|
2021-08-26 14:29:42 +00:00
|
|
|
add: 'onParameterAddedToTemplateModel',
|
|
|
|
remove: 'onParameterRemovedFromTemplateModel'
|
2021-06-17 11:20:50 +00:00
|
|
|
} );
|
2021-05-17 15:43:49 +00:00
|
|
|
|
2021-08-26 14:29:42 +00:00
|
|
|
var parameterNames = this.templateModel
|
2021-06-29 19:15:08 +00:00
|
|
|
.getAllParametersOrdered()
|
|
|
|
.filter( function ( paramName ) {
|
2021-08-04 14:34:54 +00:00
|
|
|
if ( spec.isParameterDeprecated( paramName ) && !template.hasParameter( paramName ) ) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-06-29 19:15:08 +00:00
|
|
|
// Don't create a checkbox for ve.ui.MWParameterPlaceholderPage
|
2021-07-13 19:01:30 +00:00
|
|
|
return paramName;
|
2021-06-29 19:15:08 +00:00
|
|
|
} );
|
2021-06-21 14:19:03 +00:00
|
|
|
|
2021-07-20 10:36:23 +00:00
|
|
|
this.searchWidget = new OO.ui.SearchInputWidget( {
|
2021-10-21 10:30:02 +00:00
|
|
|
title: ve.msg( 'visualeditor-dialog-transclusion-filter-title', spec.getLabel() ),
|
2021-07-20 10:36:23 +00:00
|
|
|
placeholder: ve.msg( 'visualeditor-dialog-transclusion-filter-placeholder' ),
|
|
|
|
classes: [ 've-ui-mwTransclusionOutlineTemplateWidget-searchWidget' ]
|
|
|
|
} ).connect( this, {
|
2021-08-06 13:05:54 +00:00
|
|
|
change: 'filterParameters'
|
2021-08-26 14:29:42 +00:00
|
|
|
} ).toggle( parameterNames.length );
|
2021-10-21 10:30:02 +00:00
|
|
|
this.searchWidget.$element.attr( 'role', 'search' );
|
|
|
|
|
2021-07-20 10:36:23 +00:00
|
|
|
this.infoWidget = new OO.ui.LabelWidget( {
|
2021-10-18 20:37:25 +00:00
|
|
|
label: ve.msg( 'visualeditor-dialog-transclusion-filter-no-match' ),
|
2021-07-20 10:36:23 +00:00
|
|
|
classes: [ 've-ui-mwTransclusionOutlineTemplateWidget-no-match' ]
|
|
|
|
} ).toggle( false );
|
2021-07-12 15:00:04 +00:00
|
|
|
|
2021-10-31 10:08:13 +00:00
|
|
|
var $parametersAriaDescription = $( '<span>' )
|
|
|
|
.text( ve.msg( 'visualeditor-dialog-transclusion-param-selection-aria-description' ) )
|
|
|
|
.addClass( 've-ui-mwTransclusionOutline-ariaHidden' );
|
|
|
|
|
2021-08-16 16:17:14 +00:00
|
|
|
this.parameters = new ve.ui.MWTransclusionOutlineParameterSelectWidget( {
|
2021-10-31 10:08:13 +00:00
|
|
|
items: parameterNames.map( this.createCheckbox.bind( this ) ),
|
|
|
|
ariaLabel: ve.msg( 'visualeditor-dialog-transclusion-param-selection-aria-label', spec.getLabel() ),
|
2021-11-01 15:47:31 +00:00
|
|
|
$ariaDescribedBy: $parametersAriaDescription
|
2021-08-16 16:17:14 +00:00
|
|
|
} )
|
|
|
|
.connect( this, {
|
2021-08-31 08:05:25 +00:00
|
|
|
choose: 'onTemplateParameterChoose',
|
2021-09-07 15:53:37 +00:00
|
|
|
templateParameterSelectionChanged: 'onTemplateParameterSelectionChanged',
|
2021-08-26 14:29:42 +00:00
|
|
|
change: 'onParameterWidgetListChanged'
|
2021-08-16 16:17:14 +00:00
|
|
|
} );
|
2021-07-20 10:36:23 +00:00
|
|
|
|
|
|
|
this.$element.append(
|
|
|
|
this.searchWidget.$element,
|
|
|
|
this.infoWidget.$element,
|
2021-10-31 10:08:13 +00:00
|
|
|
$parametersAriaDescription,
|
2021-08-18 07:22:43 +00:00
|
|
|
this.parameters.$element
|
2021-07-20 10:36:23 +00:00
|
|
|
);
|
2021-05-17 15:43:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Inheritance */
|
|
|
|
|
2021-07-09 15:04:14 +00:00
|
|
|
OO.inheritClass( ve.ui.MWTransclusionOutlineTemplateWidget, ve.ui.MWTransclusionOutlinePartWidget );
|
2021-06-17 11:20:50 +00:00
|
|
|
|
2021-08-05 12:36:10 +00:00
|
|
|
/* Events */
|
|
|
|
|
2021-08-13 14:41:48 +00:00
|
|
|
/**
|
2021-08-31 08:05:25 +00:00
|
|
|
* @event focusTemplateParameterById
|
|
|
|
* @param {string} pageName Unique id of the {@see OO.ui.BookletLayout} page, e.g. something like
|
|
|
|
* "part_1" or "part_1/param1".
|
2021-08-13 14:41:48 +00:00
|
|
|
*/
|
|
|
|
|
2021-08-05 12:36:10 +00:00
|
|
|
/**
|
|
|
|
* Triggered when the user uses the search widget at the top to filter the list of parameters.
|
|
|
|
*
|
2021-08-31 08:05:25 +00:00
|
|
|
* @event filterParametersById
|
2021-08-11 06:06:22 +00:00
|
|
|
* @param {Object.<string,boolean>} visibility Keyed by unique id of the parameter, e.g. something
|
2021-08-31 08:05:25 +00:00
|
|
|
* like "part_1/param1". Note this lists only parameters that are currently shown as a checkbox.
|
|
|
|
* The spec might contain more parameters (e.g. deprecated).
|
2021-08-05 12:36:10 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Methods */
|
|
|
|
|
2021-06-29 19:45:09 +00:00
|
|
|
/**
|
2021-08-13 14:41:48 +00:00
|
|
|
* @private
|
2021-09-03 14:26:43 +00:00
|
|
|
* @param {string} paramName Parameter name or alias as used in the model
|
2021-08-26 14:29:42 +00:00
|
|
|
* @return {OO.ui.OptionWidget}
|
2021-06-29 19:45:09 +00:00
|
|
|
*/
|
2021-07-13 19:01:30 +00:00
|
|
|
ve.ui.MWTransclusionOutlineTemplateWidget.prototype.createCheckbox = function ( paramName ) {
|
|
|
|
var spec = this.templateModel.getSpec();
|
2021-08-26 14:29:42 +00:00
|
|
|
return ve.ui.MWTransclusionOutlineParameterSelectWidget.static.createItem( {
|
2021-07-13 19:01:30 +00:00
|
|
|
required: spec.isParameterRequired( paramName ),
|
|
|
|
label: spec.getParameterLabel( paramName ),
|
|
|
|
data: paramName,
|
|
|
|
selected: this.templateModel.hasParameter( paramName )
|
2021-06-17 11:20:50 +00:00
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
2021-08-06 13:05:54 +00:00
|
|
|
/**
|
2021-08-13 14:41:48 +00:00
|
|
|
* @private
|
2021-08-26 14:29:42 +00:00
|
|
|
* @param {string} paramName
|
|
|
|
* @return {number}
|
2021-08-06 13:05:54 +00:00
|
|
|
*/
|
2021-08-26 14:29:42 +00:00
|
|
|
ve.ui.MWTransclusionOutlineTemplateWidget.prototype.findCanonicalPosition = function ( paramName ) {
|
|
|
|
var insertAt = 0,
|
2021-08-06 13:05:54 +00:00
|
|
|
// Note this might include parameters that don't have a checkbox, e.g. deprecated
|
|
|
|
allParamNames = this.templateModel.getAllParametersOrdered();
|
|
|
|
for ( var i = 0; i < allParamNames.length; i++ ) {
|
|
|
|
if ( allParamNames[ i ] === paramName || !this.parameters.items[ insertAt ] ) {
|
|
|
|
break;
|
|
|
|
} else if ( this.parameters.items[ insertAt ].getData() === allParamNames[ i ] ) {
|
|
|
|
insertAt++;
|
|
|
|
}
|
|
|
|
}
|
2021-08-26 14:29:42 +00:00
|
|
|
return insertAt;
|
2021-08-06 13:05:54 +00:00
|
|
|
};
|
|
|
|
|
2021-09-01 09:15:37 +00:00
|
|
|
/**
|
2021-09-23 11:26:25 +00:00
|
|
|
* @param {string} [paramName] Parameter name to highlight, e.g. "param1". Omit for no highlight.
|
2021-09-01 09:15:37 +00:00
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionOutlineTemplateWidget.prototype.highlightParameter = function ( paramName ) {
|
|
|
|
this.parameters.highlightParameter( paramName );
|
|
|
|
};
|
|
|
|
|
2021-09-23 11:26:25 +00:00
|
|
|
/**
|
|
|
|
* @inheritDoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionOutlineTemplateWidget.prototype.setSelected = function ( state ) {
|
|
|
|
if ( !state && this.isSelected() ) {
|
|
|
|
this.parameters.highlightItem();
|
|
|
|
}
|
|
|
|
ve.ui.MWTransclusionOutlineTemplateWidget.super.prototype.setSelected.call( this, state );
|
2021-09-09 12:11:36 +00:00
|
|
|
};
|
|
|
|
|
2021-06-29 19:45:09 +00:00
|
|
|
/**
|
2021-08-13 14:41:48 +00:00
|
|
|
* @private
|
2021-07-13 19:01:30 +00:00
|
|
|
* @param {ve.dm.MWParameterModel} param
|
2021-06-29 19:45:09 +00:00
|
|
|
*/
|
2021-08-26 14:29:42 +00:00
|
|
|
ve.ui.MWTransclusionOutlineTemplateWidget.prototype.onParameterAddedToTemplateModel = function ( param ) {
|
2021-08-05 10:11:40 +00:00
|
|
|
var paramName = param.getName();
|
|
|
|
// The placeholder (currently) doesn't get a corresponding item in the sidebar
|
|
|
|
if ( !paramName ) {
|
|
|
|
return;
|
|
|
|
}
|
2021-07-13 19:01:30 +00:00
|
|
|
|
|
|
|
// All parameters known via the spec already have a checkbox
|
2021-08-26 14:29:42 +00:00
|
|
|
var item = this.parameters.findItemFromData( paramName );
|
|
|
|
if ( !item ) {
|
|
|
|
item = this.createCheckbox( paramName );
|
|
|
|
this.parameters.addItems( [ item ], this.findCanonicalPosition( paramName ) );
|
|
|
|
|
2021-08-05 10:11:40 +00:00
|
|
|
// Make sure an active filter is applied to the new checkbox as well
|
|
|
|
var filter = this.searchWidget.getValue();
|
|
|
|
if ( filter ) {
|
2021-08-06 13:05:54 +00:00
|
|
|
this.filterParameters( filter );
|
2021-08-05 10:11:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-26 14:29:42 +00:00
|
|
|
item.setSelected( true, true );
|
2021-08-05 10:11:40 +00:00
|
|
|
|
|
|
|
// Reset filter, but only if it hides the relevant checkbox
|
2021-08-26 14:29:42 +00:00
|
|
|
if ( !item.isVisible() ) {
|
2021-07-20 10:36:23 +00:00
|
|
|
this.searchWidget.setValue( '' );
|
2021-06-18 15:23:35 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-06-29 19:45:09 +00:00
|
|
|
/**
|
2021-08-13 14:41:48 +00:00
|
|
|
* @private
|
2021-07-13 19:01:30 +00:00
|
|
|
* @param {ve.dm.MWParameterModel} param
|
2021-06-29 19:45:09 +00:00
|
|
|
*/
|
2021-08-26 14:29:42 +00:00
|
|
|
ve.ui.MWTransclusionOutlineTemplateWidget.prototype.onParameterRemovedFromTemplateModel = function ( param ) {
|
|
|
|
this.parameters.markParameterAsUnused( param.getName() );
|
2021-06-18 15:23:35 +00:00
|
|
|
};
|
|
|
|
|
2021-06-29 19:45:09 +00:00
|
|
|
/**
|
2021-08-13 14:41:48 +00:00
|
|
|
* @private
|
2021-08-26 14:29:42 +00:00
|
|
|
* @param {OO.ui.OptionWidget} item
|
2021-08-17 06:35:13 +00:00
|
|
|
* @param {boolean} selected
|
2021-09-07 15:53:37 +00:00
|
|
|
* @fires focusTemplateParameterById
|
2021-06-29 19:45:09 +00:00
|
|
|
*/
|
2021-08-31 08:05:25 +00:00
|
|
|
ve.ui.MWTransclusionOutlineTemplateWidget.prototype.onTemplateParameterChoose = function ( item, selected ) {
|
2021-09-07 15:53:37 +00:00
|
|
|
this.onTemplateParameterSelectionChanged( item, selected );
|
|
|
|
|
|
|
|
var param = this.templateModel.getParameter( item.getData() );
|
2021-10-20 14:39:43 +00:00
|
|
|
if ( param && selected ) {
|
2021-09-07 15:53:37 +00:00
|
|
|
this.emit( 'focusTemplateParameterById', param.getId() );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* @param {OO.ui.OptionWidget} item
|
|
|
|
* @param {boolean} selected
|
|
|
|
*/
|
|
|
|
ve.ui.MWTransclusionOutlineTemplateWidget.prototype.onTemplateParameterSelectionChanged = function ( item, selected ) {
|
2021-08-26 14:29:42 +00:00
|
|
|
var paramName = item.getData(),
|
2021-08-16 16:17:14 +00:00
|
|
|
param = this.templateModel.getParameter( paramName );
|
2021-08-17 06:35:13 +00:00
|
|
|
if ( !selected ) {
|
2021-07-13 19:01:30 +00:00
|
|
|
this.templateModel.removeParameter( param );
|
|
|
|
} else if ( !param ) {
|
2021-09-10 14:20:51 +00:00
|
|
|
param = new ve.dm.MWParameterModel( this.templateModel, paramName );
|
|
|
|
this.templateModel.addParameter( param );
|
2021-07-13 19:01:30 +00:00
|
|
|
}
|
|
|
|
};
|
2021-06-18 15:23:35 +00:00
|
|
|
|
2021-07-20 10:36:23 +00:00
|
|
|
/**
|
2021-08-13 14:41:48 +00:00
|
|
|
* @private
|
2021-07-20 10:36:23 +00:00
|
|
|
* @param {OO.ui.Element[]} items
|
|
|
|
*/
|
2021-08-26 14:29:42 +00:00
|
|
|
ve.ui.MWTransclusionOutlineTemplateWidget.prototype.onParameterWidgetListChanged = function ( items ) {
|
2021-07-20 10:36:23 +00:00
|
|
|
this.searchWidget.toggle( items.length >= 1 );
|
|
|
|
};
|
|
|
|
|
2021-07-12 15:00:04 +00:00
|
|
|
/**
|
2021-07-14 07:31:42 +00:00
|
|
|
* Narrows the list of checkboxes down to parameters that match the user's input. The search
|
|
|
|
* algorithm is modelled after {@see ve.ui.MWParameterSearchWidget.buildIndex}. We search the
|
|
|
|
* parameter's primary name, aliases, label, and description. But not e.g. the example value.
|
2021-07-12 15:00:04 +00:00
|
|
|
*
|
2021-08-13 14:41:48 +00:00
|
|
|
* @private
|
2021-07-14 07:31:42 +00:00
|
|
|
* @param {string} query user input
|
2021-08-31 08:05:25 +00:00
|
|
|
* @fires filterParametersById
|
2021-07-12 15:00:04 +00:00
|
|
|
*/
|
2021-08-06 13:05:54 +00:00
|
|
|
ve.ui.MWTransclusionOutlineTemplateWidget.prototype.filterParameters = function ( query ) {
|
2021-08-05 12:36:10 +00:00
|
|
|
var self = this,
|
|
|
|
template = this.templateModel,
|
|
|
|
spec = this.templateModel.getSpec(),
|
2021-08-11 06:06:22 +00:00
|
|
|
visibility = {},
|
2021-07-14 07:31:42 +00:00
|
|
|
nothingFound = true;
|
|
|
|
|
|
|
|
query = query.trim().toLowerCase();
|
|
|
|
|
|
|
|
// Note: We can't really cache this because the list of know parameters can change any time
|
2021-08-26 14:29:42 +00:00
|
|
|
this.parameters.items.forEach( function ( item ) {
|
|
|
|
var paramName = item.getData(),
|
2021-08-05 10:11:40 +00:00
|
|
|
placesToSearch = [
|
|
|
|
spec.getPrimaryParameterName( paramName ),
|
|
|
|
spec.getParameterLabel( paramName ),
|
|
|
|
spec.getParameterDescription( paramName )
|
|
|
|
].concat( spec.getParameterAliases( paramName ) );
|
2021-07-14 07:31:42 +00:00
|
|
|
|
|
|
|
var foundSomeMatch = placesToSearch.some( function ( term ) {
|
|
|
|
return term && term.toLowerCase().indexOf( query ) !== -1;
|
|
|
|
} );
|
2021-07-12 15:00:04 +00:00
|
|
|
|
2021-08-26 14:29:42 +00:00
|
|
|
item.toggle( foundSomeMatch );
|
2021-08-11 06:06:22 +00:00
|
|
|
|
2021-07-14 07:31:42 +00:00
|
|
|
nothingFound = nothingFound && !foundSomeMatch;
|
2021-08-05 12:36:10 +00:00
|
|
|
|
|
|
|
var param = template.getParameter( paramName );
|
|
|
|
if ( param ) {
|
2021-08-11 06:06:22 +00:00
|
|
|
visibility[ param.getId() ] = foundSomeMatch;
|
2021-08-05 12:36:10 +00:00
|
|
|
}
|
2021-07-12 15:00:04 +00:00
|
|
|
} );
|
|
|
|
|
2021-07-14 07:31:42 +00:00
|
|
|
this.infoWidget.toggle( nothingFound );
|
2021-08-31 08:05:25 +00:00
|
|
|
self.emit( 'filterParametersById', visibility );
|
2021-07-12 15:00:04 +00:00
|
|
|
};
|