X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=resources%2Flib%2Foojs-ui%2Foojs-ui.js;h=fbffe09a77ec2df478d61861a37561f4b5931167;hb=5d9459c7000c28f7755f41a4652747a9fec6b68e;hp=aeff69e0fad2aea76380d9896c004a6b9812c080;hpb=e36b72b84352b1718a311dc77df6fb0c97b198d1;p=lhc%2Fweb%2Fwiklou.git diff --git a/resources/lib/oojs-ui/oojs-ui.js b/resources/lib/oojs-ui/oojs-ui.js index aeff69e0fa..fbffe09a77 100644 --- a/resources/lib/oojs-ui/oojs-ui.js +++ b/resources/lib/oojs-ui/oojs-ui.js @@ -1,12 +1,12 @@ /*! - * OOjs UI v0.12.12 + * OOjs UI v0.13.0 * https://www.mediawiki.org/wiki/OOjs_UI * * Copyright 2011–2015 OOjs UI Team and other contributors. * Released under the MIT license * http://oojs.mit-license.org * - * Date: 2015-10-13T20:38:18Z + * Date: 2015-10-27T17:52:51Z */ ( function ( OO ) { @@ -1289,10 +1289,10 @@ 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, data ); // jscs:disable requireCapitalizedConstructors obj = new cls( data ); // rebuild widget - // pick up dynamic state, like focus, value of form inputs, scroll position, etc. - state = obj.gatherPreInfuseState( $elem ); // now replace old DOM with this new DOM. if ( top ) { $elem.replaceWith( obj.$element ); @@ -1310,6 +1310,24 @@ OO.ui.Element.static.unsafeInfuse = function ( idOrNode, domPromise ) { return obj; }; +/** + * Gather the dynamic state (focus, value of form inputs, scroll position, etc.) of a HTML DOM node + * (and its children) that represent an Element of the same class and the given configuration, + * generated by the PHP implementation. + * + * This method is called just before `node` is detached from the DOM. The return value of this + * function will be passed to #restorePreInfuseState after the newly created widget's #$element + * is inserted into DOM to replace `node`. + * + * @protected + * @param {HTMLElement} node + * @param {Object} config + * @return {Object} + */ +OO.ui.Element.static.gatherPreInfuseState = function () { + return {}; +}; + /** * Get a jQuery function within a specific document. * @@ -1888,23 +1906,6 @@ OO.ui.Element.prototype.scrollElementIntoView = function ( config ) { return OO.ui.Element.static.scrollIntoView( this.$element[ 0 ], config ); }; -/** - * Gather the dynamic state (focus, value of form inputs, scroll position, etc.) of a HTML DOM node - * (and its children) that represent an Element of the same type and configuration as the current - * one, generated by the PHP implementation. - * - * This method is called just before `node` is detached from the DOM. The return value of this - * function will be passed to #restorePreInfuseState after this widget's #$element is inserted into - * DOM to replace `node`. - * - * @protected - * @param {HTMLElement} node - * @return {Object} - */ -OO.ui.Element.prototype.gatherPreInfuseState = function () { - return {}; -}; - /** * Restore the pre-infusion dynamic state for this widget. * @@ -9730,6 +9731,8 @@ OO.ui.BookletLayout = function OoUiBookletLayout( config ) { this.stackLayout.connect( this, { set: 'onStackLayoutSet' } ); if ( this.outlined ) { this.outlineSelectWidget.connect( this, { select: 'onOutlineSelectWidgetSelect' } ); + this.scrolling = false; + this.stackLayout.connect( this, { visibleItemChange: 'onStackLayoutVisibleItemChange' } ); } if ( this.autoFocus ) { // Event 'focus' does not bubble, but 'focusin' does @@ -9801,6 +9804,22 @@ OO.ui.BookletLayout.prototype.onStackLayoutFocus = function ( e ) { } }; +/** + * Handle visibleItemChange events from the stackLayout + * + * The next visible page is set as the current page by selecting it + * in the outline + * + * @param {OO.ui.PageLayout} page The next visible page in the layout + */ +OO.ui.BookletLayout.prototype.onStackLayoutVisibleItemChange = function ( page ) { + // Set a flag to so that the resulting call to #onStackLayoutSet doesn't + // try and scroll the item into view again. + this.scrolling = true; + this.outlineSelectWidget.selectItemByData( page.getName() ); + this.scrolling = false; +}; + /** * Handle stack layout set events. * @@ -9809,7 +9828,7 @@ OO.ui.BookletLayout.prototype.onStackLayoutFocus = function ( e ) { */ OO.ui.BookletLayout.prototype.onStackLayoutSet = function ( page ) { var layout = this; - if ( page ) { + if ( !this.scrolling && page ) { page.scrollElementIntoView( { complete: function () { if ( layout.autoFocus ) { layout.focus(); @@ -11020,6 +11039,7 @@ OO.ui.StackLayout = function OoUiStackLayout( config ) { this.$element.addClass( 'oo-ui-stackLayout' ); if ( this.continuous ) { this.$element.addClass( 'oo-ui-stackLayout-continuous' ); + this.$element.on( 'scroll', OO.ui.debounce( this.onScroll.bind( this ), 250 ) ); } if ( Array.isArray( config.items ) ) { this.addItems( config.items ); @@ -11041,8 +11061,66 @@ OO.mixinClass( OO.ui.StackLayout, OO.ui.mixin.GroupElement ); * @param {OO.ui.Layout|null} item Current panel or `null` if no panel is shown */ +/** + * When used in continuous mode, this event is emitted when the user scrolls down + * far enough such that currentItem is no longer visible. + * + * @event visibleItemChange + * @param {OO.ui.PanelLayout} panel The next visible item in the layout + */ + /* Methods */ +/** + * Handle scroll events from the layout element + * + * @param {jQuery.Event} e + * @fires visibleItemChange + */ +OO.ui.StackLayout.prototype.onScroll = function () { + var currentRect, + len = this.items.length, + currentIndex = this.items.indexOf( this.currentItem ), + newIndex = currentIndex, + containerRect = this.$element[ 0 ].getBoundingClientRect(); + + if ( !containerRect || ( !containerRect.top && !containerRect.bottom ) ) { + // Can't get bounding rect, possibly not attached. + return; + } + + function getRect( item ) { + return item.$element[ 0 ].getBoundingClientRect(); + } + + function isVisible( item ) { + var rect = getRect( item ); + return rect.bottom > containerRect.top && rect.top < containerRect.bottom; + } + + currentRect = getRect( this.currentItem ); + + if ( currentRect.bottom < containerRect.top ) { + // Scrolled down past current item + while ( ++newIndex < len ) { + if ( isVisible( this.items[ newIndex ] ) ) { + break; + } + } + } else if ( currentRect.top > containerRect.bottom ) { + // Scrolled up past current item + while ( --newIndex >= 0 ) { + if ( isVisible( this.items[ newIndex ] ) ) { + break; + } + } + } + + if ( newIndex !== currentIndex ) { + this.emit( 'visibleItemChange', this.items[ newIndex ] ); + } +}; + /** * Get the current panel. * @@ -14540,6 +14618,21 @@ OO.mixinClass( OO.ui.InputWidget, OO.ui.mixin.AccessKeyedElement ); OO.ui.InputWidget.static.supportsSimpleLabel = true; +/* Static Methods */ + +/** + * @inheritdoc + */ +OO.ui.InputWidget.static.gatherPreInfuseState = function ( node, config ) { + var + state = OO.ui.InputWidget.parent.static.gatherPreInfuseState( node, config ), + $input = state.$input || $( node ).find( '.oo-ui-inputWidget-input' ); + state.value = $input.val(); + // Might be better in TabIndexedElement, but it's awkward to do there because mixins are awkward + state.focus = $input.is( ':focus' ); + return state; +}; + /* Events */ /** @@ -14718,19 +14811,6 @@ OO.ui.InputWidget.prototype.blur = function () { return this; }; -/** - * @inheritdoc - */ -OO.ui.InputWidget.prototype.gatherPreInfuseState = function ( node ) { - var - state = OO.ui.InputWidget.parent.prototype.gatherPreInfuseState.call( this, node ), - $input = state.$input || $( node ).find( '.oo-ui-inputWidget-input' ); - state.value = $input.val(); - // Might be better in TabIndexedElement, but it's awkward to do there because mixins are awkward - state.focus = $input.is( ':focus' ); - return state; -}; - /** * @inheritdoc */ @@ -14936,6 +15016,20 @@ OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) { OO.inheritClass( OO.ui.CheckboxInputWidget, OO.ui.InputWidget ); +/* Static Methods */ + +/** + * @inheritdoc + */ +OO.ui.CheckboxInputWidget.static.gatherPreInfuseState = function ( node, config ) { + var + state = OO.ui.CheckboxInputWidget.parent.static.gatherPreInfuseState( node, config ), + $input = $( node ).find( '.oo-ui-inputWidget-input' ); + state.$input = $input; // shortcut for performance, used in InputWidget + state.checked = $input.prop( 'checked' ); + return state; +}; + /* Methods */ /** @@ -14990,18 +15084,6 @@ OO.ui.CheckboxInputWidget.prototype.isSelected = function () { return this.selected; }; -/** - * @inheritdoc - */ -OO.ui.CheckboxInputWidget.prototype.gatherPreInfuseState = function ( node ) { - var - state = OO.ui.CheckboxInputWidget.parent.prototype.gatherPreInfuseState.call( this, node ), - $input = $( node ).find( '.oo-ui-inputWidget-input' ); - state.$input = $input; // shortcut for performance, used in InputWidget - state.checked = $input.prop( 'checked' ); - return state; -}; - /** * @inheritdoc */ @@ -15225,6 +15307,20 @@ OO.ui.RadioInputWidget = function OoUiRadioInputWidget( config ) { OO.inheritClass( OO.ui.RadioInputWidget, OO.ui.InputWidget ); +/* Static Methods */ + +/** + * @inheritdoc + */ +OO.ui.RadioInputWidget.static.gatherPreInfuseState = function ( node, config ) { + var + state = OO.ui.RadioInputWidget.parent.static.gatherPreInfuseState( node, config ), + $input = $( node ).find( '.oo-ui-inputWidget-input' ); + state.$input = $input; // shortcut for performance, used in InputWidget + state.checked = $input.prop( 'checked' ); + return state; +}; + /* Methods */ /** @@ -15263,18 +15359,6 @@ OO.ui.RadioInputWidget.prototype.isSelected = function () { return this.$input.prop( 'checked' ); }; -/** - * @inheritdoc - */ -OO.ui.RadioInputWidget.prototype.gatherPreInfuseState = function ( node ) { - var - state = OO.ui.RadioInputWidget.parent.prototype.gatherPreInfuseState.call( this, node ), - $input = $( node ).find( '.oo-ui-inputWidget-input' ); - state.$input = $input; // shortcut for performance, used in InputWidget - state.checked = $input.prop( 'checked' ); - return state; -}; - /** * @inheritdoc */ @@ -15341,6 +15425,17 @@ OO.inheritClass( OO.ui.RadioSelectInputWidget, OO.ui.InputWidget ); OO.ui.RadioSelectInputWidget.static.supportsSimpleLabel = false; +/* Static Methods */ + +/** + * @inheritdoc + */ +OO.ui.RadioSelectInputWidget.static.gatherPreInfuseState = function ( node, config ) { + var state = OO.ui.RadioSelectInputWidget.parent.static.gatherPreInfuseState( node, config ); + state.value = $( node ).find( '.oo-ui-radioInputWidget .oo-ui-inputWidget-input:checked' ).val(); + return state; +}; + /* Methods */ /** @@ -15416,15 +15511,6 @@ OO.ui.RadioSelectInputWidget.prototype.setOptions = function ( options ) { return this; }; -/** - * @inheritdoc - */ -OO.ui.RadioSelectInputWidget.prototype.gatherPreInfuseState = function ( node ) { - var state = OO.ui.RadioSelectInputWidget.parent.prototype.gatherPreInfuseState.call( this, node ); - state.value = $( node ).find( '.oo-ui-radioInputWidget .oo-ui-inputWidget-input:checked' ).val(); - return state; -}; - /** * TextInputWidgets, like HTML text inputs, can be configured with options that customize the * size of the field as well as its presentation. In addition, these widgets can be configured @@ -15517,6 +15603,7 @@ OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) { this.minRows = config.rows !== undefined ? config.rows : ''; this.maxRows = config.maxRows || Math.max( 2 * ( this.minRows || 0 ), 10 ); this.validate = null; + this.styleHeight = null; // Clone for resizing if ( this.autosize ) { @@ -15603,6 +15690,22 @@ OO.ui.TextInputWidget.static.validationPatterns = { integer: /^\d+$/ }; +/* Static Methods */ + +/** + * @inheritdoc + */ +OO.ui.TextInputWidget.static.gatherPreInfuseState = function ( node, config ) { + var + state = OO.ui.TextInputWidget.parent.static.gatherPreInfuseState( node, config ), + $input = $( node ).find( '.oo-ui-inputWidget-input' ); + state.$input = $input; // shortcut for performance, used in InputWidget + if ( config.multiline ) { + state.scrollTop = $input.scrollTop(); + } + return state; +}; + /* Events */ /** @@ -15613,6 +15716,12 @@ OO.ui.TextInputWidget.static.validationPatterns = { * @event enter */ +/** + * A `resize` event is emitted when autosize is set and the widget resizes + * + * @event resize + */ + /* Methods */ /** @@ -15802,9 +15911,10 @@ OO.ui.TextInputWidget.prototype.installParentChangeDetector = function () { * This only affects #multiline inputs that are {@link #autosize autosized}. * * @chainable + * @fires resize */ OO.ui.TextInputWidget.prototype.adjustSize = function () { - var scrollHeight, innerHeight, outerHeight, maxInnerHeight, measurementError, idealHeight; + var scrollHeight, innerHeight, outerHeight, maxInnerHeight, measurementError, idealHeight, newHeight; if ( this.multiline && this.autosize && this.$input.val() !== this.valCache ) { this.$clone @@ -15839,11 +15949,12 @@ OO.ui.TextInputWidget.prototype.adjustSize = function () { this.$clone.addClass( 'oo-ui-element-hidden' ); // Only apply inline height when expansion beyond natural height is needed - if ( idealHeight > innerHeight ) { - // Use the difference between the inner and outer height as a buffer - this.$input.css( 'height', idealHeight + ( outerHeight - innerHeight ) ); - } else { - this.$input.css( 'height', '' ); + // Use the difference between the inner and outer height as a buffer + newHeight = idealHeight > innerHeight ? idealHeight + ( outerHeight - innerHeight ) : ''; + if ( newHeight !== this.styleHeight ) { + this.$input.css( 'height', newHeight ); + this.styleHeight = newHeight; + this.emit( 'resize' ); } } return this; @@ -15892,30 +16003,74 @@ OO.ui.TextInputWidget.prototype.isAutosizing = function () { }; /** - * Select the entire text of the input. + * Focus the input and select a specified range within the text. * + * @param {number} from Select from offset + * @param {number} [to] Select to offset, defaults to from * @chainable */ -OO.ui.TextInputWidget.prototype.select = function () { - this.$input.select(); - return this; -}; - -/** - * Focus the input and move the cursor to the end. - */ -OO.ui.TextInputWidget.prototype.moveCursorToEnd = function () { - var textRange, +OO.ui.TextInputWidget.prototype.selectRange = function ( from, to ) { + var textRange, isBackwards, start, end, element = this.$input[ 0 ]; + + to = to || from; + + isBackwards = to < from; + start = isBackwards ? to : from; + end = isBackwards ? from : to; + this.focus(); - if ( element.selectionStart !== undefined ) { - element.selectionStart = element.selectionEnd = element.value.length; + + if ( element.setSelectionRange ) { + element.setSelectionRange( start, end, isBackwards ? 'backward' : 'forward' ); } else if ( element.createTextRange ) { // IE 8 and below textRange = element.createTextRange(); - textRange.collapse( false ); + textRange.collapse( true ); + textRange.moveStart( 'character', start ); + textRange.moveEnd( 'character', end - start ); textRange.select(); } + return this; +}; + +/** + * Get the length of the text input value. + * + * This could differ from the length of #getValue if the + * value gets filtered + * + * @return {number} Input length + */ +OO.ui.TextInputWidget.prototype.getInputLength = function () { + return this.$input[ 0 ].value.length; +}; + +/** + * Focus the input and select the entire text. + * + * @chainable + */ +OO.ui.TextInputWidget.prototype.select = function () { + return this.selectRange( 0, this.getInputLength() ); +}; + +/** + * Focus the input and move the cursor to the start. + * + * @chainable + */ +OO.ui.TextInputWidget.prototype.moveCursorToStart = function () { + return this.selectRange( 0 ); +}; + +/** + * Focus the input and move the cursor to the end. + * + * @chainable + */ +OO.ui.TextInputWidget.prototype.moveCursorToEnd = function () { + return this.selectRange( this.getInputLength() ); }; /** @@ -16117,20 +16272,6 @@ OO.ui.TextInputWidget.prototype.positionLabel = function () { return this; }; -/** - * @inheritdoc - */ -OO.ui.TextInputWidget.prototype.gatherPreInfuseState = function ( node ) { - var - state = OO.ui.TextInputWidget.parent.prototype.gatherPreInfuseState.call( this, node ), - $input = $( node ).find( '.oo-ui-inputWidget-input' ); - state.$input = $input; // shortcut for performance, used in InputWidget - if ( this.multiline ) { - state.scrollTop = $input.scrollTop(); - } - return state; -}; - /** * @inheritdoc */ @@ -19612,104 +19753,4 @@ OO.ui.ToggleSwitchWidget.prototype.onKeyPress = function ( e ) { } }; -/*! - * Deprecated aliases for classes in the `OO.ui.mixin` namespace. - */ - -/** - * @inheritdoc OO.ui.mixin.ButtonElement - * @deprecated Use {@link OO.ui.mixin.ButtonElement} instead. - */ -OO.ui.ButtonElement = OO.ui.mixin.ButtonElement; - -/** - * @inheritdoc OO.ui.mixin.ClippableElement - * @deprecated Use {@link OO.ui.mixin.ClippableElement} instead. - */ -OO.ui.ClippableElement = OO.ui.mixin.ClippableElement; - -/** - * @inheritdoc OO.ui.mixin.DraggableElement - * @deprecated Use {@link OO.ui.mixin.DraggableElement} instead. - */ -OO.ui.DraggableElement = OO.ui.mixin.DraggableElement; - -/** - * @inheritdoc OO.ui.mixin.DraggableGroupElement - * @deprecated Use {@link OO.ui.mixin.DraggableGroupElement} instead. - */ -OO.ui.DraggableGroupElement = OO.ui.mixin.DraggableGroupElement; - -/** - * @inheritdoc OO.ui.mixin.FlaggedElement - * @deprecated Use {@link OO.ui.mixin.FlaggedElement} instead. - */ -OO.ui.FlaggedElement = OO.ui.mixin.FlaggedElement; - -/** - * @inheritdoc OO.ui.mixin.GroupElement - * @deprecated Use {@link OO.ui.mixin.GroupElement} instead. - */ -OO.ui.GroupElement = OO.ui.mixin.GroupElement; - -/** - * @inheritdoc OO.ui.mixin.GroupWidget - * @deprecated Use {@link OO.ui.mixin.GroupWidget} instead. - */ -OO.ui.GroupWidget = OO.ui.mixin.GroupWidget; - -/** - * @inheritdoc OO.ui.mixin.IconElement - * @deprecated Use {@link OO.ui.mixin.IconElement} instead. - */ -OO.ui.IconElement = OO.ui.mixin.IconElement; - -/** - * @inheritdoc OO.ui.mixin.IndicatorElement - * @deprecated Use {@link OO.ui.mixin.IndicatorElement} instead. - */ -OO.ui.IndicatorElement = OO.ui.mixin.IndicatorElement; - -/** - * @inheritdoc OO.ui.mixin.ItemWidget - * @deprecated Use {@link OO.ui.mixin.ItemWidget} instead. - */ -OO.ui.ItemWidget = OO.ui.mixin.ItemWidget; - -/** - * @inheritdoc OO.ui.mixin.LabelElement - * @deprecated Use {@link OO.ui.mixin.LabelElement} instead. - */ -OO.ui.LabelElement = OO.ui.mixin.LabelElement; - -/** - * @inheritdoc OO.ui.mixin.LookupElement - * @deprecated Use {@link OO.ui.mixin.LookupElement} instead. - */ -OO.ui.LookupElement = OO.ui.mixin.LookupElement; - -/** - * @inheritdoc OO.ui.mixin.PendingElement - * @deprecated Use {@link OO.ui.mixin.PendingElement} instead. - */ -OO.ui.PendingElement = OO.ui.mixin.PendingElement; - -/** - * @inheritdoc OO.ui.mixin.PopupElement - * @deprecated Use {@link OO.ui.mixin.PopupElement} instead. - */ -OO.ui.PopupElement = OO.ui.mixin.PopupElement; - -/** - * @inheritdoc OO.ui.mixin.TabIndexedElement - * @deprecated Use {@link OO.ui.mixin.TabIndexedElement} instead. - */ -OO.ui.TabIndexedElement = OO.ui.mixin.TabIndexedElement; - -/** - * @inheritdoc OO.ui.mixin.TitledElement - * @deprecated Use {@link OO.ui.mixin.TitledElement} instead. - */ -OO.ui.TitledElement = OO.ui.mixin.TitledElement; - }( OO ) );