/*!
- * OOUI v0.26.1
+ * OOUI v0.26.5
* 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-03-23T23:42:32Z
+ * Date: 2018-04-24T23:29:01Z
*/
( function ( OO ) {
* in the toolbar, but are not configured as tools. By default, actions are displayed on the right side of
* the toolbar.
* @cfg {string} [position='top'] Whether the toolbar is positioned above ('top') or below ('bottom') content.
+ * @cfg {jQuery} [$overlay] An overlay for the popup.
+ * See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.
*/
OO.ui.Toolbar = function OoUiToolbar( toolFactory, toolGroupFactory, config ) {
// Allow passing positional parameters inside the config object
this.position = config.position || 'top';
this.$bar = $( '<div>' );
this.$actions = $( '<div>' );
+ this.$popups = $( '<div>' );
this.initialized = false;
this.narrowThreshold = null;
this.onWindowResizeHandler = this.onWindowResize.bind( this );
+ this.$overlay = ( config.$overlay === true ? OO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;
// Events
this.$element
if ( config.actions ) {
this.$bar.append( this.$actions.addClass( 'oo-ui-toolbar-actions' ) );
}
+ this.$popups.addClass( 'oo-ui-toolbar-popups' );
this.$bar
.addClass( 'oo-ui-toolbar-bar' )
.append( this.$group, '<div style="clear:both"></div>' );
// Possible classes: oo-ui-toolbar-position-top, oo-ui-toolbar-position-bottom
this.$element.addClass( 'oo-ui-toolbar oo-ui-toolbar-position-' + this.position ).append( this.$bar );
+ this.$overlay.append( this.$popups );
};
/* Setup */
* @param {jQuery.Event} e Window resize event
*/
OO.ui.Toolbar.prototype.onWindowResize = function () {
- this.$element.toggleClass(
+ this.$element.add( this.$popups ).toggleClass(
'oo-ui-toolbar-narrow',
this.$bar[ 0 ].clientWidth <= this.getNarrowThreshold()
);
this.$accel = $( '<span>' );
this.$link = $( '<a>' );
this.title = null;
+ this.checkIcon = new OO.ui.IconWidget( {
+ icon: 'check',
+ classes: [ 'oo-ui-tool-checkIcon' ]
+ } );
// Mixin constructors
OO.ui.mixin.IconElement.call( this, config );
} );
this.$link
.addClass( 'oo-ui-tool-link' )
- .append( this.$icon, this.$title, this.$accel )
+ .append( this.checkIcon.$element, this.$icon, this.$title, this.$accel )
.attr( 'role', 'button' );
this.$element
.data( 'oo-ui-tool', this )
this.onCapturedMouseKeyUpHandler = this.onCapturedMouseKeyUp.bind( this );
// Events
- this.$element.on( {
+ this.$group.on( {
mousedown: this.onMouseKeyDown.bind( this ),
mouseup: this.onMouseKeyUp.bind( this ),
keydown: this.onMouseKeyDown.bind( this ),
} );
this.toolbar.getToolFactory().connect( this, { register: 'onToolFactoryRegister' } );
this.aggregate( { disable: 'itemDisable' } );
- this.connect( this, { itemDisable: 'updateDisabled' } );
+ this.connect( this, {
+ itemDisable: 'updateDisabled',
+ disable: 'onDisable'
+ } );
// Initialization
this.$group.addClass( 'oo-ui-toolGroup-tools' );
this.$element
.addClass( 'oo-ui-toolGroup' )
.append( this.$group );
+ this.onDisable( this.isDisabled() );
this.populate();
};
OO.ui.ToolGroup.parent.prototype.updateDisabled.apply( this, arguments );
};
+/**
+ * Handle disable events.
+ *
+ * @protected
+ * @param {boolean} isDisabled
+ */
+OO.ui.ToolGroup.prototype.onDisable = function ( isDisabled ) {
+ this.$group.toggleClass( 'oo-ui-toolGroup-disabled-tools', isDisabled );
+ this.$group.toggleClass( 'oo-ui-toolGroup-enabled-tools', !isDisabled );
+};
+
/**
* Handle mouse down and key down events.
*
// Mixin constructors
OO.ui.mixin.PopupElement.call( this, config );
+ // Events
+ this.popup.connect( this, { toggle: 'onPopupToggle' } );
+
// Initialization
this.popup.setPosition( toolGroup.getToolbar().position === 'bottom' ? 'above' : 'below' );
- this.$element
- .addClass( 'oo-ui-popupTool' )
- .append( this.popup.$element );
+ this.$element.addClass( 'oo-ui-popupTool' );
+ this.popup.$element.addClass( 'oo-ui-popupTool-popup' );
+ this.toolbar.$popups.append( this.popup.$element );
};
/* Setup */
if ( !this.isDisabled() ) {
this.popup.toggle();
}
- this.setActive( false );
return false;
};
* @inheritdoc
*/
OO.ui.PopupTool.prototype.onUpdateState = function () {
- this.setActive( false );
+};
+
+/**
+ * Handle popup visibility being toggled.
+ *
+ * @param {boolean} isVisible
+ */
+OO.ui.PopupTool.prototype.onPopupToggle = function ( isVisible ) {
+ this.setActive( isVisible );
};
/**
// Initialization
this.$element.addClass( 'oo-ui-barToolGroup' );
+ this.$group.addClass( 'oo-ui-barToolGroup-tools' );
};
/* Setup */
* @mixins OO.ui.mixin.TitledElement
* @mixins OO.ui.mixin.FlaggedElement
* @mixins OO.ui.mixin.ClippableElement
+ * @mixins OO.ui.mixin.FloatableElement
* @mixins OO.ui.mixin.TabIndexedElement
*
* @constructor
OO.ui.mixin.TitledElement.call( this, config );
OO.ui.mixin.FlaggedElement.call( this, config );
OO.ui.mixin.ClippableElement.call( this, $.extend( {}, config, { $clippable: this.$group } ) );
+ OO.ui.mixin.FloatableElement.call( this, $.extend( {}, config, {
+ $floatable: this.$group,
+ $floatableContainer: this.$handle,
+ hideWhenOutOfView: false,
+ verticalPosition: this.toolbar.position === 'bottom' ? 'above' : 'below'
+ } ) );
OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$handle } ) );
// Events
this.$element
.addClass( 'oo-ui-popupToolGroup' )
.prepend( this.$handle );
+ this.$group.addClass( 'oo-ui-popupToolGroup-tools' );
+ this.toolbar.$popups.append( this.$group );
};
/* Setup */
OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.TitledElement );
OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.FlaggedElement );
OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.ClippableElement );
+OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.FloatableElement );
OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.TabIndexedElement );
/* Methods */
-/**
- * @inheritdoc OO.ui.mixin.ClippableElement
- */
-OO.ui.PopupToolGroup.prototype.getHorizontalAnchorEdge = function () {
- var out;
- if ( this.$element.hasClass( 'oo-ui-popupToolGroup-right' ) ) {
- out = 'right';
- } else {
- out = 'left';
- }
- // Flip for RTL
- if ( this.$element.css( 'direction' ) === 'rtl' ) {
- out = ( out === 'left' ) ? 'right' : 'left';
- }
- return out;
-};
-
-/**
- * @inheritdoc OO.ui.mixin.ClippableElement
- */
-OO.ui.PopupToolGroup.prototype.getVerticalAnchorEdge = function () {
- if ( this.toolbar.position === 'bottom' ) {
- return 'bottom';
- }
- return 'top';
-};
-
/**
* @inheritdoc
*/
* @param {MouseEvent|KeyboardEvent} e Mouse up or key up event
*/
OO.ui.PopupToolGroup.prototype.onBlur = function ( e ) {
+ var $target = $( e.target );
// Only deactivate when clicking outside the dropdown element
- if ( $( e.target ).closest( '.oo-ui-popupToolGroup' )[ 0 ] !== this.$element[ 0 ] ) {
- this.setActive( false );
+ if ( $target.closest( '.oo-ui-popupToolGroup' )[ 0 ] === this.$element[ 0 ] ) {
+ return;
+ }
+ if ( $target.closest( '.oo-ui-popupToolGroup-tools' )[ 0 ] === this.$group[ 0 ] ) {
+ return;
}
+ this.setActive( false );
};
/**
this.getElementDocument().addEventListener( 'keyup', this.onBlurHandler, true );
this.$clippable.css( 'left', '' );
- // Try anchoring the popup to the left first
- this.$element.addClass( 'oo-ui-popupToolGroup-active oo-ui-popupToolGroup-left' );
+ this.$element.addClass( 'oo-ui-popupToolGroup-active' );
+ this.$group.addClass( 'oo-ui-popupToolGroup-active-tools' );
+ this.togglePositioning( true );
this.toggleClipping( true );
- if ( this.isClippedHorizontally() ) {
+
+ // Try anchoring the popup to the left first
+ this.setHorizontalPosition( 'start' );
+
+ if ( this.isClippedHorizontally() || this.isFloatableOutOfView() ) {
// Anchoring to the left caused the popup to clip, so anchor it to the right instead
- this.toggleClipping( false );
- this.$element
- .removeClass( 'oo-ui-popupToolGroup-left' )
- .addClass( 'oo-ui-popupToolGroup-right' );
- this.toggleClipping( true );
+ this.setHorizontalPosition( 'end' );
}
- if ( this.isClippedHorizontally() ) {
+ if ( this.isClippedHorizontally() || this.isFloatableOutOfView() ) {
// Anchoring to the right also caused the popup to clip, so just make it fill the container
containerWidth = this.$clippableScrollableContainer.width();
containerLeft = this.$clippableScrollableContainer[ 0 ] === document.documentElement ?
this.$clippableScrollableContainer.offset().left;
this.toggleClipping( false );
- this.$element.removeClass( 'oo-ui-popupToolGroup-right' );
+ this.setHorizontalPosition( 'start' );
this.$clippable.css( {
left: -( this.$element.offset().left - containerLeft ),
} else {
this.getElementDocument().removeEventListener( 'mouseup', this.onBlurHandler, true );
this.getElementDocument().removeEventListener( 'keyup', this.onBlurHandler, true );
- this.$element.removeClass(
- 'oo-ui-popupToolGroup-active oo-ui-popupToolGroup-left oo-ui-popupToolGroup-right'
- );
+ this.$element.removeClass( 'oo-ui-popupToolGroup-active' );
+ this.$group.removeClass( 'oo-ui-popupToolGroup-active-tools' );
+ this.togglePositioning( false );
this.toggleClipping( false );
}
this.updateThemeClasses();
// Initialization
this.$element.addClass( 'oo-ui-listToolGroup' );
+ this.$group.addClass( 'oo-ui-listToolGroup-tools' );
};
/* Setup */
// Initialization
this.$element.addClass( 'oo-ui-menuToolGroup' );
+ this.$group.addClass( 'oo-ui-menuToolGroup-tools' );
};
/* Setup */