LaravelTest
1062 строки · 33.1 Кб
1/**!
2* @fileOverview Kickass library to create and place poppers near their reference elements.
3* @version 1.16.1
4* @license
5* Copyright (c) 2016 Federico Zivolo and contributors
6*
7* Permission is hereby granted, free of charge, to any person obtaining a copy
8* of this software and associated documentation files (the "Software"), to deal
9* in the Software without restriction, including without limitation the rights
10* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11* copies of the Software, and to permit persons to whom the Software is
12* furnished to do so, subject to the following conditions:
13*
14* The above copyright notice and this permission notice shall be included in all
15* copies or substantial portions of the Software.
16*
17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23* SOFTWARE.
24*/
25/**
26* Get CSS computed property of the given element
27* @method
28* @memberof Popper.Utils
29* @argument {Eement} element
30* @argument {String} property
31*/
32function getStyleComputedProperty(element, property) {33if (element.nodeType !== 1) {34return [];35}36// NOTE: 1 DOM access here37const window = element.ownerDocument.defaultView;38const css = window.getComputedStyle(element, null);39return property ? css[property] : css;40}
41
42/**
43* Returns the parentNode or the host of the element
44* @method
45* @memberof Popper.Utils
46* @argument {Element} element
47* @returns {Element} parent
48*/
49function getParentNode(element) {50if (element.nodeName === 'HTML') {51return element;52}53return element.parentNode || element.host;54}
55
56/**
57* Returns the scrolling parent of the given element
58* @method
59* @memberof Popper.Utils
60* @argument {Element} element
61* @returns {Element} scroll parent
62*/
63function getScrollParent(element) {64// Return body, `getScroll` will take care to get the correct `scrollTop` from it65if (!element) {66return document.body;67}68
69switch (element.nodeName) {70case 'HTML':71case 'BODY':72return element.ownerDocument.body;73case '#document':74return element.body;75}76
77// Firefox want us to check `-x` and `-y` variations as well78const { overflow, overflowX, overflowY } = getStyleComputedProperty(element);79if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) {80return element;81}82
83return getScrollParent(getParentNode(element));84}
85
86/**
87* Returns the reference node of the reference object, or the reference object itself.
88* @method
89* @memberof Popper.Utils
90* @param {Element|Object} reference - the reference element (the popper will be relative to this)
91* @returns {Element} parent
92*/
93function getReferenceNode(reference) {94return reference && reference.referenceNode ? reference.referenceNode : reference;95}
96
97var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && typeof navigator !== 'undefined';98
99const isIE11 = isBrowser && !!(window.MSInputMethodContext && document.documentMode);100const isIE10 = isBrowser && /MSIE 10/.test(navigator.userAgent);101
102/**
103* Determines if the browser is Internet Explorer
104* @method
105* @memberof Popper.Utils
106* @param {Number} version to check
107* @returns {Boolean} isIE
108*/
109function isIE(version) {110if (version === 11) {111return isIE11;112}113if (version === 10) {114return isIE10;115}116return isIE11 || isIE10;117}
118
119/**
120* Returns the offset parent of the given element
121* @method
122* @memberof Popper.Utils
123* @argument {Element} element
124* @returns {Element} offset parent
125*/
126function getOffsetParent(element) {127if (!element) {128return document.documentElement;129}130
131const noOffsetParent = isIE(10) ? document.body : null;132
133// NOTE: 1 DOM access here134let offsetParent = element.offsetParent || null;135// Skip hidden elements which don't have an offsetParent136while (offsetParent === noOffsetParent && element.nextElementSibling) {137offsetParent = (element = element.nextElementSibling).offsetParent;138}139
140const nodeName = offsetParent && offsetParent.nodeName;141
142if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {143return element ? element.ownerDocument.documentElement : document.documentElement;144}145
146// .offsetParent will return the closest TH, TD or TABLE in case147// no offsetParent is present, I hate this job...148if (['TH', 'TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') {149return getOffsetParent(offsetParent);150}151
152return offsetParent;153}
154
155function isOffsetContainer(element) {156const { nodeName } = element;157if (nodeName === 'BODY') {158return false;159}160return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element;161}
162
163/**
164* Finds the root node (document, shadowDOM root) of the given element
165* @method
166* @memberof Popper.Utils
167* @argument {Element} node
168* @returns {Element} root node
169*/
170function getRoot(node) {171if (node.parentNode !== null) {172return getRoot(node.parentNode);173}174
175return node;176}
177
178/**
179* Finds the offset parent common to the two provided nodes
180* @method
181* @memberof Popper.Utils
182* @argument {Element} element1
183* @argument {Element} element2
184* @returns {Element} common offset parent
185*/
186function findCommonOffsetParent(element1, element2) {187// This check is needed to avoid errors in case one of the elements isn't defined for any reason188if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) {189return document.documentElement;190}191
192// Here we make sure to give as "start" the element that comes first in the DOM193const order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING;194const start = order ? element1 : element2;195const end = order ? element2 : element1;196
197// Get common ancestor container198const range = document.createRange();199range.setStart(start, 0);200range.setEnd(end, 0);201const { commonAncestorContainer } = range;202
203// Both nodes are inside #document204if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) {205if (isOffsetContainer(commonAncestorContainer)) {206return commonAncestorContainer;207}208
209return getOffsetParent(commonAncestorContainer);210}211
212// one of the nodes is inside shadowDOM, find which one213const element1root = getRoot(element1);214if (element1root.host) {215return findCommonOffsetParent(element1root.host, element2);216} else {217return findCommonOffsetParent(element1, getRoot(element2).host);218}219}
220
221/**
222* Gets the scroll value of the given element in the given side (top and left)
223* @method
224* @memberof Popper.Utils
225* @argument {Element} element
226* @argument {String} side `top` or `left`
227* @returns {number} amount of scrolled pixels
228*/
229function getScroll(element, side = 'top') {230const upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft';231const nodeName = element.nodeName;232
233if (nodeName === 'BODY' || nodeName === 'HTML') {234const html = element.ownerDocument.documentElement;235const scrollingElement = element.ownerDocument.scrollingElement || html;236return scrollingElement[upperSide];237}238
239return element[upperSide];240}
241
242/*
243* Sum or subtract the element scroll values (left and top) from a given rect object
244* @method
245* @memberof Popper.Utils
246* @param {Object} rect - Rect object you want to change
247* @param {HTMLElement} element - The element from the function reads the scroll values
248* @param {Boolean} subtract - set to true if you want to subtract the scroll values
249* @return {Object} rect - The modifier rect object
250*/
251function includeScroll(rect, element, subtract = false) {252const scrollTop = getScroll(element, 'top');253const scrollLeft = getScroll(element, 'left');254const modifier = subtract ? -1 : 1;255rect.top += scrollTop * modifier;256rect.bottom += scrollTop * modifier;257rect.left += scrollLeft * modifier;258rect.right += scrollLeft * modifier;259return rect;260}
261
262/*
263* Helper to detect borders of a given element
264* @method
265* @memberof Popper.Utils
266* @param {CSSStyleDeclaration} styles
267* Result of `getStyleComputedProperty` on the given element
268* @param {String} axis - `x` or `y`
269* @return {number} borders - The borders size of the given axis
270*/
271
272function getBordersSize(styles, axis) {273const sideA = axis === 'x' ? 'Left' : 'Top';274const sideB = sideA === 'Left' ? 'Right' : 'Bottom';275
276return parseFloat(styles[`border${sideA}Width`]) + parseFloat(styles[`border${sideB}Width`]);277}
278
279function getSize(axis, body, html, computedStyle) {280return Math.max(body[`offset${axis}`], body[`scroll${axis}`], html[`client${axis}`], html[`offset${axis}`], html[`scroll${axis}`], isIE(10) ? parseInt(html[`offset${axis}`]) + parseInt(computedStyle[`margin${axis === 'Height' ? 'Top' : 'Left'}`]) + parseInt(computedStyle[`margin${axis === 'Height' ? 'Bottom' : 'Right'}`]) : 0);281}
282
283function getWindowSizes(document) {284const body = document.body;285const html = document.documentElement;286const computedStyle = isIE(10) && getComputedStyle(html);287
288return {289height: getSize('Height', body, html, computedStyle),290width: getSize('Width', body, html, computedStyle)291};292}
293
294var _extends = Object.assign || function (target) {295for (var i = 1; i < arguments.length; i++) {296var source = arguments[i];297
298for (var key in source) {299if (Object.prototype.hasOwnProperty.call(source, key)) {300target[key] = source[key];301}302}303}304
305return target;306};307
308/**
309* Given element offsets, generate an output similar to getBoundingClientRect
310* @method
311* @memberof Popper.Utils
312* @argument {Object} offsets
313* @returns {Object} ClientRect like output
314*/
315function getClientRect(offsets) {316return _extends({}, offsets, {317right: offsets.left + offsets.width,318bottom: offsets.top + offsets.height319});320}
321
322/**
323* Get bounding client rect of given element
324* @method
325* @memberof Popper.Utils
326* @param {HTMLElement} element
327* @return {Object} client rect
328*/
329function getBoundingClientRect(element) {330let rect = {};331
332// IE10 10 FIX: Please, don't ask, the element isn't333// considered in DOM in some circumstances...334// This isn't reproducible in IE10 compatibility mode of IE11335try {336if (isIE(10)) {337rect = element.getBoundingClientRect();338const scrollTop = getScroll(element, 'top');339const scrollLeft = getScroll(element, 'left');340rect.top += scrollTop;341rect.left += scrollLeft;342rect.bottom += scrollTop;343rect.right += scrollLeft;344} else {345rect = element.getBoundingClientRect();346}347} catch (e) {}348
349const result = {350left: rect.left,351top: rect.top,352width: rect.right - rect.left,353height: rect.bottom - rect.top354};355
356// subtract scrollbar size from sizes357const sizes = element.nodeName === 'HTML' ? getWindowSizes(element.ownerDocument) : {};358const width = sizes.width || element.clientWidth || result.width;359const height = sizes.height || element.clientHeight || result.height;360
361let horizScrollbar = element.offsetWidth - width;362let vertScrollbar = element.offsetHeight - height;363
364// if an hypothetical scrollbar is detected, we must be sure it's not a `border`365// we make this check conditional for performance reasons366if (horizScrollbar || vertScrollbar) {367const styles = getStyleComputedProperty(element);368horizScrollbar -= getBordersSize(styles, 'x');369vertScrollbar -= getBordersSize(styles, 'y');370
371result.width -= horizScrollbar;372result.height -= vertScrollbar;373}374
375return getClientRect(result);376}
377
378function getOffsetRectRelativeToArbitraryNode(children, parent, fixedPosition = false) {379const isIE10 = isIE(10);380const isHTML = parent.nodeName === 'HTML';381const childrenRect = getBoundingClientRect(children);382const parentRect = getBoundingClientRect(parent);383const scrollParent = getScrollParent(children);384
385const styles = getStyleComputedProperty(parent);386const borderTopWidth = parseFloat(styles.borderTopWidth);387const borderLeftWidth = parseFloat(styles.borderLeftWidth);388
389// In cases where the parent is fixed, we must ignore negative scroll in offset calc390if (fixedPosition && isHTML) {391parentRect.top = Math.max(parentRect.top, 0);392parentRect.left = Math.max(parentRect.left, 0);393}394let offsets = getClientRect({395top: childrenRect.top - parentRect.top - borderTopWidth,396left: childrenRect.left - parentRect.left - borderLeftWidth,397width: childrenRect.width,398height: childrenRect.height399});400offsets.marginTop = 0;401offsets.marginLeft = 0;402
403// Subtract margins of documentElement in case it's being used as parent404// we do this only on HTML because it's the only element that behaves405// differently when margins are applied to it. The margins are included in406// the box of the documentElement, in the other cases not.407if (!isIE10 && isHTML) {408const marginTop = parseFloat(styles.marginTop);409const marginLeft = parseFloat(styles.marginLeft);410
411offsets.top -= borderTopWidth - marginTop;412offsets.bottom -= borderTopWidth - marginTop;413offsets.left -= borderLeftWidth - marginLeft;414offsets.right -= borderLeftWidth - marginLeft;415
416// Attach marginTop and marginLeft because in some circumstances we may need them417offsets.marginTop = marginTop;418offsets.marginLeft = marginLeft;419}420
421if (isIE10 && !fixedPosition ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') {422offsets = includeScroll(offsets, parent);423}424
425return offsets;426}
427
428function getViewportOffsetRectRelativeToArtbitraryNode(element, excludeScroll = false) {429const html = element.ownerDocument.documentElement;430const relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html);431const width = Math.max(html.clientWidth, window.innerWidth || 0);432const height = Math.max(html.clientHeight, window.innerHeight || 0);433
434const scrollTop = !excludeScroll ? getScroll(html) : 0;435const scrollLeft = !excludeScroll ? getScroll(html, 'left') : 0;436
437const offset = {438top: scrollTop - relativeOffset.top + relativeOffset.marginTop,439left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft,440width,441height
442};443
444return getClientRect(offset);445}
446
447/**
448* Check if the given element is fixed or is inside a fixed parent
449* @method
450* @memberof Popper.Utils
451* @argument {Element} element
452* @argument {Element} customContainer
453* @returns {Boolean} answer to "isFixed?"
454*/
455function isFixed(element) {456const nodeName = element.nodeName;457if (nodeName === 'BODY' || nodeName === 'HTML') {458return false;459}460if (getStyleComputedProperty(element, 'position') === 'fixed') {461return true;462}463const parentNode = getParentNode(element);464if (!parentNode) {465return false;466}467return isFixed(parentNode);468}
469
470/**
471* Finds the first parent of an element that has a transformed property defined
472* @method
473* @memberof Popper.Utils
474* @argument {Element} element
475* @returns {Element} first transformed parent or documentElement
476*/
477
478function getFixedPositionOffsetParent(element) {479// This check is needed to avoid errors in case one of the elements isn't defined for any reason480if (!element || !element.parentElement || isIE()) {481return document.documentElement;482}483let el = element.parentElement;484while (el && getStyleComputedProperty(el, 'transform') === 'none') {485el = el.parentElement;486}487return el || document.documentElement;488}
489
490/**
491* Computed the boundaries limits and return them
492* @method
493* @memberof Popper.Utils
494* @param {HTMLElement} popper
495* @param {HTMLElement} reference
496* @param {number} padding
497* @param {HTMLElement} boundariesElement - Element used to define the boundaries
498* @param {Boolean} fixedPosition - Is in fixed position mode
499* @returns {Object} Coordinates of the boundaries
500*/
501function getBoundaries(popper, reference, padding, boundariesElement, fixedPosition = false) {502// NOTE: 1 DOM access here503
504let boundaries = { top: 0, left: 0 };505const offsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, getReferenceNode(reference));506
507// Handle viewport case508if (boundariesElement === 'viewport') {509boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent, fixedPosition);510} else {511// Handle other cases based on DOM element used as boundaries512let boundariesNode;513if (boundariesElement === 'scrollParent') {514boundariesNode = getScrollParent(getParentNode(reference));515if (boundariesNode.nodeName === 'BODY') {516boundariesNode = popper.ownerDocument.documentElement;517}518} else if (boundariesElement === 'window') {519boundariesNode = popper.ownerDocument.documentElement;520} else {521boundariesNode = boundariesElement;522}523
524const offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent, fixedPosition);525
526// In case of HTML, we need a different computation527if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) {528const { height, width } = getWindowSizes(popper.ownerDocument);529boundaries.top += offsets.top - offsets.marginTop;530boundaries.bottom = height + offsets.top;531boundaries.left += offsets.left - offsets.marginLeft;532boundaries.right = width + offsets.left;533} else {534// for all the other DOM elements, this one is good535boundaries = offsets;536}537}538
539// Add paddings540padding = padding || 0;541const isPaddingNumber = typeof padding === 'number';542boundaries.left += isPaddingNumber ? padding : padding.left || 0;543boundaries.top += isPaddingNumber ? padding : padding.top || 0;544boundaries.right -= isPaddingNumber ? padding : padding.right || 0;545boundaries.bottom -= isPaddingNumber ? padding : padding.bottom || 0;546
547return boundaries;548}
549
550function getArea({ width, height }) {551return width * height;552}
553
554/**
555* Utility used to transform the `auto` placement to the placement with more
556* available space.
557* @method
558* @memberof Popper.Utils
559* @argument {Object} data - The data object generated by update method
560* @argument {Object} options - Modifiers configuration and options
561* @returns {Object} The data object, properly modified
562*/
563function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement, padding = 0) {564if (placement.indexOf('auto') === -1) {565return placement;566}567
568const boundaries = getBoundaries(popper, reference, padding, boundariesElement);569
570const rects = {571top: {572width: boundaries.width,573height: refRect.top - boundaries.top574},575right: {576width: boundaries.right - refRect.right,577height: boundaries.height578},579bottom: {580width: boundaries.width,581height: boundaries.bottom - refRect.bottom582},583left: {584width: refRect.left - boundaries.left,585height: boundaries.height586}587};588
589const sortedAreas = Object.keys(rects).map(key => _extends({590key
591}, rects[key], {592area: getArea(rects[key])593})).sort((a, b) => b.area - a.area);594
595const filteredAreas = sortedAreas.filter(({ width, height }) => width >= popper.clientWidth && height >= popper.clientHeight);596
597const computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key;598
599const variation = placement.split('-')[1];600
601return computedPlacement + (variation ? `-${variation}` : '');602}
603
604const timeoutDuration = function () {605const longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];606for (let i = 0; i < longerTimeoutBrowsers.length; i += 1) {607if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {608return 1;609}610}611return 0;612}();613
614function microtaskDebounce(fn) {615let called = false;616return () => {617if (called) {618return;619}620called = true;621window.Promise.resolve().then(() => {622called = false;623fn();624});625};626}
627
628function taskDebounce(fn) {629let scheduled = false;630return () => {631if (!scheduled) {632scheduled = true;633setTimeout(() => {634scheduled = false;635fn();636}, timeoutDuration);637}638};639}
640
641const supportsMicroTasks = isBrowser && window.Promise;642
643/**
644* Create a debounced version of a method, that's asynchronously deferred
645* but called in the minimum time possible.
646*
647* @method
648* @memberof Popper.Utils
649* @argument {Function} fn
650* @returns {Function}
651*/
652var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce;653
654/**
655* Mimics the `find` method of Array
656* @method
657* @memberof Popper.Utils
658* @argument {Array} arr
659* @argument prop
660* @argument value
661* @returns index or -1
662*/
663function find(arr, check) {664// use native find if supported665if (Array.prototype.find) {666return arr.find(check);667}668
669// use `filter` to obtain the same behavior of `find`670return arr.filter(check)[0];671}
672
673/**
674* Return the index of the matching object
675* @method
676* @memberof Popper.Utils
677* @argument {Array} arr
678* @argument prop
679* @argument value
680* @returns index or -1
681*/
682function findIndex(arr, prop, value) {683// use native findIndex if supported684if (Array.prototype.findIndex) {685return arr.findIndex(cur => cur[prop] === value);686}687
688// use `find` + `indexOf` if `findIndex` isn't supported689const match = find(arr, obj => obj[prop] === value);690return arr.indexOf(match);691}
692
693/**
694* Get the position of the given element, relative to its offset parent
695* @method
696* @memberof Popper.Utils
697* @param {Element} element
698* @return {Object} position - Coordinates of the element and its `scrollTop`
699*/
700function getOffsetRect(element) {701let elementRect;702if (element.nodeName === 'HTML') {703const { width, height } = getWindowSizes(element.ownerDocument);704elementRect = {705width,706height,707left: 0,708top: 0709};710} else {711elementRect = {712width: element.offsetWidth,713height: element.offsetHeight,714left: element.offsetLeft,715top: element.offsetTop716};717}718
719// position720return getClientRect(elementRect);721}
722
723/**
724* Get the outer sizes of the given element (offset size + margins)
725* @method
726* @memberof Popper.Utils
727* @argument {Element} element
728* @returns {Object} object containing width and height properties
729*/
730function getOuterSizes(element) {731const window = element.ownerDocument.defaultView;732const styles = window.getComputedStyle(element);733const x = parseFloat(styles.marginTop || 0) + parseFloat(styles.marginBottom || 0);734const y = parseFloat(styles.marginLeft || 0) + parseFloat(styles.marginRight || 0);735const result = {736width: element.offsetWidth + y,737height: element.offsetHeight + x738};739return result;740}
741
742/**
743* Get the opposite placement of the given one
744* @method
745* @memberof Popper.Utils
746* @argument {String} placement
747* @returns {String} flipped placement
748*/
749function getOppositePlacement(placement) {750const hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' };751return placement.replace(/left|right|bottom|top/g, matched => hash[matched]);752}
753
754/**
755* Get offsets to the popper
756* @method
757* @memberof Popper.Utils
758* @param {Object} position - CSS position the Popper will get applied
759* @param {HTMLElement} popper - the popper element
760* @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this)
761* @param {String} placement - one of the valid placement options
762* @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper
763*/
764function getPopperOffsets(popper, referenceOffsets, placement) {765placement = placement.split('-')[0];766
767// Get popper node sizes768const popperRect = getOuterSizes(popper);769
770// Add position, width and height to our offsets object771const popperOffsets = {772width: popperRect.width,773height: popperRect.height774};775
776// depending by the popper placement we have to compute its offsets slightly differently777const isHoriz = ['right', 'left'].indexOf(placement) !== -1;778const mainSide = isHoriz ? 'top' : 'left';779const secondarySide = isHoriz ? 'left' : 'top';780const measurement = isHoriz ? 'height' : 'width';781const secondaryMeasurement = !isHoriz ? 'height' : 'width';782
783popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2;784if (placement === secondarySide) {785popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement];786} else {787popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)];788}789
790return popperOffsets;791}
792
793/**
794* Get offsets to the reference element
795* @method
796* @memberof Popper.Utils
797* @param {Object} state
798* @param {Element} popper - the popper element
799* @param {Element} reference - the reference element (the popper will be relative to this)
800* @param {Element} fixedPosition - is in fixed position mode
801* @returns {Object} An object containing the offsets which will be applied to the popper
802*/
803function getReferenceOffsets(state, popper, reference, fixedPosition = null) {804const commonOffsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, getReferenceNode(reference));805return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent, fixedPosition);806}
807
808/**
809* Get the prefixed supported property name
810* @method
811* @memberof Popper.Utils
812* @argument {String} property (camelCase)
813* @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix)
814*/
815function getSupportedPropertyName(property) {816const prefixes = [false, 'ms', 'Webkit', 'Moz', 'O'];817const upperProp = property.charAt(0).toUpperCase() + property.slice(1);818
819for (let i = 0; i < prefixes.length; i++) {820const prefix = prefixes[i];821const toCheck = prefix ? `${prefix}${upperProp}` : property;822if (typeof document.body.style[toCheck] !== 'undefined') {823return toCheck;824}825}826return null;827}
828
829/**
830* Check if the given variable is a function
831* @method
832* @memberof Popper.Utils
833* @argument {Any} functionToCheck - variable to check
834* @returns {Boolean} answer to: is a function?
835*/
836function isFunction(functionToCheck) {837const getType = {};838return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';839}
840
841/**
842* Helper used to know if the given modifier is enabled.
843* @method
844* @memberof Popper.Utils
845* @returns {Boolean}
846*/
847function isModifierEnabled(modifiers, modifierName) {848return modifiers.some(({ name, enabled }) => enabled && name === modifierName);849}
850
851/**
852* Helper used to know if the given modifier depends from another one.<br />
853* It checks if the needed modifier is listed and enabled.
854* @method
855* @memberof Popper.Utils
856* @param {Array} modifiers - list of modifiers
857* @param {String} requestingName - name of requesting modifier
858* @param {String} requestedName - name of requested modifier
859* @returns {Boolean}
860*/
861function isModifierRequired(modifiers, requestingName, requestedName) {862const requesting = find(modifiers, ({ name }) => name === requestingName);863
864const isRequired = !!requesting && modifiers.some(modifier => {865return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order;866});867
868if (!isRequired) {869const requesting = `\`${requestingName}\``;870const requested = `\`${requestedName}\``;871console.warn(`${requested} modifier is required by ${requesting} modifier in order to work, be sure to include it before ${requesting}!`);872}873return isRequired;874}
875
876/**
877* Tells if a given input is a number
878* @method
879* @memberof Popper.Utils
880* @param {*} input to check
881* @return {Boolean}
882*/
883function isNumeric(n) {884return n !== '' && !isNaN(parseFloat(n)) && isFinite(n);885}
886
887/**
888* Get the window associated with the element
889* @argument {Element} element
890* @returns {Window}
891*/
892function getWindow(element) {893const ownerDocument = element.ownerDocument;894return ownerDocument ? ownerDocument.defaultView : window;895}
896
897/**
898* Remove event listeners used to update the popper position
899* @method
900* @memberof Popper.Utils
901* @private
902*/
903function removeEventListeners(reference, state) {904// Remove resize event listener on window905getWindow(reference).removeEventListener('resize', state.updateBound);906
907// Remove scroll event listener on scroll parents908state.scrollParents.forEach(target => {909target.removeEventListener('scroll', state.updateBound);910});911
912// Reset state913state.updateBound = null;914state.scrollParents = [];915state.scrollElement = null;916state.eventsEnabled = false;917return state;918}
919
920/**
921* Loop trough the list of modifiers and run them in order,
922* each of them will then edit the data object.
923* @method
924* @memberof Popper.Utils
925* @param {dataObject} data
926* @param {Array} modifiers
927* @param {String} ends - Optional modifier name used as stopper
928* @returns {dataObject}
929*/
930function runModifiers(modifiers, data, ends) {931const modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends));932
933modifiersToRun.forEach(modifier => {934if (modifier['function']) {935// eslint-disable-line dot-notation936console.warn('`modifier.function` is deprecated, use `modifier.fn`!');937}938const fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation939if (modifier.enabled && isFunction(fn)) {940// Add properties to offsets to make them a complete clientRect object941// we do this before each modifier to make sure the previous one doesn't942// mess with these values943data.offsets.popper = getClientRect(data.offsets.popper);944data.offsets.reference = getClientRect(data.offsets.reference);945
946data = fn(data, modifier);947}948});949
950return data;951}
952
953/**
954* Set the attributes to the given popper
955* @method
956* @memberof Popper.Utils
957* @argument {Element} element - Element to apply the attributes to
958* @argument {Object} styles
959* Object with a list of properties and values which will be applied to the element
960*/
961function setAttributes(element, attributes) {962Object.keys(attributes).forEach(function (prop) {963const value = attributes[prop];964if (value !== false) {965element.setAttribute(prop, attributes[prop]);966} else {967element.removeAttribute(prop);968}969});970}
971
972/**
973* Set the style to the given popper
974* @method
975* @memberof Popper.Utils
976* @argument {Element} element - Element to apply the style to
977* @argument {Object} styles
978* Object with a list of properties and values which will be applied to the element
979*/
980function setStyles(element, styles) {981Object.keys(styles).forEach(prop => {982let unit = '';983// add unit if the value is numeric and is one of the following984if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) {985unit = 'px';986}987element.style[prop] = styles[prop] + unit;988});989}
990
991function attachToScrollParents(scrollParent, event, callback, scrollParents) {992const isBody = scrollParent.nodeName === 'BODY';993const target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent;994target.addEventListener(event, callback, { passive: true });995
996if (!isBody) {997attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents);998}999scrollParents.push(target);1000}
1001
1002/**
1003* Setup needed event listeners used to update the popper position
1004* @method
1005* @memberof Popper.Utils
1006* @private
1007*/
1008function setupEventListeners(reference, options, state, updateBound) {1009// Resize event listener on window1010state.updateBound = updateBound;1011getWindow(reference).addEventListener('resize', state.updateBound, { passive: true });1012
1013// Scroll event listener on scroll parents1014const scrollElement = getScrollParent(reference);1015attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents);1016state.scrollElement = scrollElement;1017state.eventsEnabled = true;1018
1019return state;1020}
1021
1022// This is here just for backward compatibility with versions lower than v1.10.3
1023// you should import the utilities using named exports, if you want them all use:
1024// ```
1025// import * as PopperUtils from 'popper-utils';
1026// ```
1027// The default export will be removed in the next major version.
1028var index = {1029computeAutoPlacement,1030debounce,1031findIndex,1032getBordersSize,1033getBoundaries,1034getBoundingClientRect,1035getClientRect,1036getOffsetParent,1037getOffsetRect,1038getOffsetRectRelativeToArbitraryNode,1039getOuterSizes,1040getParentNode,1041getPopperOffsets,1042getReferenceOffsets,1043getScroll,1044getScrollParent,1045getStyleComputedProperty,1046getSupportedPropertyName,1047getWindowSizes,1048isFixed,1049isFunction,1050isModifierEnabled,1051isModifierRequired,1052isNumeric,1053removeEventListeners,1054runModifiers,1055setAttributes,1056setStyles,1057setupEventListeners
1058};1059
1060export { computeAutoPlacement, debounce, findIndex, getBordersSize, getBoundaries, getBoundingClientRect, getClientRect, getOffsetParent, getOffsetRect, getOffsetRectRelativeToArbitraryNode, getOuterSizes, getParentNode, getPopperOffsets, getReferenceOffsets, getScroll, getScrollParent, getStyleComputedProperty, getSupportedPropertyName, getWindowSizes, isFixed, isFunction, isModifierEnabled, isModifierRequired, isNumeric, removeEventListeners, runModifiers, setAttributes, setStyles, setupEventListeners };1061export default index;1062//# sourceMappingURL=popper-utils.js.map
1063