diff options
Diffstat (limited to 'vendor/oojs/oojs-ui/src/widgets/PopupWidget.js')
-rw-r--r-- | vendor/oojs/oojs-ui/src/widgets/PopupWidget.js | 395 |
1 files changed, 0 insertions, 395 deletions
diff --git a/vendor/oojs/oojs-ui/src/widgets/PopupWidget.js b/vendor/oojs/oojs-ui/src/widgets/PopupWidget.js deleted file mode 100644 index 0b1f4ca6..00000000 --- a/vendor/oojs/oojs-ui/src/widgets/PopupWidget.js +++ /dev/null @@ -1,395 +0,0 @@ -/** - * PopupWidget is a container for content. The popup is overlaid and positioned absolutely. - * By default, each popup has an anchor that points toward its origin. - * Please see the [OOjs UI documentation on Mediawiki] [1] for more information and examples. - * - * @example - * // A popup widget. - * var popup = new OO.ui.PopupWidget( { - * $content: $( '<p>Hi there!</p>' ), - * padded: true, - * width: 300 - * } ); - * - * $( 'body' ).append( popup.$element ); - * // To display the popup, toggle the visibility to 'true'. - * popup.toggle( true ); - * - * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Popups - * - * @class - * @extends OO.ui.Widget - * @mixins OO.ui.LabelElement - * - * @constructor - * @param {Object} [config] Configuration options - * @cfg {number} [width=320] Width of popup in pixels - * @cfg {number} [height] Height of popup in pixels. Omit to use the automatic height. - * @cfg {boolean} [anchor=true] Show anchor pointing to origin of popup - * @cfg {string} [align='center'] Alignment of the popup: `center`, `force-left`, `force-right`, `backwards` or `forwards`. - * If the popup is forced-left the popup body is leaning towards the left. For force-right alignment, the body of the - * popup is leaning towards the right of the screen. - * Using 'backwards' is a logical direction which will result in the popup leaning towards the beginning of the sentence - * in the given language, which means it will flip to the correct positioning in right-to-left languages. - * Using 'forward' will also result in a logical alignment where the body of the popup leans towards the end of the - * sentence in the given language. - * @cfg {jQuery} [$container] Constrain the popup to the boundaries of the specified container. - * See the [OOjs UI docs on MediaWiki][3] for an example. - * [3]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Popups#containerExample - * @cfg {number} [containerPadding=10] Padding between the popup and its container, specified as a number of pixels. - * @cfg {jQuery} [$content] Content to append to the popup's body - * @cfg {boolean} [autoClose=false] Automatically close the popup when it loses focus. - * @cfg {jQuery} [$autoCloseIgnore] Elements that will not close the popup when clicked. - * This config option is only relevant if #autoClose is set to `true`. See the [OOjs UI docs on MediaWiki][2] - * for an example. - * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Popups#autocloseExample - * @cfg {boolean} [head] Show a popup header that contains a #label (if specified) and close - * button. - * @cfg {boolean} [padded] Add padding to the popup's body - */ -OO.ui.PopupWidget = function OoUiPopupWidget( config ) { - // Configuration initialization - config = config || {}; - - // Parent constructor - OO.ui.PopupWidget.super.call( this, config ); - - // Properties (must be set before ClippableElement constructor call) - this.$body = $( '<div>' ); - - // Mixin constructors - OO.ui.LabelElement.call( this, config ); - OO.ui.ClippableElement.call( this, $.extend( {}, config, { $clippable: this.$body } ) ); - - // Properties - this.$popup = $( '<div>' ); - this.$head = $( '<div>' ); - this.$anchor = $( '<div>' ); - // If undefined, will be computed lazily in updateDimensions() - this.$container = config.$container; - this.containerPadding = config.containerPadding !== undefined ? config.containerPadding : 10; - this.autoClose = !!config.autoClose; - this.$autoCloseIgnore = config.$autoCloseIgnore; - this.transitionTimeout = null; - this.anchor = null; - this.width = config.width !== undefined ? config.width : 320; - this.height = config.height !== undefined ? config.height : null; - this.setAlignment( config.align ); - this.closeButton = new OO.ui.ButtonWidget( { framed: false, icon: 'close' } ); - this.onMouseDownHandler = this.onMouseDown.bind( this ); - this.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this ); - - // Events - this.closeButton.connect( this, { click: 'onCloseButtonClick' } ); - - // Initialization - this.toggleAnchor( config.anchor === undefined || config.anchor ); - this.$body.addClass( 'oo-ui-popupWidget-body' ); - this.$anchor.addClass( 'oo-ui-popupWidget-anchor' ); - this.$head - .addClass( 'oo-ui-popupWidget-head' ) - .append( this.$label, this.closeButton.$element ); - if ( !config.head ) { - this.$head.addClass( 'oo-ui-element-hidden' ); - } - this.$popup - .addClass( 'oo-ui-popupWidget-popup' ) - .append( this.$head, this.$body ); - this.$element - .addClass( 'oo-ui-popupWidget' ) - .append( this.$popup, this.$anchor ); - // Move content, which was added to #$element by OO.ui.Widget, to the body - if ( config.$content instanceof jQuery ) { - this.$body.append( config.$content ); - } - if ( config.padded ) { - this.$body.addClass( 'oo-ui-popupWidget-body-padded' ); - } - - // Initially hidden - using #toggle may cause errors if subclasses override toggle with methods - // that reference properties not initialized at that time of parent class construction - // TODO: Find a better way to handle post-constructor setup - this.visible = false; - this.$element.addClass( 'oo-ui-element-hidden' ); -}; - -/* Setup */ - -OO.inheritClass( OO.ui.PopupWidget, OO.ui.Widget ); -OO.mixinClass( OO.ui.PopupWidget, OO.ui.LabelElement ); -OO.mixinClass( OO.ui.PopupWidget, OO.ui.ClippableElement ); - -/* Methods */ - -/** - * Handles mouse down events. - * - * @private - * @param {MouseEvent} e Mouse down event - */ -OO.ui.PopupWidget.prototype.onMouseDown = function ( e ) { - if ( - this.isVisible() && - !$.contains( this.$element[ 0 ], e.target ) && - ( !this.$autoCloseIgnore || !this.$autoCloseIgnore.has( e.target ).length ) - ) { - this.toggle( false ); - } -}; - -/** - * Bind mouse down listener. - * - * @private - */ -OO.ui.PopupWidget.prototype.bindMouseDownListener = function () { - // Capture clicks outside popup - this.getElementWindow().addEventListener( 'mousedown', this.onMouseDownHandler, true ); -}; - -/** - * Handles close button click events. - * - * @private - */ -OO.ui.PopupWidget.prototype.onCloseButtonClick = function () { - if ( this.isVisible() ) { - this.toggle( false ); - } -}; - -/** - * Unbind mouse down listener. - * - * @private - */ -OO.ui.PopupWidget.prototype.unbindMouseDownListener = function () { - this.getElementWindow().removeEventListener( 'mousedown', this.onMouseDownHandler, true ); -}; - -/** - * Handles key down events. - * - * @private - * @param {KeyboardEvent} e Key down event - */ -OO.ui.PopupWidget.prototype.onDocumentKeyDown = function ( e ) { - if ( - e.which === OO.ui.Keys.ESCAPE && - this.isVisible() - ) { - this.toggle( false ); - e.preventDefault(); - e.stopPropagation(); - } -}; - -/** - * Bind key down listener. - * - * @private - */ -OO.ui.PopupWidget.prototype.bindKeyDownListener = function () { - this.getElementWindow().addEventListener( 'keydown', this.onDocumentKeyDownHandler, true ); -}; - -/** - * Unbind key down listener. - * - * @private - */ -OO.ui.PopupWidget.prototype.unbindKeyDownListener = function () { - this.getElementWindow().removeEventListener( 'keydown', this.onDocumentKeyDownHandler, true ); -}; - -/** - * Show, hide, or toggle the visibility of the anchor. - * - * @param {boolean} [show] Show anchor, omit to toggle - */ -OO.ui.PopupWidget.prototype.toggleAnchor = function ( show ) { - show = show === undefined ? !this.anchored : !!show; - - if ( this.anchored !== show ) { - if ( show ) { - this.$element.addClass( 'oo-ui-popupWidget-anchored' ); - } else { - this.$element.removeClass( 'oo-ui-popupWidget-anchored' ); - } - this.anchored = show; - } -}; - -/** - * Check if the anchor is visible. - * - * @return {boolean} Anchor is visible - */ -OO.ui.PopupWidget.prototype.hasAnchor = function () { - return this.anchor; -}; - -/** - * @inheritdoc - */ -OO.ui.PopupWidget.prototype.toggle = function ( show ) { - show = show === undefined ? !this.isVisible() : !!show; - - var change = show !== this.isVisible(); - - // Parent method - OO.ui.PopupWidget.super.prototype.toggle.call( this, show ); - - if ( change ) { - if ( show ) { - if ( this.autoClose ) { - this.bindMouseDownListener(); - this.bindKeyDownListener(); - } - this.updateDimensions(); - this.toggleClipping( true ); - } else { - this.toggleClipping( false ); - if ( this.autoClose ) { - this.unbindMouseDownListener(); - this.unbindKeyDownListener(); - } - } - } - - return this; -}; - -/** - * Set the size of the popup. - * - * Changing the size may also change the popup's position depending on the alignment. - * - * @param {number} width Width in pixels - * @param {number} height Height in pixels - * @param {boolean} [transition=false] Use a smooth transition - * @chainable - */ -OO.ui.PopupWidget.prototype.setSize = function ( width, height, transition ) { - this.width = width; - this.height = height !== undefined ? height : null; - if ( this.isVisible() ) { - this.updateDimensions( transition ); - } -}; - -/** - * Update the size and position. - * - * Only use this to keep the popup properly anchored. Use #setSize to change the size, and this will - * be called automatically. - * - * @param {boolean} [transition=false] Use a smooth transition - * @chainable - */ -OO.ui.PopupWidget.prototype.updateDimensions = function ( transition ) { - var popupOffset, originOffset, containerLeft, containerWidth, containerRight, - popupLeft, popupRight, overlapLeft, overlapRight, anchorWidth, - align = this.align, - widget = this; - - if ( !this.$container ) { - // Lazy-initialize $container if not specified in constructor - this.$container = $( this.getClosestScrollableElementContainer() ); - } - - // Set height and width before measuring things, since it might cause our measurements - // to change (e.g. due to scrollbars appearing or disappearing) - this.$popup.css( { - width: this.width, - height: this.height !== null ? this.height : 'auto' - } ); - - // If we are in RTL, we need to flip the alignment, unless it is center - if ( align === 'forwards' || align === 'backwards' ) { - if ( this.$container.css( 'direction' ) === 'rtl' ) { - align = ( { forwards: 'force-left', backwards: 'force-right' } )[ this.align ]; - } else { - align = ( { forwards: 'force-right', backwards: 'force-left' } )[ this.align ]; - } - - } - - // Compute initial popupOffset based on alignment - popupOffset = this.width * ( { 'force-left': -1, center: -0.5, 'force-right': 0 } )[ align ]; - - // Figure out if this will cause the popup to go beyond the edge of the container - originOffset = this.$element.offset().left; - containerLeft = this.$container.offset().left; - containerWidth = this.$container.innerWidth(); - containerRight = containerLeft + containerWidth; - popupLeft = popupOffset - this.containerPadding; - popupRight = popupOffset + this.containerPadding + this.width + this.containerPadding; - overlapLeft = ( originOffset + popupLeft ) - containerLeft; - overlapRight = containerRight - ( originOffset + popupRight ); - - // Adjust offset to make the popup not go beyond the edge, if needed - if ( overlapRight < 0 ) { - popupOffset += overlapRight; - } else if ( overlapLeft < 0 ) { - popupOffset -= overlapLeft; - } - - // Adjust offset to avoid anchor being rendered too close to the edge - // $anchor.width() doesn't work with the pure CSS anchor (returns 0) - // TODO: Find a measurement that works for CSS anchors and image anchors - anchorWidth = this.$anchor[ 0 ].scrollWidth * 2; - if ( popupOffset + this.width < anchorWidth ) { - popupOffset = anchorWidth - this.width; - } else if ( -popupOffset < anchorWidth ) { - popupOffset = -anchorWidth; - } - - // Prevent transition from being interrupted - clearTimeout( this.transitionTimeout ); - if ( transition ) { - // Enable transition - this.$element.addClass( 'oo-ui-popupWidget-transitioning' ); - } - - // Position body relative to anchor - this.$popup.css( 'margin-left', popupOffset ); - - if ( transition ) { - // Prevent transitioning after transition is complete - this.transitionTimeout = setTimeout( function () { - widget.$element.removeClass( 'oo-ui-popupWidget-transitioning' ); - }, 200 ); - } else { - // Prevent transitioning immediately - this.$element.removeClass( 'oo-ui-popupWidget-transitioning' ); - } - - // Reevaluate clipping state since we've relocated and resized the popup - this.clip(); - - return this; -}; - -/** - * Set popup alignment - * @param {string} align Alignment of the popup, `center`, `force-left`, `force-right`, - * `backwards` or `forwards`. - */ -OO.ui.PopupWidget.prototype.setAlignment = function ( align ) { - // Validate alignment and transform deprecated values - if ( [ 'left', 'right', 'force-left', 'force-right', 'backwards', 'forwards', 'center' ].indexOf( align ) > -1 ) { - this.align = { left: 'force-right', right: 'force-left' }[ align ] || align; - } else { - this.align = 'center'; - } -}; - -/** - * Get popup alignment - * @return {string} align Alignment of the popup, `center`, `force-left`, `force-right`, - * `backwards` or `forwards`. - */ -OO.ui.PopupWidget.prototype.getAlignment = function () { - return this.align; -}; |