mediawiki-extensions-Visual.../modules/ve-mw/ui/widgets/ve.ui.MWTransclusionOutlineContainerWidget.js
Thiemo Kreuz 7a8ad64cbd Fix click/enter on template parameters not focusing the input
This got lost in patch I20dbd2b.

Both events come from the same sidebar class. The difference
between the two is:
* selectPart is when the button representing a top-level part
  is clicked.
* focusPart is when a parameter name is clicked while the
  parameter is already checked.

Yes, this is confusing at the moment. Following patches will
rename, merge and split a lot of these events to be much more
self-explaining.

Bug: T285323
Change-Id: I0c6b53c93c712ff5e47c1beb5199d590cba7ab1a
2021-09-01 16:01:17 +02:00

176 lines
5.1 KiB
JavaScript

/*!
* VisualEditor user interface MWTransclusionOutlineContainerWidget class.
*
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* Container for transclusion, may contain a single or multiple templates.
*
* @class
* @extends OO.ui.Widget
*
* @constructor
* @property {Object.<string,ve.ui.MWTransclusionOutlinePartWidget>} partWidgets Map of top-level
* items currently visible in this container, indexed by part id
*/
ve.ui.MWTransclusionOutlineContainerWidget = function VeUiMWTransclusionOutlineContainerWidget() {
// Parent constructor
ve.ui.MWTransclusionOutlineContainerWidget.super.call( this );
// Initialization
this.partWidgets = {};
this.$element.addClass( 've-ui-mwTransclusionOutlineContainerWidget' );
};
/* Inheritance */
OO.inheritClass( ve.ui.MWTransclusionOutlineContainerWidget, OO.ui.Widget );
/* Events */
/**
* @event filterParameters
* @param {Object.<string,boolean>} visibility Keyed by unique id of the parameter, e.g. something
* like "part_1/param1". Note this lists only parameters that are currently in use.
*/
/**
* @event focusPart
* @param {string} partId Unique id of the part, e.g. something like "part_1" or "part_1/param1".
*/
/**
* @param {ve.dm.MWTransclusionPartModel|null} removed Removed part
* @param {ve.dm.MWTransclusionPartModel|null} added Added part
* @param {number} [newPosition]
*/
ve.ui.MWTransclusionOutlineContainerWidget.prototype.onReplacePart = function ( removed, added, newPosition ) {
if ( removed ) {
this.removePartWidget( removed );
}
// TODO: reselect if active part was in a removed template
if ( added ) {
this.addPartWidget( added, newPosition );
}
};
/**
* @param {ve.dm.MWTransclusionModel} transclusionModel
*/
ve.ui.MWTransclusionOutlineContainerWidget.prototype.onTransclusionModelChange = function ( transclusionModel ) {
var newOrder = transclusionModel.getParts();
for ( var i = 0; i < newOrder.length; i++ ) {
var expectedWidget = this.partWidgets[ newOrder[ i ].getId() ],
$expectedElement = expectedWidget && expectedWidget.$element,
$currentElement = this.$element.children().eq( i );
if ( !$currentElement.is( $expectedElement ) ) {
// Move each widget to the correct position if it wasn't there before
$currentElement.before( $expectedElement );
}
}
};
/**
* @private
* @param {string} partId
* @fires focusPart
*/
ve.ui.MWTransclusionOutlineContainerWidget.prototype.onPartSelected = function ( partId ) {
this.selectPartById( partId );
this.emit( 'focusPart', partId );
};
/* Methods */
/**
* @private
* @param {ve.dm.MWTransclusionPartModel} part
*/
ve.ui.MWTransclusionOutlineContainerWidget.prototype.removePartWidget = function ( part ) {
var id = part.getId();
if ( id in this.partWidgets ) {
this.partWidgets[ id ]
.disconnect( this )
.$element.remove();
delete this.partWidgets[ id ];
}
};
/**
* @private
* @param {ve.dm.MWTransclusionPartModel} part
* @param {number} [newPosition]
* @fires filterParameters
*/
ve.ui.MWTransclusionOutlineContainerWidget.prototype.addPartWidget = function ( part, newPosition ) {
var widget;
if ( part instanceof ve.dm.MWTemplateModel ) {
widget = new ve.ui.MWTransclusionOutlineTemplateWidget( part );
// This forwards events from the nested ve.ui.MWTransclusionOutlineTemplateWidget upwards.
// The array syntax is a way to call `this.emit( 'filterParameters' )`.
widget.connect( this, {
focusPart: [ 'emit', 'focusPart' ],
filterParameters: [ 'emit', 'filterParameters' ]
} );
} else if ( part instanceof ve.dm.MWTemplatePlaceholderModel ) {
widget = new ve.ui.MWTransclusionOutlinePlaceholderWidget( part );
} else if ( part instanceof ve.dm.MWTransclusionContentModel ) {
widget = new ve.ui.MWTransclusionOutlineWikitextWidget( part );
}
widget.connect( this, {
selectPart: 'onPartSelected'
} );
this.partWidgets[ part.getId() ] = widget;
if ( typeof newPosition === 'number' && newPosition < this.$element.children().length ) {
this.$element.children().eq( newPosition ).before( widget.$element );
} else {
this.$element.append( widget.$element );
}
};
/**
* This is inspired by {@see OO.ui.SelectWidget.selectItem}, but isn't one.
*
* @param {string} partId Top-level part id, e.g. "part_1". Note this (currently) doesn't accept
* parameter ids like "part_1/param1".
*/
ve.ui.MWTransclusionOutlineContainerWidget.prototype.selectPartById = function ( partId ) {
for ( var id in this.partWidgets ) {
this.partWidgets[ id ].setSelected( id === partId );
}
};
/**
* This is inspired by {@see OO.ui.SelectWidget.findSelectedItem}, but isn't one.
*
* @return {string|undefined}
*/
ve.ui.MWTransclusionOutlineContainerWidget.prototype.findSelectedPartId = function () {
for ( var id in this.partWidgets ) {
var part = this.partWidgets[ id ];
if ( part.isSelected() ) {
return part.getData();
}
}
};
/**
* Removes all {@see ve.ui.MWTransclusionOutlinePartWidget}, i.e. empties the list.
*/
ve.ui.MWTransclusionOutlineContainerWidget.prototype.clear = function () {
for ( var id in this.partWidgets ) {
this.partWidgets[ id ]
.disconnect( this )
.$element.remove();
}
this.partWidgets = {};
};