/* eslint-disable */ /*! * Positions elements relative to other elements. * Borrowed from jquery.ui.position and updated to remove unused code. * Does not pollute the global jQuery or jQuery.ui objects * Does not support all options supported by jQuery.ui.position * Changes: * - The 'using' option is not supported * - Only 'collision': 'flip' is supported. * - In options, the 'of' parameter must always be provided * Upstream commit: https://github.com/jquery/jquery-ui/commit/0df6e658307f8936a477deb9674d643d18a2469b */ 'use strict'; var cachedScrollbarWidth, abs = Math.abs, rhorizontal = /left|center|right/, rvertical = /top|center|bottom/, roffset = /[\+\-]\d+(\.[\d]+)?%?/, rposition = /^\w+/, rpercent = /%$/; function getOffsets( offsets, width, height ) { return [ parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) ]; } function parseCss( element, property ) { return parseInt( $.css( element, property ), 10 ) || 0; } function isWindow( obj ) { return obj != null && obj === obj.window; } function getDimensions( elem ) { var raw = elem[ 0 ]; if ( raw.nodeType === 9 ) { return { width: elem.width(), height: elem.height(), offset: { top: 0, left: 0 } }; } if ( isWindow( raw ) ) { return { width: elem.width(), height: elem.height(), offset: { top: elem.scrollTop(), left: elem.scrollLeft() } }; } if ( raw.preventDefault ) { return { width: 0, height: 0, offset: { top: raw.pageY, left: raw.pageX } }; } return { width: elem.outerWidth(), height: elem.outerHeight(), offset: elem.offset() }; } function scrollbarWidth() { if ( cachedScrollbarWidth !== undefined ) { return cachedScrollbarWidth; } var w1, w2, div = $( '
" + "
" ), innerDiv = div.children()[ 0 ]; $( 'body' ).append( div ); w1 = innerDiv.offsetWidth; div.css( 'overflow', 'scroll' ); w2 = innerDiv.offsetWidth; if ( w1 === w2 ) { w2 = div[ 0 ].clientWidth; } div.remove(); return cachedScrollbarWidth = w1 - w2; } function getScrollInfo( within ) { var overflowX = within.isWindow || within.isDocument ? '' : within.element.css( 'overflow-x' ), overflowY = within.isWindow || within.isDocument ? '' : within.element.css( 'overflow-y' ), hasOverflowX = overflowX === 'scroll' || ( overflowX === 'auto' && within.width < within.element[ 0 ].scrollWidth ), hasOverflowY = overflowY === 'scroll' || ( overflowY === 'auto' && within.height < within.element[ 0 ].scrollHeight ); return { width: hasOverflowY ? scrollbarWidth() : 0, height: hasOverflowX ? scrollbarWidth() : 0 }; } function getWithinInfo( element ) { var withinElement = $( element || window ), isElemWindow = isWindow( withinElement[ 0 ] ), isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9, hasOffset = !isElemWindow && !isDocument; return { element: withinElement, isWindow: isElemWindow, isDocument: isDocument, offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 }, scrollLeft: withinElement.scrollLeft(), scrollTop: withinElement.scrollTop(), width: withinElement.outerWidth(), height: withinElement.outerHeight() }; } var flip = { left: function ( position, data ) { var within = data.within, withinOffset = within.offset.left + within.scrollLeft, outerWidth = within.width, offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, collisionPosLeft = position.left - data.collisionPosition.marginLeft, overLeft = collisionPosLeft - offsetLeft, overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, myOffset = data.my[ 0 ] === 'left' ? -data.elemWidth : data.my[ 0 ] === 'right' ? data.elemWidth : 0, atOffset = data.at[ 0 ] === 'left' ? data.targetWidth : data.at[ 0 ] === 'right' ? -data.targetWidth : 0, offset = -2 * data.offset[ 0 ], newOverRight, newOverLeft; if ( overLeft < 0 ) { newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { position.left += myOffset + atOffset + offset; } } else if ( overRight > 0 ) { newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { position.left += myOffset + atOffset + offset; } } }, top: function ( position, data ) { var within = data.within, withinOffset = within.offset.top + within.scrollTop, outerHeight = within.height, offsetTop = within.isWindow ? within.scrollTop : within.offset.top, collisionPosTop = position.top - data.collisionPosition.marginTop, overTop = collisionPosTop - offsetTop, overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, top = data.my[ 1 ] === 'top', myOffset = top ? -data.elemHeight : data.my[ 1 ] === 'bottom' ? data.elemHeight : 0, atOffset = data.at[ 1 ] === 'top' ? data.targetHeight : data.at[ 1 ] === 'bottom' ? -data.targetHeight : 0, offset = -2 * data.offset[ 1 ], newOverTop, newOverBottom; if ( overTop < 0 ) { newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { position.top += myOffset + atOffset + offset; } } else if ( overBottom > 0 ) { newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { position.top += myOffset + atOffset + offset; } } } }; function positionElement( $targetElem, options ) { // Make a copy, we don't want to modify arguments options = $.extend( {}, options ); var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, // Make sure string options are treated as CSS selectors target = typeof options.of === 'string' ? $( document ).find( options.of ) : $( options.of ), within = getWithinInfo( options.within ), scrollInfo = getScrollInfo( within ), offsets = {}; dimensions = getDimensions( target ); if ( target[ 0 ].preventDefault ) { // Force left top to allow flipping options.at = 'left top'; } targetWidth = dimensions.width; targetHeight = dimensions.height; targetOffset = dimensions.offset; // Clone to reuse original targetOffset later basePosition = $.extend( {}, targetOffset ); // Force my and at to have valid horizontal and vertical positions // if a value is missing or invalid, it will be converted to center $.each( [ 'my', 'at' ], function () { var pos = ( options[ this ] || '' ).split( ' ' ), horizontalOffset, verticalOffset; if ( pos.length === 1 ) { pos = rhorizontal.test( pos[ 0 ] ) ? pos.concat( [ 'center' ] ) : rvertical.test( pos[ 0 ] ) ? [ 'center' ].concat( pos ) : [ 'center', 'center' ]; } pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : 'center'; pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : 'center'; // Calculate offsets horizontalOffset = roffset.exec( pos[ 0 ] ); verticalOffset = roffset.exec( pos[ 1 ] ); offsets[ this ] = [ horizontalOffset ? horizontalOffset[ 0 ] : 0, verticalOffset ? verticalOffset[ 0 ] : 0 ]; // Reduce to just the positions without the offsets options[ this ] = [ rposition.exec( pos[ 0 ] )[ 0 ], rposition.exec( pos[ 1 ] )[ 0 ] ]; } ); if ( options.at[ 0 ] === 'right' ) { basePosition.left += targetWidth; } else if ( options.at[ 0 ] === 'center' ) { basePosition.left += targetWidth / 2; } if ( options.at[ 1 ] === 'bottom' ) { basePosition.top += targetHeight; } else if ( options.at[ 1 ] === 'center' ) { basePosition.top += targetHeight / 2; } atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); basePosition.left += atOffset[ 0 ]; basePosition.top += atOffset[ 1 ]; return $targetElem.each( function () { var collisionPosition, elem = $( this ), elemWidth = elem.outerWidth(), elemHeight = elem.outerHeight(), marginLeft = parseCss( this, 'marginLeft' ), marginTop = parseCss( this, 'marginTop' ), collisionWidth = elemWidth + marginLeft + parseCss( this, 'marginRight' ) + scrollInfo.width, collisionHeight = elemHeight + marginTop + parseCss( this, 'marginBottom' ) + scrollInfo.height, position = $.extend( {}, basePosition ), myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); if ( options.my[ 0 ] === 'right' ) { position.left -= elemWidth; } else if ( options.my[ 0 ] === 'center' ) { position.left -= elemWidth / 2; } if ( options.my[ 1 ] === 'bottom' ) { position.top -= elemHeight; } else if ( options.my[ 1 ] === 'center' ) { position.top -= elemHeight / 2; } position.left += myOffset[ 0 ]; position.top += myOffset[ 1 ]; collisionPosition = { marginLeft: marginLeft, marginTop: marginTop }; $.each( [ 'left', 'top' ], function ( i, dir ) { flip[ dir ]( position, { targetWidth: targetWidth, targetHeight: targetHeight, elemWidth: elemWidth, elemHeight: elemHeight, collisionPosition: collisionPosition, collisionWidth: collisionWidth, collisionHeight: collisionHeight, offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset[ 1 ] + myOffset[ 1 ] ], my: options.my, at: options.at, within: within, elem: elem } ); } ); elem.offset( position ); } ); } module.exports = positionElement;