/*!
- * OOUI v0.29.1
+ * OOUI v0.29.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-10-04T00:42:40Z
+ * Date: 2018-12-05T00:15:55Z
*/
( function ( OO ) {
*
* @private
* @param {OO.ui.mixin.DraggableElement} item Dropped item
+ * @return {OO.ui.Element} The element, for chaining
*/
OO.ui.mixin.DraggableGroupElement.prototype.onItemDropOrDragEnd = function () {
var targetIndex, originalIndex,
*
* @private
* @chainable
+ * @return {OO.ui.Element} The element, for chaining
*/
OO.ui.mixin.LookupElement.prototype.openLookupMenu = function () {
if ( !this.lookupMenu.isEmpty() ) {
*
* @private
* @chainable
+ * @return {OO.ui.Element} The element, for chaining
*/
OO.ui.mixin.LookupElement.prototype.closeLookupMenu = function () {
this.lookupMenu.toggle( false );
*
* @private
* @chainable
+ * @return {OO.ui.Element} The element, for chaining
*/
OO.ui.mixin.LookupElement.prototype.populateLookupMenu = function () {
var widget = this,
*
* @param {boolean} readOnly Make input read-only
* @chainable
+ * @return {OO.ui.Element} The element, for chaining
*/
OO.ui.mixin.LookupElement.prototype.setReadOnly = function ( readOnly ) {
// Parent method
*
* @param {OO.ui.TabOptionWidget|null} tabItem Tab option widget, null to clear
* @chainable
+ * @return {OO.ui.TabPanelLayout} The layout, for chaining
*/
OO.ui.TabPanelLayout.prototype.setTabItem = function ( tabItem ) {
this.tabItem = tabItem || null;
*
* @param {OO.ui.TabOptionWidget} tabItem Tab option widget to set up
* @chainable
+ * @return {OO.ui.TabPanelLayout} The layout, for chaining
*/
OO.ui.TabPanelLayout.prototype.setupTabItem = function () {
this.$element.attr( 'aria-labelledby', this.tabItem.getElementId() );
*
* @param {OO.ui.OutlineOptionWidget|null} outlineItem Outline option widget, null to clear
* @chainable
+ * @return {OO.ui.PageLayout} The layout, for chaining
*/
OO.ui.PageLayout.prototype.setOutlineItem = function ( outlineItem ) {
this.outlineItem = outlineItem || null;
*
* @param {OO.ui.OutlineOptionWidget} outlineItem Outline option widget to set up
* @chainable
+ * @return {OO.ui.PageLayout} The layout, for chaining
*/
OO.ui.PageLayout.prototype.setupOutlineItem = function () {
return this;
* by setting the #continuous option to 'true'.
*
* @example
- * // A stack layout with two panels, configured to be displayed continously
+ * // A stack layout with two panels, configured to be displayed continuously
* var myStack = new OO.ui.StackLayout( {
* items: [
* new OO.ui.PanelLayout( {
* @param {OO.ui.Layout[]} items Panels to add
* @param {number} [index] Index of the insertion point
* @chainable
+ * @return {OO.ui.StackLayout} The layout, for chaining
*/
OO.ui.StackLayout.prototype.addItems = function ( items, index ) {
// Update the visibility
*
* @param {OO.ui.Layout[]} items Panels to remove
* @chainable
+ * @return {OO.ui.StackLayout} The layout, for chaining
* @fires set
*/
OO.ui.StackLayout.prototype.removeItems = function ( items ) {
* a subset of panels, use the #removeItems method.
*
* @chainable
+ * @return {OO.ui.StackLayout} The layout, for chaining
* @fires set
*/
OO.ui.StackLayout.prototype.clearItems = function () {
*
* @param {OO.ui.Layout} item Panel to show
* @chainable
+ * @return {OO.ui.StackLayout} The layout, for chaining
* @fires set
*/
OO.ui.StackLayout.prototype.setItem = function ( item ) {
return this;
};
+/**
+ * Reset the scroll offset of all panels, or the container if continuous
+ *
+ * @inheritdoc
+ */
+OO.ui.StackLayout.prototype.resetScroll = function () {
+ if ( this.continuous ) {
+ // Parent method
+ return OO.ui.StackLayout.parent.prototype.resetScroll.call( this );
+ }
+ // Reset each panel
+ this.getItems().forEach( function ( panel ) {
+ var hidden = panel.$element.hasClass( 'oo-ui-element-hidden' );
+ // Scroll can only be reset when panel is visible
+ panel.$element.removeClass( 'oo-ui-element-hidden' );
+ panel.resetScroll();
+ if ( hidden ) {
+ panel.$element.addClass( 'oo-ui-element-hidden' );
+ }
+ } );
+
+ return this;
+};
+
/**
* Update the visibility of all items in case of non-continuous view.
*
* and its size is customized with the #menuSize config. The content area will fill all remaining space.
*
* @example
- * var menuLayout = new OO.ui.MenuLayout( {
- * position: 'top'
- * } ),
+ * var menuLayout,
* menuPanel = new OO.ui.PanelLayout( { padded: true, expanded: true, scrollable: true } ),
* contentPanel = new OO.ui.PanelLayout( { padded: true, expanded: true, scrollable: true } ),
* select = new OO.ui.SelectWidget( {
* items: [
* new OO.ui.OptionWidget( {
* data: 'before',
- * label: 'Before',
+ * label: 'Before'
* } ),
* new OO.ui.OptionWidget( {
* data: 'after',
- * label: 'After',
+ * label: 'After'
* } ),
* new OO.ui.OptionWidget( {
* data: 'top',
- * label: 'Top',
+ * label: 'Top'
* } ),
* new OO.ui.OptionWidget( {
* data: 'bottom',
- * label: 'Bottom',
+ * label: 'Bottom'
* } )
* ]
* } ).on( 'select', function ( item ) {
* menuLayout.setMenuPosition( item.getData() );
* } );
*
+ * menuLayout = new OO.ui.MenuLayout( {
+ * position: 'top',
+ * menuPanel: menuPanel,
+ * contentPanel: contentPanel
+ * } )
* menuLayout.$menu.append(
* menuPanel.$element.append( '<b>Menu panel</b>', select.$element )
* );
* may be omitted.
*
* .oo-ui-menuLayout-menu {
- * height: 200px;
* width: 200px;
+ * height: 200px;
* }
+ *
* .oo-ui-menuLayout-content {
* top: 200px;
* left: 200px;
*
* @constructor
* @param {Object} [config] Configuration options
+ * @cfg {OO.ui.PanelLayout} [menuPanel] Menu panel
+ * @cfg {OO.ui.PanelLayout} [contentPanel] Content panel
* @cfg {boolean} [expanded=true] Expand the layout to fill the entire parent element.
* @cfg {boolean} [showMenu=true] Show menu
* @cfg {string} [menuPosition='before'] Position of menu: `top`, `after`, `bottom` or `before`
// Parent constructor
OO.ui.MenuLayout.parent.call( this, config );
+ this.menuPanel = null;
+ this.contentPanel = null;
this.expanded = !!config.expanded;
/**
* Menu DOM node
} else {
this.$element.addClass( 'oo-ui-menuLayout-static' );
}
+ if ( config.menuPanel ) {
+ this.setMenuPanel( config.menuPanel );
+ }
+ if ( config.contentPanel ) {
+ this.setContentPanel( config.contentPanel );
+ }
this.setMenuPosition( config.menuPosition );
this.toggleMenu( config.showMenu );
};
*
* @param {boolean} showMenu Show menu, omit to toggle
* @chainable
+ * @return {OO.ui.MenuLayout} The layout, for chaining
*/
OO.ui.MenuLayout.prototype.toggleMenu = function ( showMenu ) {
showMenu = showMenu === undefined ? !this.showMenu : !!showMenu;
* @param {string} position Position of menu, either `top`, `after`, `bottom` or `before`
* @throws {Error} If position value is not supported
* @chainable
+ * @return {OO.ui.MenuLayout} The layout, for chaining
*/
OO.ui.MenuLayout.prototype.setMenuPosition = function ( position ) {
this.$element.removeClass( 'oo-ui-menuLayout-' + this.menuPosition );
return this.menuPosition;
};
+/**
+ * Set the menu panel.
+ *
+ * @param {OO.ui.PanelLayout} menuPanel Menu panel
+ */
+OO.ui.MenuLayout.prototype.setMenuPanel = function ( menuPanel ) {
+ this.menuPanel = menuPanel;
+ this.$menu.append( this.menuPanel.$element );
+};
+
+/**
+ * Set the content panel.
+ *
+ * @param {OO.ui.PanelLayout} contentPanel Content panel
+ */
+OO.ui.MenuLayout.prototype.setContentPanel = function ( contentPanel ) {
+ this.contentPanel = contentPanel;
+ this.$content.append( this.contentPanel.$element );
+};
+
+/**
+ * Clear the menu panel.
+ */
+OO.ui.MenuLayout.prototype.clearMenuPanel = function () {
+ this.menuPanel = null;
+ this.$menu.empty();
+};
+
+/**
+ * Clear the content panel.
+ */
+OO.ui.MenuLayout.prototype.clearContentPanel = function () {
+ this.contentPanel = null;
+ this.$content.empty();
+};
+
+/**
+ * Reset the scroll offset of all panels and the tab select widget
+ *
+ * @inheritdoc
+ */
+OO.ui.MenuLayout.prototype.resetScroll = function () {
+ if ( this.menuPanel ) {
+ this.menuPanel.resetScroll();
+ }
+ if ( this.contentPanel ) {
+ this.contentPanel.resetScroll();
+ }
+
+ return this;
+};
+
/**
* BookletLayouts contain {@link OO.ui.PageLayout page layouts} as well as
* an {@link OO.ui.OutlineSelectWidget outline} that allows users to easily navigate
* outlined: true
* } );
*
- * booklet.addPages ( [ page1, page2 ] );
+ * booklet.addPages( [ page1, page2 ] );
* $( 'body' ).append( booklet.$element );
*
* @class
continuous: !!config.continuous,
expanded: this.expanded
} );
- this.$content.append( this.stackLayout.$element );
+ this.setContentPanel( this.stackLayout );
this.autoFocus = config.autoFocus === undefined || !!config.autoFocus;
this.outlineVisible = false;
this.outlined = !!config.outlined;
expanded: this.expanded,
scrollable: true
} );
- this.$menu.append( this.outlinePanel.$element );
+ this.setMenuPanel( this.outlinePanel );
this.outlineVisible = true;
if ( this.editable ) {
this.outlineControlsWidget = new OO.ui.OutlineControlsWidget(
*
* @param {boolean} [show] Show outline, omit to invert current state
* @chainable
+ * @return {OO.ui.BookletLayout} The layout, for chaining
*/
OO.ui.BookletLayout.prototype.toggleOutline = function ( show ) {
var booklet = this;
// outline controls are present, delay matches transition on `.oo-ui-menuLayout-menu`.
setTimeout( function () {
OO.ui.Element.static.reconsiderScrollbars( booklet.outlinePanel.$element[ 0 ] );
- }, 200 );
+ }, OO.ui.theme.getDialogTransitionDuration() );
}
}
* @param {number} index Index of the insertion point
* @fires add
* @chainable
+ * @return {OO.ui.BookletLayout} The layout, for chaining
*/
OO.ui.BookletLayout.prototype.addPages = function ( pages, index ) {
var i, len, name, page, item, currentIndex,
* @param {OO.ui.PageLayout[]} pages An array of pages to remove
* @fires remove
* @chainable
+ * @return {OO.ui.BookletLayout} The layout, for chaining
*/
OO.ui.BookletLayout.prototype.removePages = function ( pages ) {
var i, len, name, page,
*
* @fires remove
* @chainable
+ * @return {OO.ui.BookletLayout} The layout, for chaining
*/
OO.ui.BookletLayout.prototype.clearPages = function () {
var i, len,
}
};
+/**
+ * For outlined-continuous booklets, also reset the outlineSelectWidget to the first item.
+ *
+ * @inheritdoc
+ */
+OO.ui.BookletLayout.prototype.resetScroll = function () {
+ // Parent method
+ OO.ui.BookletLayout.parent.prototype.resetScroll.call( this );
+
+ if ( this.outlined && this.stackLayout.continuous && this.outlineSelectWidget.findFirstSelectableItem() ) {
+ this.scrolling = true;
+ this.outlineSelectWidget.selectItem( this.outlineSelectWidget.findFirstSelectableItem() );
+ this.scrolling = false;
+ }
+ return this;
+};
+
/**
* Select the first selectable page.
*
* @chainable
+ * @return {OO.ui.BookletLayout} The layout, for chaining
*/
OO.ui.BookletLayout.prototype.selectFirstSelectablePage = function () {
if ( !this.outlineSelectWidget.findSelectedItem() ) {
*
* var index = new OO.ui.IndexLayout();
*
- * index.addTabPanels ( [ tabPanel1, tabPanel2 ] );
+ * index.addTabPanels( [ tabPanel1, tabPanel2 ] );
* $( 'body' ).append( index.$element );
*
* @class
continuous: !!config.continuous,
expanded: this.expanded
} );
- this.$content.append( this.stackLayout.$element );
+ this.setContentPanel( this.stackLayout );
this.autoFocus = config.autoFocus === undefined || !!config.autoFocus;
this.tabSelectWidget = new OO.ui.TabSelectWidget();
this.tabPanel = new OO.ui.PanelLayout( {
expanded: this.expanded
} );
- this.$menu.append( this.tabPanel.$element );
+ this.setMenuPanel( this.tabPanel );
this.toggleMenu( true );
* @param {number} index Index of the insertion point
* @fires add
* @chainable
+ * @return {OO.ui.BookletLayout} The layout, for chaining
*/
OO.ui.IndexLayout.prototype.addTabPanels = function ( tabPanels, index ) {
var i, len, name, tabPanel, item, currentIndex,
* @param {OO.ui.TabPanelLayout[]} tabPanels An array of tab panels to remove
* @fires remove
* @chainable
+ * @return {OO.ui.BookletLayout} The layout, for chaining
*/
OO.ui.IndexLayout.prototype.removeTabPanels = function ( tabPanels ) {
var i, len, name, tabPanel,
*
* @fires remove
* @chainable
+ * @return {OO.ui.BookletLayout} The layout, for chaining
*/
OO.ui.IndexLayout.prototype.clearTabPanels = function () {
var i, len,
OO.ui.IndexLayout.prototype.setTabPanel = function ( name ) {
var selectedItem,
$focused,
- tabPanel = this.tabPanels[ name ],
- previousTabPanel = this.currentTabPanelName && this.tabPanels[ this.currentTabPanelName ];
+ previousTabPanel,
+ tabPanel = this.tabPanels[ name ];
if ( name !== this.currentTabPanelName ) {
+ previousTabPanel = this.getCurrentTabPanel();
selectedItem = this.tabSelectWidget.findSelectedItem();
if ( selectedItem && selectedItem.getData() !== name ) {
this.tabSelectWidget.selectItemByData( name );
* Select the first selectable tab panel.
*
* @chainable
+ * @return {OO.ui.BookletLayout} The layout, for chaining
*/
OO.ui.IndexLayout.prototype.selectFirstSelectableTabPanel = function () {
if ( !this.tabSelectWidget.findSelectedItem() ) {
* @param {boolean} value The state of the toggle
* @fires change
* @chainable
+ * @return {OO.ui.Widget} The widget, for chaining
*/
OO.ui.ToggleWidget.prototype.setValue = function ( value ) {
value = !!value;
*
* @private
* @param {jQuery.Event} e Mouse click event
+ * @return {undefined/boolean} False to prevent default if event is handled
*/
OO.ui.ToggleSwitchWidget.prototype.onClick = function ( e ) {
if ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {
*
* @private
* @param {jQuery.Event} e Key press event
+ * @return {undefined/boolean} False to prevent default if event is handled
*/
OO.ui.ToggleSwitchWidget.prototype.onKeyPress = function ( e ) {
if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
*
* @param {boolean} movable Item is movable
* @chainable
+ * @return {OO.ui.Widget} The widget, for chaining
*/
OO.ui.OutlineOptionWidget.prototype.setMovable = function ( movable ) {
this.movable = !!movable;
*
* @param {boolean} removable Item is removable
* @chainable
+ * @return {OO.ui.Widget} The widget, for chaining
*/
OO.ui.OutlineOptionWidget.prototype.setRemovable = function ( removable ) {
this.removable = !!removable;
*
* @param {number} [level=0] Indentation level, in the range of [0,#maxLevel]
* @chainable
+ * @return {OO.ui.Widget} The widget, for chaining
*/
OO.ui.OutlineOptionWidget.prototype.setLevel = function ( level ) {
var levels = this.constructor.static.levels,
*
* @param {string} [state] Item is fixed
* @fires fixed
+ * @return {OO.ui.Widget} The widget, for chaining
*/
OO.ui.TagItemWidget.prototype.setFixed = function ( state ) {
state = state === undefined ? !this.fixed : !!state;
/**
* Check whether the item is fixed
+ * @return {boolean}
*/
OO.ui.TagItemWidget.prototype.isFixed = function () {
return this.fixed;
OO.ui.TagItemWidget.prototype.onKeyDown = function ( e ) {
var movement;
- if ( !this.isDisabled() && !this.isFixed() && e.keyCode === OO.ui.Keys.BACKSPACE || e.keyCode === OO.ui.Keys.DELETE ) {
+ if ( !this.isDisabled() && !this.isFixed() && ( e.keyCode === OO.ui.Keys.BACKSPACE || e.keyCode === OO.ui.Keys.DELETE ) ) {
this.remove();
return false;
} else if ( e.keyCode === OO.ui.Keys.ENTER ) {
* replace the input widget used in the TagMultiselectWidget. If not given,
* TagMultiselectWidget creates its own.
* @cfg {boolean} [inputPosition='inline'] Position of the input. Options are:
- * - inline: The input is invisible, but exists inside the tag list, so
- * the user types into the tag groups to add tags.
- * - outline: The input is underneath the tag area.
- * - none: No input supplied
+ * - inline: The input is invisible, but exists inside the tag list, so
+ * the user types into the tag groups to add tags.
+ * - outline: The input is underneath the tag area.
+ * - none: No input supplied
* @cfg {boolean} [allowEditTags=true] Allow editing of the tags by clicking them
* @cfg {boolean} [allowArbitrary=false] Allow data items to be added even if
* not present in the menu.
* invalid tags. These tags will display with an invalid state, and
* the widget as a whole will have an invalid state if any invalid tags
* are present.
+ * @cfg {number} [tagLimit] An optional limit on the number of selected options.
+ * If 'tagLimit' is set and is reached, the input is disabled, not allowing any
+ * additions. If 'tagLimit' is unset or is 0, an unlimited number of items can be
+ * added.
* @cfg {boolean} [allowReordering=true] Allow reordering of the items
* @cfg {Object[]|String[]} [selected] A set of selected tags. If given,
* these will appear in the tag list on initialization, as long as they
this.allowedValues = config.allowedValues || [];
this.allowDisplayInvalidTags = config.allowDisplayInvalidTags;
this.hasInput = this.inputPosition !== 'none';
+ this.tagLimit = config.tagLimit;
this.height = null;
this.valid = true;
};
this.input.$input.on( inputEvents );
+ this.inputPlaceholder = this.input.$input.attr( 'placeholder' );
if ( this.inputPosition === 'outline' ) {
// Override max-height for the input widget
// in the case the widget is outline so it can
- // stretch all the way if the widet is wide
+ // stretch all the way if the widget is wide
this.input.$element.css( 'max-width', 'inherit' );
this.$element
.addClass( 'oo-ui-tagMultiselectWidget-outlined' )
*/
OO.ui.TagMultiselectWidget.prototype.onInputFocus = function () {
this.$element.addClass( 'oo-ui-tagMultiselectWidget-focus' );
+ // Reset validity
+ this.toggleValid( true );
};
/**
*/
OO.ui.TagMultiselectWidget.prototype.onInputBlur = function () {
this.$element.removeClass( 'oo-ui-tagMultiselectWidget-focus' );
+
+ // Set the widget as invalid if there's text in the input
+ this.addTagFromInput();
+ this.toggleValid( this.checkValidity() && ( !this.hasInput || !this.input.getValue() ) );
};
/**
* Respond to change event, where items were added, removed, or cleared.
*/
OO.ui.TagMultiselectWidget.prototype.onChangeTags = function () {
- this.toggleValid( this.checkValidity() );
+ var isUnderLimit = this.isUnderLimit();
+
+ // Reset validity
+ this.toggleValid(
+ this.checkValidity() &&
+ !( this.hasInput && this.input.getValue() )
+ );
+
if ( this.hasInput ) {
this.updateInputSize();
+ if ( !isUnderLimit ) {
+ // Clear the input
+ this.input.setValue( '' );
+ }
+ if ( this.inputPosition === 'outline' ) {
+ // Show/clear the placeholder and enable/disable the input
+ // based on whether we are/aren't under the specified limit
+ this.input.$input.attr( 'placeholder', isUnderLimit ? this.inputPlaceholder : '' );
+ this.input.setDisabled( !isUnderLimit );
+ } else {
+ // Show/hide the input
+ this.input.$input.toggleClass( 'oo-ui-element-hidden', !isUnderLimit );
+ }
}
this.updateIfHeightChanged();
};
OO.ui.TagMultiselectWidget.parent.prototype.setDisabled.call( this, isDisabled );
if ( this.hasInput && this.input ) {
- this.input.setDisabled( !!isDisabled );
+ this.input.setDisabled( !!isDisabled && !this.isUnderLimit() );
}
if ( this.items ) {
}
if ( isValid || this.allowDisplayInvalidTags ) {
- this.addTag( val );
this.clearInput();
- this.focus();
+ this.addTag( val );
}
};
* This object must contain at least a data key. Example:
* { data: 'foo', label: 'Foo item' }
* For multiple items, use an array of objects. For example:
- * [
- * { data: 'foo', label: 'Foo item' },
- * { data: 'bar', label: 'Bar item' }
- * ]
+ * [
+ * { data: 'foo', label: 'Foo item' },
+ * { data: 'bar', label: 'Bar item' }
+ * ]
* Value can also be added with plaintext array, for example:
* [ 'foo', 'bar', 'bla' ] or a single string, like 'foo'
*/
var newItemWidget,
isValid = this.isAllowedData( data );
- if ( isValid || this.allowDisplayInvalidTags ) {
+ if ( this.isUnderLimit() && ( isValid || this.allowDisplayInvalidTags ) ) {
newItemWidget = this.createTagItemWidget( data, label );
newItemWidget.toggleValid( isValid );
this.addItems( [ newItemWidget ] );
return true;
}
+
return false;
};
+/**
+ * Check whether the number of current tags is within the limit.
+ *
+ * @return {boolean} True if current tag count is within the limit or
+ * if 'tagLimit' is not set
+ */
+OO.ui.TagMultiselectWidget.prototype.isUnderLimit = function () {
+ return !this.tagLimit ||
+ this.getItemCount() < this.tagLimit;
+};
+
/**
* Remove tag by its data property.
*
// Some safety margin for sanity, because I *really* don't feel like finding out where the few
// pixels this is off by are coming from.
- bestWidth -= 10;
+ bestWidth -= 13;
if ( contentWidth > bestWidth ) {
// This will result in the input getting shifted to the next line
- bestWidth = this.$content.innerWidth() - 10;
+ bestWidth = this.$content.innerWidth() - 13;
}
this.input.$input.width( Math.floor( bestWidth ) );
this.updateIfHeightChanged();
this.menu.toggle( true );
};
+/**
+ * @inheritdoc
+ */
+OO.ui.MenuTagMultiselectWidget.prototype.onInputBlur = function () {
+ // Parent method
+ OO.ui.MenuTagMultiselectWidget.parent.prototype.onInputBlur.call( this );
+
+ this.menu.toggle( false );
+};
+
/**
* Respond to input change event
*/
*/
OO.ui.MenuTagMultiselectWidget.prototype.initializeMenuSelection = function () {
if ( !this.menu.findSelectedItem() ) {
- this.menu.highlightItem( this.menu.findFirstSelectableItem() );
+ this.menu.highlightItem(
+ this.allowArbitrary ?
+ null :
+ this.menu.findFirstSelectableItem()
+ );
}
};
* @inheritdoc
*/
OO.ui.MenuTagMultiselectWidget.prototype.addTagFromInput = function () {
- var inputValue = this.input.getValue(),
- validated = false,
- highlightedItem = this.menu.findHighlightedItem(),
- item = this.menu.findItemFromData( inputValue );
-
- if ( !inputValue ) {
- return;
- }
+ var val = this.input.getValue(),
+ // Look for a highlighted item first
+ // Then look for the element that fits the data
+ item = this.menu.findHighlightedItem() || this.menu.findItemFromData( val ),
+ data = item ? item.getData() : val,
+ isValid = this.isAllowedData( data );
// Override the parent method so we add from the menu
// rather than directly from the input
- // Look for a highlighted item first
- if ( highlightedItem ) {
- validated = this.addTag( highlightedItem.getData(), highlightedItem.getLabel() );
- } else if ( item ) {
- // Look for the element that fits the data
- validated = this.addTag( item.getData(), item.getLabel() );
- } else {
- // Otherwise, add the tag - the method will only add if the
- // tag is valid or if invalid tags are allowed
- validated = this.addTag( inputValue );
+ if ( !val ) {
+ return;
}
- if ( validated ) {
+ if ( isValid || this.allowDisplayInvalidTags ) {
this.clearInput();
- this.focus();
+ if ( item ) {
+ this.addTag( data, item.getLabel() );
+ } else {
+ this.addTag( val );
+ }
}
};
* Focusses the select file button.
*
* @chainable
+ * @return {OO.ui.Widget} The widget, for chaining
*/
OO.ui.SelectFileWidget.prototype.focus = function () {
this.selectButton.focus();
* Blur the widget.
*
* @chainable
+ * @return {OO.ui.Widget} The widget, for chaining
*/
OO.ui.SelectFileWidget.prototype.blur = function () {
this.selectButton.blur();
* Handle clear button click events.
*
* @private
+ * @return {undefined/boolean} False to prevent default if event is handled
*/
OO.ui.SelectFileWidget.prototype.onClearClick = function () {
this.setValue( null );
*
* @private
* @param {jQuery.Event} e Key press event
+ * @return {undefined/boolean} False to prevent default if event is handled
*/
OO.ui.SelectFileWidget.prototype.onKeyPress = function ( e ) {
if ( this.isSupported && !this.isDisabled() && this.$input &&
*
* @private
* @param {jQuery.Event} e Key press event
+ * @return {undefined/boolean} False to prevent default if event is handled
*/
OO.ui.SelectFileWidget.prototype.onDropTargetClick = function () {
if ( this.isSupported && !this.isDisabled() && this.$input ) {
*
* @private
* @param {jQuery.Event} e Drag event
+ * @return {undefined/boolean} False to prevent default if event is handled
*/
OO.ui.SelectFileWidget.prototype.onDragEnterOrOver = function ( e ) {
var itemOrFile,
*
* @private
* @param {jQuery.Event} e Drop event
+ * @return {undefined/boolean} False to prevent default if event is handled
*/
OO.ui.SelectFileWidget.prototype.onDrop = function ( e ) {
var file = null,