Merge "Avoid 'message' in log context in AuthManager"
[lhc/web/wiklou.git] / resources / lib / oojs-ui / oojs-ui-core.js
index 4d32961..109645b 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.10
  * 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-08-03T16:38:22Z
+ * Date: 2016-10-03T18:59:01Z
  */
 ( function ( OO ) {
 
@@ -747,9 +747,7 @@ OO.ui.Element.static.unsafeInfuse = function ( idOrNode, domPromise ) {
        // pick up dynamic state, like focus, value of form inputs, scroll position, etc.
        state = cls.static.gatherPreInfuseState( $elem[ 0 ], data );
        // rebuild widget
-       // jscs:disable requireCapitalizedConstructors
        obj = new cls( data );
-       // jscs:enable requireCapitalizedConstructors
        // now replace old DOM with this new DOM.
        if ( top ) {
                // An efficient constructor might be able to reuse the entire DOM tree of the original element,
@@ -1584,12 +1582,8 @@ OO.ui.Widget.prototype.updateDisabled = function () {
  * @class
  *
  * @constructor
- * @param {Object} [config] Configuration options
  */
-OO.ui.Theme = function OoUiTheme( config ) {
-       // Configuration initialization
-       config = config || {};
-};
+OO.ui.Theme = function OoUiTheme() {};
 
 /* Setup */
 
@@ -1809,7 +1803,7 @@ OO.ui.mixin.ButtonElement = function OoUiMixinButtonElement( config ) {
        // Properties
        this.$button = null;
        this.framed = null;
-       this.active = false;
+       this.active = config.active !== undefined && config.active;
        this.onMouseUpHandler = this.onMouseUp.bind( this );
        this.onMouseDownHandler = this.onMouseDown.bind( this );
        this.onKeyDownHandler = this.onKeyDown.bind( this );
@@ -2026,6 +2020,7 @@ OO.ui.mixin.ButtonElement.prototype.toggleFramed = function ( framed ) {
 OO.ui.mixin.ButtonElement.prototype.setActive = function ( value ) {
        this.active = !!value;
        this.$element.toggleClass( 'oo-ui-buttonElement-active', this.active );
+       this.updateThemeClasses();
        return this;
 };
 
@@ -6366,7 +6361,10 @@ OO.ui.DropdownWidget = function OoUiDropdownWidget( config ) {
                keypress: this.menu.onKeyPressHandler,
                blur: this.menu.clearKeyPressBuffer.bind( this.menu )
        } );
-       this.menu.connect( this, { select: 'onMenuSelect' } );
+       this.menu.connect( this, {
+               select: 'onMenuSelect',
+               toggle: 'onMenuToggle'
+       } );
 
        // Initialization
        this.$handle
@@ -6422,6 +6420,16 @@ OO.ui.DropdownWidget.prototype.onMenuSelect = function ( item ) {
        this.setLabel( selectedLabel );
 };
 
+/**
+ * Handle menu toggle events.
+ *
+ * @private
+ * @param {boolean} isVisible Menu toggle event
+ */
+OO.ui.DropdownWidget.prototype.onMenuToggle = function ( isVisible ) {
+       this.$element.toggleClass( 'oo-ui-dropdownWidget-open', isVisible );
+};
+
 /**
  * Handle mouse click events.
  *
@@ -7167,7 +7175,6 @@ OO.ui.mixin.FloatableElement.prototype.togglePositioning = function ( positionin
  */
 OO.ui.mixin.FloatableElement.prototype.isElementInViewport = function ( $element, $container ) {
        var elemRect, contRect,
-               topEdgeInBounds = false,
                leftEdgeInBounds = false,
                bottomEdgeInBounds = false,
                rightEdgeInBounds = false;
@@ -7184,9 +7191,8 @@ OO.ui.mixin.FloatableElement.prototype.isElementInViewport = function ( $element
                contRect = $container[ 0 ].getBoundingClientRect();
        }
 
-       if ( elemRect.top >= contRect.top && elemRect.top <= contRect.bottom ) {
-               topEdgeInBounds = true;
-       }
+       // For completeness, if we still cared about topEdgeInBounds, that'd be:
+       // elemRect.top >= contRect.top && elemRect.top <= contRect.bottom
        if ( elemRect.left >= contRect.left && elemRect.left <= contRect.right ) {
                leftEdgeInBounds = true;
        }
@@ -7325,6 +7331,103 @@ OO.ui.FloatingMenuSelectWidget.prototype.toggle = function ( visible ) {
        return this;
 };
 
+/**
+ * Progress bars visually display the status of an operation, such as a download,
+ * and can be either determinate or indeterminate:
+ *
+ * - **determinate** process bars show the percent of an operation that is complete.
+ *
+ * - **indeterminate** process bars use a visual display of motion to indicate that an operation
+ *   is taking place. Because the extent of an indeterminate operation is unknown, the bar does
+ *   not use percentages.
+ *
+ * The value of the `progress` configuration determines whether the bar is determinate or indeterminate.
+ *
+ *     @example
+ *     // Examples of determinate and indeterminate progress bars.
+ *     var progressBar1 = new OO.ui.ProgressBarWidget( {
+ *         progress: 33
+ *     } );
+ *     var progressBar2 = new OO.ui.ProgressBarWidget();
+ *
+ *     // Create a FieldsetLayout to layout progress bars
+ *     var fieldset = new OO.ui.FieldsetLayout;
+ *     fieldset.addItems( [
+ *        new OO.ui.FieldLayout( progressBar1, {label: 'Determinate', align: 'top'}),
+ *        new OO.ui.FieldLayout( progressBar2, {label: 'Indeterminate', align: 'top'})
+ *     ] );
+ *     $( 'body' ).append( fieldset.$element );
+ *
+ * @class
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {number|boolean} [progress=false] The type of progress bar (determinate or indeterminate).
+ *  To create a determinate progress bar, specify a number that reflects the initial percent complete.
+ *  By default, the progress bar is indeterminate.
+ */
+OO.ui.ProgressBarWidget = function OoUiProgressBarWidget( config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.ProgressBarWidget.parent.call( this, config );
+
+       // Properties
+       this.$bar = $( '<div>' );
+       this.progress = null;
+
+       // Initialization
+       this.setProgress( config.progress !== undefined ? config.progress : false );
+       this.$bar.addClass( 'oo-ui-progressBarWidget-bar' );
+       this.$element
+               .attr( {
+                       role: 'progressbar',
+                       'aria-valuemin': 0,
+                       'aria-valuemax': 100
+               } )
+               .addClass( 'oo-ui-progressBarWidget' )
+               .append( this.$bar );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.ProgressBarWidget, OO.ui.Widget );
+
+/* Static Properties */
+
+OO.ui.ProgressBarWidget.static.tagName = 'div';
+
+/* Methods */
+
+/**
+ * Get the percent of the progress that has been completed. Indeterminate progresses will return `false`.
+ *
+ * @return {number|boolean} Progress percent
+ */
+OO.ui.ProgressBarWidget.prototype.getProgress = function () {
+       return this.progress;
+};
+
+/**
+ * Set the percent of the process completed or `false` for an indeterminate process.
+ *
+ * @param {number|boolean} progress Progress percent or `false` for indeterminate
+ */
+OO.ui.ProgressBarWidget.prototype.setProgress = function ( progress ) {
+       this.progress = progress;
+
+       if ( progress !== false ) {
+               this.$bar.css( 'width', this.progress + '%' );
+               this.$element.attr( 'aria-valuenow', this.progress );
+       } else {
+               this.$bar.css( 'width', '' );
+               this.$element.removeAttr( 'aria-valuenow' );
+       }
+       this.$element.toggleClass( 'oo-ui-progressBarWidget-indeterminate', progress === false );
+};
+
 /**
  * InputWidget is the base class for all input widgets, which
  * include {@link OO.ui.TextInputWidget text inputs}, {@link OO.ui.CheckboxInputWidget checkbox inputs},
@@ -8590,7 +8693,8 @@ OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
        // Events
        this.$input.on( {
                keypress: this.onKeyPress.bind( this ),
-               blur: this.onBlur.bind( this )
+               blur: this.onBlur.bind( this ),
+               focus: this.onFocus.bind( this )
        } );
        this.$input.one( {
                focus: this.onElementAttach.bind( this )
@@ -8602,6 +8706,7 @@ OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
                change: 'onChange',
                disable: 'onDisable'
        } );
+       this.on( 'change', OO.ui.debounce( this.onDebouncedChange.bind( this ), 250 ) );
 
        // Initialization
        this.$element
@@ -8744,6 +8849,16 @@ OO.ui.TextInputWidget.prototype.onBlur = function () {
        this.setValidityFlag();
 };
 
+/**
+ * Handle focus events.
+ *
+ * @private
+ * @param {jQuery.Event} e Focus event
+ */
+OO.ui.TextInputWidget.prototype.onFocus = function () {
+       this.setValidityFlag( true );
+};
+
 /**
  * Handle element attach events.
  *
@@ -8765,10 +8880,19 @@ OO.ui.TextInputWidget.prototype.onElementAttach = function () {
  */
 OO.ui.TextInputWidget.prototype.onChange = function () {
        this.updateSearchIndicator();
-       this.setValidityFlag();
        this.adjustSize();
 };
 
+/**
+ * Handle debounced change events.
+ *
+ * @param {string} value
+ * @private
+ */
+OO.ui.TextInputWidget.prototype.onDebouncedChange = function () {
+       this.setValidityFlag();
+};
+
 /**
  * Handle disable events.
  *
@@ -9689,12 +9813,12 @@ OO.ui.FieldLayout = function OoUiFieldLayout( fieldWidget, config ) {
        // Initialization
        this.$element
                .addClass( 'oo-ui-fieldLayout' )
+               .toggleClass( 'oo-ui-fieldLayout-disabled', this.fieldWidget.isDisabled() )
                .append( this.$help, this.$body );
        this.$body.addClass( 'oo-ui-fieldLayout-body' );
        this.$messages.addClass( 'oo-ui-fieldLayout-messages' );
        this.$field
                .addClass( 'oo-ui-fieldLayout-field' )
-               .toggleClass( 'oo-ui-fieldLayout-disable', this.fieldWidget.isDisabled() )
                .append( this.fieldWidget.$element );
 
        this.setErrors( config.errors || [] );
@@ -9976,7 +10100,7 @@ OO.ui.FieldsetLayout = function OoUiFieldsetLayout( config ) {
 
        // Mixin constructors
        OO.ui.mixin.IconElement.call( this, config );
-       OO.ui.mixin.LabelElement.call( this, config );
+       OO.ui.mixin.LabelElement.call( this, $.extend( {}, config, { $label: $( '<legend>' ) } ) );
        OO.ui.mixin.GroupElement.call( this, config );
 
        if ( config.help ) {
@@ -9997,9 +10121,10 @@ OO.ui.FieldsetLayout = function OoUiFieldsetLayout( config ) {
        }
 
        // Initialization
+       this.$group.addClass( 'oo-ui-fieldsetLayout-group' );
        this.$element
                .addClass( 'oo-ui-fieldsetLayout' )
-               .prepend( this.$help, this.$icon, this.$label, this.$group );
+               .prepend( this.$label, this.$help, this.$icon, this.$group );
        if ( Array.isArray( config.items ) ) {
                this.addItems( config.items );
        }
@@ -10012,6 +10137,10 @@ OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.mixin.IconElement );
 OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.mixin.LabelElement );
 OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.mixin.GroupElement );
 
+/* Static Properties */
+
+OO.ui.FieldsetLayout.static.tagName = 'fieldset';
+
 /**
  * FormLayouts are used to wrap {@link OO.ui.FieldsetLayout FieldsetLayouts} when you intend to use browser-based
  * form submission for the fields instead of handling them in JavaScript. Form layouts can be configured with an