Update OOjs UI to v0.17.3
[lhc/web/wiklou.git] / resources / lib / oojs-ui / oojs-ui-core.js
index a05193e..efed6b2 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * 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 ) {
 
@@ -2001,10 +2001,13 @@ OO.ui.mixin.ButtonElement.prototype.toggleFramed = function ( framed ) {
 /**
  * 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
  */
@@ -2017,6 +2020,7 @@ OO.ui.mixin.ButtonElement.prototype.setActive = function ( value ) {
 /**
  * Check if the button is active
  *
+ * @protected
  * @return {boolean} The button is active
  */
 OO.ui.mixin.ButtonElement.prototype.isActive = function () {
@@ -3332,6 +3336,7 @@ OO.ui.mixin.AccessKeyedElement.prototype.getAccessKey = 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)
@@ -3366,6 +3371,7 @@ OO.ui.ButtonWidget = function OoUiButtonWidget( config ) {
        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 );
@@ -3522,6 +3528,14 @@ OO.ui.ButtonWidget.prototype.setNoFollow = function ( 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,
@@ -4079,12 +4093,16 @@ OO.ui.mixin.ClippableElement.prototype.setIdealSize = function ( width, height )
 };
 
 /**
- * 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 () {
@@ -4128,14 +4146,30 @@ 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
@@ -4763,8 +4797,10 @@ OO.ui.mixin.ItemWidget.prototype.setElementGroup = function ( group ) {
  *
  * @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
@@ -4780,6 +4816,7 @@ OO.ui.OptionWidget = function OoUiOptionWidget( config ) {
        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;
@@ -4789,6 +4826,8 @@ OO.ui.OptionWidget = function OoUiOptionWidget( config ) {
        // 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' )
@@ -4801,6 +4840,7 @@ OO.inheritClass( OO.ui.OptionWidget, OO.ui.Widget );
 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 */
 
@@ -5001,6 +5041,7 @@ OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
                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 )
@@ -5081,6 +5122,27 @@ OO.ui.SelectWidget.static.passAllFilter = function () {
 
 /* 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.
  *
@@ -5954,7 +6016,7 @@ OO.ui.MenuSectionOptionWidget.static.highlightable = false;
  *  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
@@ -6415,9 +6477,6 @@ OO.ui.RadioOptionWidget = function OoUiRadioOptionWidget( config ) {
        // 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' );
@@ -6445,15 +6504,6 @@ OO.ui.RadioOptionWidget.static.tagName = 'label';
 
 /* Methods */
 
-/**
- * @param {jQuery.Event} e Focus event
- * @private
- */
-OO.ui.RadioOptionWidget.prototype.onInputFocus = function () {
-       this.radio.$input.blur();
-       this.$element.parent().focus();
-};
-
 /**
  * @inheritdoc
  */
@@ -7837,7 +7887,7 @@ OO.ui.RadioSelectInputWidget.prototype.setOptions = function ( options ) {
  * @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:
  *
@@ -8024,7 +8074,6 @@ OO.ui.TextInputWidget.static.gatherPreInfuseState = function ( node, config ) {
  *
  * @private
  * @param {jQuery.Event} e Mouse down event
- * @fires icon
  */
 OO.ui.TextInputWidget.prototype.onIconMouseDown = function ( e ) {
        if ( e.which === OO.ui.MouseButtons.LEFT ) {
@@ -8038,7 +8087,6 @@ OO.ui.TextInputWidget.prototype.onIconMouseDown = function ( e ) {
  *
  * @private
  * @param {jQuery.Event} e Mouse down event
- * @fires indicator
  */
 OO.ui.TextInputWidget.prototype.onIndicatorMouseDown = function ( e ) {
        if ( e.which === OO.ui.MouseButtons.LEFT ) {
@@ -8280,9 +8328,15 @@ OO.ui.TextInputWidget.prototype.adjustSize = function () {
  * @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 ) );
+       }
 };
 
 /**
@@ -8293,10 +8347,16 @@ OO.ui.TextInputWidget.prototype.getInputElement = function ( 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';
 };
 
 /**