/*!
- * OOUI v0.27.3
+ * OOUI v0.27.6
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2018 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2018-06-07T21:36:30Z
+ * Date: 2018-08-01T22:17:59Z
*/
( function ( OO ) {
this.$icon = $icon
.addClass( 'oo-ui-iconElement-icon' )
+ .toggleClass( 'oo-ui-iconElement-noIcon', !this.icon )
.toggleClass( 'oo-ui-icon-' + this.icon, !!this.icon );
if ( this.iconTitle !== null ) {
this.$icon.attr( 'title', this.iconTitle );
}
this.$element.toggleClass( 'oo-ui-iconElement', !!this.icon );
+ if ( this.$icon ) {
+ this.$icon.toggleClass( 'oo-ui-iconElement-noIcon', !this.icon );
+ }
this.updateThemeClasses();
return this;
this.$indicator = $indicator
.addClass( 'oo-ui-indicatorElement-indicator' )
+ .toggleClass( 'oo-ui-indicatorElement-noIndicator', !this.indicator )
.toggleClass( 'oo-ui-indicator-' + this.indicator, !!this.indicator );
if ( this.indicatorTitle !== null ) {
this.$indicator.attr( 'title', this.indicatorTitle );
}
this.$element.toggleClass( 'oo-ui-indicatorElement', !!this.indicator );
+ if ( this.$indicator ) {
+ this.$indicator.toggleClass( 'oo-ui-indicatorElement-noIndicator', !this.indicator );
+ }
this.updateThemeClasses();
return this;
* var button = new OO.ui.ButtonWidget( {
* label: 'Button with Icon',
* icon: 'trash',
- * iconTitle: 'Remove'
+ * title: 'Remove'
* } );
* $( 'body' ).append( button.$element );
*
* // An icon widget with a label
* var myIcon = new OO.ui.IconWidget( {
* icon: 'help',
- * iconTitle: 'Help'
+ * title: 'Help'
* } );
* // Create a label.
* var iconLabel = new OO.ui.LabelWidget( {
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {number} [width=320] Width of popup in pixels
- * @cfg {number} [height] Height of popup in pixels. Omit to use the automatic height.
+ * @cfg {number|null} [width=320] Width of popup in pixels. Pass `null` to use automatic width.
+ * @cfg {number|null} [height=null] Height of popup in pixels. Pass `null` to use automatic height.
* @cfg {boolean} [anchor=true] Show anchor pointing to origin of popup
* @cfg {string} [position='below'] Where to position the popup relative to $floatableContainer
* 'above': Put popup above $floatableContainer; anchor points down to the horizontal center
this.$container = config.$container;
this.containerPadding = config.containerPadding !== undefined ? config.containerPadding : 10;
this.autoClose = !!config.autoClose;
- this.$autoCloseIgnore = config.$autoCloseIgnore;
this.transitionTimeout = null;
this.anchored = false;
- this.width = config.width !== undefined ? config.width : 320;
- this.height = config.height !== undefined ? config.height : null;
this.onMouseDownHandler = this.onMouseDown.bind( this );
this.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this );
// Initialization
+ this.setSize( config.width, config.height );
this.toggleAnchor( config.anchor === undefined || config.anchor );
this.setAlignment( config.align || 'center' );
this.setPosition( config.position || 'below' );
this.setAutoFlip( config.autoFlip === undefined || config.autoFlip );
+ this.setAutoCloseIgnore( config.$autoCloseIgnore );
this.$body.addClass( 'oo-ui-popupWidget-body' );
this.$anchor.addClass( 'oo-ui-popupWidget-anchor' );
this.$popup
OO.ui.PopupWidget.prototype.bindMouseDownListener = function () {
// Capture clicks outside popup
this.getElementWindow().addEventListener( 'mousedown', this.onMouseDownHandler, true );
+ // We add 'click' event because iOS safari needs to respond to this event.
+ // We can't use 'touchstart' (as is usually the equivalent to 'mousedown') because
+ // then it will trigger when scrolling. While iOS Safari has some reported behavior
+ // of occasionally not emitting 'click' properly, that event seems to be the standard
+ // that it should be emitting, so we add it to this and will operate the event handler
+ // on whichever of these events was triggered first
+ this.getElementDocument().addEventListener( 'click', this.onMouseDownHandler, true );
};
/**
*/
OO.ui.PopupWidget.prototype.unbindMouseDownListener = function () {
this.getElementWindow().removeEventListener( 'mousedown', this.onMouseDownHandler, true );
+ this.getElementDocument().removeEventListener( 'click', this.onMouseDownHandler, true );
};
/**
*
* Changing the size may also change the popup's position depending on the alignment.
*
- * @param {number} width Width in pixels
- * @param {number} height Height in pixels
+ * @param {number|null} [width=320] Width in pixels. Pass `null` to use automatic width.
+ * @param {number|null} [height=null] Height in pixels. Pass `null` to use automatic height.
* @param {boolean} [transition=false] Use a smooth transition
* @chainable
*/
OO.ui.PopupWidget.prototype.setSize = function ( width, height, transition ) {
- this.width = width;
+ this.width = width !== undefined ? width : 320;
this.height = height !== undefined ? height : null;
if ( this.isVisible() ) {
this.updateDimensions( transition );
// Set height and width before we do anything else, since it might cause our measurements
// to change (e.g. due to scrollbars appearing or disappearing), and it also affects centering
this.$popup.css( {
- width: this.width,
+ width: this.width !== null ? this.width : 'auto',
height: this.height !== null ? this.height : 'auto'
} );
near = vertical ? 'top' : 'left';
far = vertical ? 'bottom' : 'right';
sizeProp = vertical ? 'Height' : 'Width';
- popupSize = vertical ? ( this.height || this.$popup.height() ) : this.width;
+ popupSize = vertical ? ( this.height || this.$popup.height() ) : ( this.width || this.$popup.width() );
this.setAnchorEdge( anchorEdgeMap[ popupPosition ] );
this.horizontalPosition = vertical ? popupPosition : hPosMap[ align ];
}
};
+/**
+ * Set which elements will not close the popup when clicked.
+ *
+ * For auto-closing popups, clicks on these elements will not cause the popup to auto-close.
+ *
+ * @param {jQuery} $autoCloseIgnore Elements to ignore for auto-closing
+ */
+OO.ui.PopupWidget.prototype.setAutoCloseIgnore = function ( $autoCloseIgnore ) {
+ this.$autoCloseIgnore = $autoCloseIgnore;
+};
+
/**
* Get an ID of the body element, this can be used as the
* `aria-describedby` attribute for an input field.
* @protected
*/
OO.ui.MenuSelectWidget.prototype.updateItemVisibility = function () {
- var i, item, visible, section, sectionEmpty, filter, exactFilter,
- firstItemFound = false,
+ var i, item, items, visible, section, sectionEmpty, filter, exactFilter,
anyVisible = false,
len = this.items.length,
showAll = !this.isVisible(),
if ( this.$input && this.filterFromInput ) {
filter = showAll ? null : this.getItemMatcher( this.$input.val() );
exactFilter = this.getItemMatcher( this.$input.val(), true );
-
// Hide non-matching options, and also hide section headers if all options
// in their section are hidden.
for ( i = 0; i < len; i++ ) {
anyVisible = anyVisible || visible;
sectionEmpty = sectionEmpty && !visible;
item.toggle( visible );
- if ( this.highlightOnFilter && visible && !firstItemFound ) {
- // Highlight the first item in the list
- this.highlightItem( item );
- firstItemFound = true;
- }
}
}
// Process the final section
}
this.$element.toggleClass( 'oo-ui-menuSelectWidget-invisible', !anyVisible );
+
+ if ( this.highlightOnFilter ) {
+ // Highlight the first item on the list
+ item = null;
+ items = this.getItems();
+ for ( i = 0; i < items.length; i++ ) {
+ if ( items[ i ].isVisible() ) {
+ item = items[ i ];
+ break;
+ }
+ }
+ this.highlightItem( item );
+ }
+
}
// Reevaluate clipping
if ( this.autosize ) {
this.$clone = this.$input
.clone()
+ .removeAttr( 'id' )
+ .removeAttr( 'name' )
.insertAfter( this.$input )
.attr( 'aria-hidden', 'true' )
.addClass( 'oo-ui-element-hidden' );
this.align = null;
this.helpInline = config.helpInline;
- if ( config.help ) {
- if ( this.helpInline ) {
- this.$help = new OO.ui.LabelWidget( {
- label: config.help,
- classes: [ 'oo-ui-inline-help' ]
- } ).$element;
- } else {
- this.popupButtonWidget = new OO.ui.PopupButtonWidget( {
- $overlay: config.$overlay,
- popup: {
- padded: true
- },
- classes: [ 'oo-ui-fieldLayout-help' ],
- framed: false,
- icon: 'info',
- label: OO.ui.msg( 'ooui-field-help' )
- } );
- if ( config.help instanceof OO.ui.HtmlSnippet ) {
- this.popupButtonWidget.getPopup().$body.html( config.help.toString() );
- } else {
- this.popupButtonWidget.getPopup().$body.text( config.help );
- }
- this.$help = this.popupButtonWidget.$element;
- }
- } else {
- this.$help = $( [] );
- }
-
// Events
this.fieldWidget.connect( this, { disable: 'onFieldDisable' } );
// Initialization
- if ( config.help && !config.helpInline ) {
- // Set the 'aria-describedby' attribute on the fieldWidget
- // Preference given to an input or a button
- (
- this.fieldWidget.$input ||
- this.fieldWidget.$button ||
- this.fieldWidget.$element
- ).attr(
- 'aria-describedby',
- this.popupButtonWidget.getPopup().getBodyId()
- );
- }
+ this.$help = config.help ?
+ this.createHelpElement( config.help, config.$overlay ) :
+ $( [] );
if ( this.fieldWidget.getInputId() ) {
this.$label.attr( 'for', this.fieldWidget.getInputId() );
+ if ( this.helpInline ) {
+ this.$help.attr( 'for', this.fieldWidget.getInputId() );
+ }
} else {
this.$label.on( 'click', function () {
this.fieldWidget.simulateLabelClick();
}.bind( this ) );
+ if ( this.helpInline ) {
+ this.$help.on( 'click', function () {
+ this.fieldWidget.simulateLabelClick();
+ }.bind( this ) );
+ }
}
this.$element
.addClass( 'oo-ui-fieldLayout' )
return title;
};
+/**
+ * Creates and returns the help element. Also sets the `aria-describedby`
+ * attribute on the main element of the `fieldWidget`.
+ *
+ * @private
+ * @param {string|OO.ui.HtmlSnippet} [help] Help text.
+ * @param {jQuery} [$overlay] Passed to OO.ui.PopupButtonWidget for help popup.
+ * @return {jQuery} The element that should become `this.$help`.
+ */
+OO.ui.FieldLayout.prototype.createHelpElement = function ( help, $overlay ) {
+ var helpId, helpWidget;
+
+ if ( this.helpInline ) {
+ helpWidget = new OO.ui.LabelWidget( {
+ label: help,
+ classes: [ 'oo-ui-inline-help' ]
+ } );
+
+ helpId = helpWidget.getElementId();
+ } else {
+ helpWidget = new OO.ui.PopupButtonWidget( {
+ $overlay: $overlay,
+ popup: {
+ padded: true
+ },
+ classes: [ 'oo-ui-fieldLayout-help' ],
+ framed: false,
+ icon: 'info',
+ label: OO.ui.msg( 'ooui-field-help' )
+ } );
+ if ( help instanceof OO.ui.HtmlSnippet ) {
+ helpWidget.getPopup().$body.html( help.toString() );
+ } else {
+ helpWidget.getPopup().$body.text( help );
+ }
+
+ helpId = helpWidget.getPopup().getBodyId();
+ }
+
+ // Set the 'aria-describedby' attribute on the fieldWidget
+ // Preference given to an input or a button
+ (
+ this.fieldWidget.$input ||
+ this.fieldWidget.$button ||
+ this.fieldWidget.$element
+ ).attr( 'aria-describedby', helpId );
+
+ return helpWidget.$element;
+};
+
/**
* ActionFieldLayouts are used with OO.ui.FieldsetLayout. The layout consists of a field-widget, a button,
* and an optional label and/or help text. The field-widget (e.g., a {@link OO.ui.TextInputWidget TextInputWidget}),