/*!
- * OOjs UI v0.16.5
+ * OOjs UI v0.17.3
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2016 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-04-07T15:12:41Z
+ * Date: 2016-05-24T22:46:32Z
*/
( function ( OO ) {
/**
* Set the button's active state.
*
- * The active state occurs when a {@link OO.ui.ButtonOptionWidget ButtonOptionWidget} or
- * a {@link OO.ui.ToggleButtonWidget ToggleButtonWidget} is pressed. This method does nothing
- * for other button types.
+ * The active state can be set on:
*
+ * - {@link OO.ui.ButtonOptionWidget ButtonOptionWidget} when it is selected
+ * - {@link OO.ui.ToggleButtonWidget ToggleButtonWidget} when it is toggle on
+ * - {@link OO.ui.ButtonWidget ButtonWidget} when clicking the button would only refresh the page
+ *
+ * @protected
* @param {boolean} value Make button active
* @chainable
*/
/**
* Check if the button is active
*
+ * @protected
* @return {boolean} The button is active
*/
OO.ui.mixin.ButtonElement.prototype.isActive = function () {
*
* @constructor
* @param {Object} [config] Configuration options
+ * @cfg {boolean} [active=false] Whether button should be shown as active
* @cfg {string} [href] Hyperlink to visit when the button is clicked.
* @cfg {string} [target] The frame or window in which to open the hyperlink.
* @cfg {boolean} [noFollow] Search engine traversal hint (default: true)
this.$element
.addClass( 'oo-ui-buttonWidget' )
.append( this.$button );
+ this.setActive( config.active );
this.setHref( config.href );
this.setTarget( config.target );
this.setNoFollow( config.noFollow );
return this;
};
+// Override method visibility hints from ButtonElement
+/**
+ * @method setActive
+ */
+/**
+ * @method isActive
+ */
+
/**
* A ButtonGroupWidget groups related buttons and is used together with OO.ui.ButtonWidget and
* its subclasses. Each button in a group is addressed by a unique reference. Buttons can be added,
};
/**
- * Clip element to visible boundaries and allow scrolling when needed. Call this method when
- * the element's natural height changes.
+ * Clip element to visible boundaries and allow scrolling when needed. You should call this method
+ * when the element's natural height changes.
*
* Element will be clipped the bottom or right of the element is within 10px of the edge of, or
* overlapped by, the visible area of the nearest scrollable container.
*
+ * Because calling clip() when the natural height changes isn't always possible, we also set
+ * max-height when the element isn't being clipped. This means that if the element tries to grow
+ * beyond the edge, something reasonable will happen before clip() is called.
+ *
* @chainable
*/
OO.ui.mixin.ClippableElement.prototype.clip = function () {
clipHeight = allotedHeight < naturalHeight;
if ( clipWidth ) {
- this.$clippable.css( { overflowX: 'scroll', width: Math.max( 0, allotedWidth ) } );
+ this.$clippable.css( {
+ overflowX: 'scroll',
+ width: Math.max( 0, allotedWidth ),
+ maxWidth: ''
+ } );
} else {
- this.$clippable.css( { width: this.idealWidth ? this.idealWidth - extraWidth : '', overflowX: '' } );
+ this.$clippable.css( {
+ overflowX: '',
+ width: this.idealWidth ? this.idealWidth - extraWidth : '',
+ maxWidth: Math.max( 0, allotedWidth )
+ } );
}
if ( clipHeight ) {
- this.$clippable.css( { overflowY: 'scroll', height: Math.max( 0, allotedHeight ) } );
+ this.$clippable.css( {
+ overflowY: 'scroll',
+ height: Math.max( 0, allotedHeight ),
+ maxHeight: ''
+ } );
} else {
- this.$clippable.css( { height: this.idealHeight ? this.idealHeight - extraHeight : '', overflowY: '' } );
+ this.$clippable.css( {
+ overflowY: '',
+ height: this.idealHeight ? this.idealHeight - extraHeight : '',
+ maxHeight: Math.max( 0, allotedHeight )
+ } );
}
// If we stopped clipping in at least one of the dimensions
*
* @class
* @extends OO.ui.Widget
+ * @mixins OO.ui.mixin.ItemWidget
* @mixins OO.ui.mixin.LabelElement
* @mixins OO.ui.mixin.FlaggedElement
+ * @mixins OO.ui.mixin.AccessKeyedElement
*
* @constructor
* @param {Object} [config] Configuration options
OO.ui.mixin.ItemWidget.call( this );
OO.ui.mixin.LabelElement.call( this, config );
OO.ui.mixin.FlaggedElement.call( this, config );
+ OO.ui.mixin.AccessKeyedElement.call( this, config );
// Properties
this.selected = false;
// Initialization
this.$element
.data( 'oo-ui-optionWidget', this )
+ // Allow programmatic focussing (and by accesskey), but not tabbing
+ .attr( 'tabindex', '-1' )
.attr( 'role', 'option' )
.attr( 'aria-selected', 'false' )
.addClass( 'oo-ui-optionWidget' )
OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.ItemWidget );
OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.LabelElement );
OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.FlaggedElement );
+OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.AccessKeyedElement );
/* Static Properties */
toggle: 'onToggle'
} );
this.$element.on( {
+ focusin: this.onFocus.bind( this ),
mousedown: this.onMouseDown.bind( this ),
mouseover: this.onMouseOver.bind( this ),
mouseleave: this.onMouseLeave.bind( this )
/* Methods */
+/**
+ * Handle focus events
+ *
+ * @private
+ * @param {jQuery.Event} event
+ */
+OO.ui.SelectWidget.prototype.onFocus = function ( event ) {
+ if ( event.target === this.$element[ 0 ] ) {
+ // This widget was focussed, e.g. by the user tabbing to it.
+ // The styles for focus state depend on one of the items being selected.
+ if ( !this.getSelectedItem() ) {
+ this.selectItem( this.getFirstSelectableItem() );
+ }
+ } else {
+ // One of the options got focussed (and the event bubbled up here).
+ // They can't be tabbed to, but they can be activated using accesskeys.
+ this.selectItem( this.getTargetItem( event ) );
+ this.$element.focus();
+ }
+};
+
/**
* Handle mouse down events.
*
* the text the user types. This config is used by {@link OO.ui.ComboBoxInputWidget ComboBoxInputWidget}
* and {@link OO.ui.mixin.LookupElement LookupElement}
* @cfg {jQuery} [$input] Text input used to implement option highlighting for menu items that match
- * the text the user types. This config is used by {@link OO.ui.CapsuleMultiSelectWidget CapsuleMultiSelectWidget}
+ * the text the user types. This config is used by {@link OO.ui.CapsuleMultiselectWidget CapsuleMultiselectWidget}
* @cfg {OO.ui.Widget} [widget] Widget associated with the menu's active state. If the user clicks the mouse
* anywhere on the page outside of this widget, the menu is hidden. For example, if there is a button
* that toggles the menu's visibility on click, the menu will be hidden then re-shown when the user clicks
// Parent constructor
OO.ui.RadioOptionWidget.parent.call( this, config );
- // Events
- this.radio.$input.on( 'focus', this.onInputFocus.bind( this ) );
-
// Initialization
// Remove implicit role, we're handling it ourselves
this.radio.$input.attr( 'role', 'presentation' );
/* Methods */
-/**
- * @param {jQuery.Event} e Focus event
- * @private
- */
-OO.ui.RadioOptionWidget.prototype.onInputFocus = function () {
- this.radio.$input.blur();
- this.$element.parent().focus();
-};
-
/**
* @inheritdoc
*/
* @constructor
* @param {Object} [config] Configuration options
* @cfg {string} [type='text'] The value of the HTML `type` attribute: 'text', 'password', 'search',
- * 'email', 'url' or 'date'. Ignored if `multiline` is true.
+ * 'email', 'url', 'date' or 'number'. Ignored if `multiline` is true.
*
* Some values of `type` result in additional behaviors:
*
*
* @private
* @param {jQuery.Event} e Mouse down event
- * @fires icon
*/
OO.ui.TextInputWidget.prototype.onIconMouseDown = function ( e ) {
if ( e.which === OO.ui.MouseButtons.LEFT ) {
*
* @private
* @param {jQuery.Event} e Mouse down event
- * @fires indicator
*/
OO.ui.TextInputWidget.prototype.onIndicatorMouseDown = function ( e ) {
if ( e.which === OO.ui.MouseButtons.LEFT ) {
* @protected
*/
OO.ui.TextInputWidget.prototype.getInputElement = function ( config ) {
- return config.multiline ?
- $( '<textarea>' ) :
- $( '<input>' ).attr( 'type', this.getSaneType( config ) );
+ if ( config.multiline ) {
+ return $( '<textarea>' );
+ } else if ( this.getSaneType( config ) === 'number' ) {
+ return $( '<input>' )
+ .attr( 'step', 'any' )
+ .attr( 'type', 'number' );
+ } else {
+ return $( '<input>' ).attr( 'type', this.getSaneType( config ) );
+ }
};
/**
* @private
*/
OO.ui.TextInputWidget.prototype.getSaneType = function ( config ) {
- var type = [ 'text', 'password', 'search', 'email', 'url', 'date' ].indexOf( config.type ) !== -1 ?
- config.type :
- 'text';
- return config.multiline ? 'multiline' : type;
+ var allowedTypes = [
+ 'text',
+ 'password',
+ 'search',
+ 'email',
+ 'url',
+ 'date',
+ 'number'
+ ];
+ return allowedTypes.indexOf( config.type ) !== -1 ? config.type : 'text';
};
/**