mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-15 18:39:52 +00:00
f9fda0594f
Allows setting aria labels and descriptions on elements in a convinient way. I did not use the the .mixin. convention here for because there's already another mixin in that folder that's also not having .mixin. as part of its name. And then there's also no no need to open up that extra namespace here. If we move this upstream at some point this can be changed though. Bug: T291284 Change-Id: I1b3d40400d539f851f13719e16ced200968a7f92
202 lines
6 KiB
JavaScript
202 lines
6 KiB
JavaScript
/**
|
|
* This is modelled after {@see OO.ui.OutlineSelectWidget}.
|
|
*
|
|
* @class
|
|
* @extends OO.ui.SelectWidget
|
|
*
|
|
* @constructor
|
|
* @param {Object} config
|
|
* @cfg {ve.ui.MWTransclusionOutlineParameterWidget[]} items
|
|
*/
|
|
ve.ui.MWTransclusionOutlineParameterSelectWidget = function VeUiMWTransclusionOutlineParameterSelectWidget( config ) {
|
|
// Parent constructor
|
|
ve.ui.MWTransclusionOutlineParameterSelectWidget.super.call( this, ve.extendObject( config, {
|
|
classes: [ 've-ui-mwTransclusionOutlineParameterSelectWidget' ],
|
|
multiselect: true
|
|
} ) );
|
|
|
|
// Mixin constructors
|
|
OO.ui.mixin.TabIndexedElement.call( this, {
|
|
tabIndex: this.isEmpty() ? -1 : 0
|
|
} );
|
|
ve.ui.MWAriaDescribe.call( this, config );
|
|
|
|
this.$element
|
|
.on( {
|
|
focus: this.bindDocumentKeyDownListener.bind( this ),
|
|
blur: this.unbindDocumentKeyDownListener.bind( this )
|
|
} )
|
|
// FIXME might make sense upstream?
|
|
.attr( 'aria-multiselectable', 'true' );
|
|
};
|
|
|
|
/* Inheritance */
|
|
|
|
OO.inheritClass( ve.ui.MWTransclusionOutlineParameterSelectWidget, OO.ui.SelectWidget );
|
|
OO.mixinClass( ve.ui.MWTransclusionOutlineParameterSelectWidget, OO.ui.mixin.TabIndexedElement );
|
|
OO.mixinClass( ve.ui.MWTransclusionOutlineParameterSelectWidget, ve.ui.MWAriaDescribe );
|
|
|
|
/* Events */
|
|
|
|
/**
|
|
* This is fired instead of the "choose" event from the {@see OO.ui.SelectWidget} base class when
|
|
* pressing space on a parameter to toggle it, without loosing the focus.
|
|
*
|
|
* @event templateParameterSelectionChanged
|
|
* @param {ve.ui.MWTransclusionOutlineParameterWidget} item
|
|
* @param {boolean} selected
|
|
*/
|
|
|
|
/* Static Methods */
|
|
|
|
/**
|
|
* @param {Object} config
|
|
* @param {string} config.data Parameter name
|
|
* @param {string} config.label
|
|
* @param {boolean} [config.required] Required parameters can't be unchecked
|
|
* @param {boolean} [config.selected] If the parameter is currently used (checked)
|
|
* @return {ve.ui.MWTransclusionOutlineParameterWidget}
|
|
*/
|
|
ve.ui.MWTransclusionOutlineParameterSelectWidget.static.createItem = function ( config ) {
|
|
return new ve.ui.MWTransclusionOutlineParameterWidget( config );
|
|
};
|
|
|
|
/* Methods */
|
|
|
|
/**
|
|
* @inheritDoc OO.ui.mixin.GroupElement
|
|
* @param {ve.ui.MWTransclusionOutlineParameterWidget[]} items
|
|
* @param {number} [index]
|
|
* @return {ve.ui.MWTransclusionOutlineParameterSelectWidget}
|
|
*/
|
|
ve.ui.MWTransclusionOutlineParameterSelectWidget.prototype.addItems = function ( items, index ) {
|
|
var self = this;
|
|
items.forEach( function ( item ) {
|
|
item.connect( self, {
|
|
change: [ 'onCheckboxChange', item ]
|
|
} );
|
|
} );
|
|
|
|
ve.ui.MWTransclusionOutlineParameterSelectWidget.super.prototype.addItems.call( this, items, index );
|
|
this.setTabIndex( this.isEmpty() ? -1 : 0 );
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* @param {string} [paramName] Parameter name to highlight, e.g. "param1". Omit for no highlight.
|
|
*/
|
|
ve.ui.MWTransclusionOutlineParameterSelectWidget.prototype.highlightParameter = function ( paramName ) {
|
|
var item = this.findItemFromData( paramName );
|
|
// Intentionally drop any highlighting if the parameter can't be found
|
|
this.highlightItem( item );
|
|
if ( item ) {
|
|
this.scrollItemIntoView( item );
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @param {string} paramName
|
|
*/
|
|
ve.ui.MWTransclusionOutlineParameterSelectWidget.prototype.markParameterAsUnused = function ( paramName ) {
|
|
// There is no OO.ui.SelectWidget.unselectItemByData(), we need to do this manually
|
|
var item = this.findItemFromData( paramName );
|
|
if ( item ) {
|
|
item.setSelected( false );
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @private
|
|
* @param {ve.ui.MWTransclusionOutlineParameterWidget} item
|
|
* @param {boolean} value
|
|
*/
|
|
ve.ui.MWTransclusionOutlineParameterSelectWidget.prototype.onCheckboxChange = function ( item, value ) {
|
|
// This extra check shouldn't be necessary, but better be safe than sorry
|
|
if ( item.isSelected() !== value ) {
|
|
// Note: This should have been named `toggle…` as it toggles the item's selection
|
|
this.chooseItem( item );
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @inheritDoc OO.ui.SelectWidget
|
|
*/
|
|
ve.ui.MWTransclusionOutlineParameterSelectWidget.prototype.onFocus = function () {
|
|
if ( !this.findHighlightedItem() ) {
|
|
this.highlightItem( this.items[ 0 ] );
|
|
}
|
|
// Don't call the parent. It makes assumptions that conflict with how we use selections.
|
|
};
|
|
|
|
/**
|
|
* @inheritDoc OO.ui.SelectWidget
|
|
* @param {jQuery.Event} e
|
|
* @fires choose
|
|
*/
|
|
ve.ui.MWTransclusionOutlineParameterSelectWidget.prototype.onMouseDown = function ( e ) {
|
|
if ( e.which === OO.ui.MouseButtons.LEFT ) {
|
|
var item = this.findTargetItem( e );
|
|
// Same as pressing enter, see below.
|
|
if ( item && item.isSelected() ) {
|
|
this.emit( 'choose', item, item.isSelected() );
|
|
|
|
// Don't call the parent, i.e. can't click to unselect the item
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ve.ui.MWTransclusionOutlineParameterSelectWidget.super.prototype.onMouseDown.call( this, e );
|
|
};
|
|
|
|
/**
|
|
* @inheritDoc OO.ui.SelectWidget
|
|
* @param {KeyboardEvent} e
|
|
* @fires choose
|
|
* @fires templateParameterSelectionChanged
|
|
*/
|
|
ve.ui.MWTransclusionOutlineParameterSelectWidget.prototype.onDocumentKeyDown = function ( e ) {
|
|
var item;
|
|
|
|
switch ( e.keyCode ) {
|
|
case OO.ui.Keys.HOME:
|
|
item = this.items[ 0 ];
|
|
if ( item ) {
|
|
this.highlightItem( item );
|
|
}
|
|
break;
|
|
case OO.ui.Keys.END:
|
|
item = this.items[ this.items.length - 1 ];
|
|
if ( item ) {
|
|
this.highlightItem( item );
|
|
}
|
|
break;
|
|
case OO.ui.Keys.SPACE:
|
|
item = this.findHighlightedItem();
|
|
if ( item ) {
|
|
// Warning, this intentionally doesn't call .chooseItem() because we don't want this
|
|
// to fire a "choose" event!
|
|
if ( item.isSelected() ) {
|
|
this.unselectItem( item );
|
|
} else {
|
|
this.selectItem( item );
|
|
}
|
|
this.emit( 'templateParameterSelectionChanged', item, item.isSelected() );
|
|
}
|
|
e.preventDefault();
|
|
break;
|
|
case OO.ui.Keys.ENTER:
|
|
item = this.findHighlightedItem();
|
|
// Same as clicking with the mouse, see above.
|
|
if ( item && item.isSelected() ) {
|
|
this.emit( 'choose', item, item.isSelected() );
|
|
e.preventDefault();
|
|
|
|
// Don't call the parent, i.e. can't use enter to unselect the item
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
ve.ui.MWTransclusionOutlineParameterSelectWidget.super.prototype.onDocumentKeyDown.call( this, e );
|
|
};
|