You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							1001 lines
						
					
					
						
							30 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							1001 lines
						
					
					
						
							30 KiB
						
					
					
				| /**! | |
|  * @fileOverview Kickass library to create and place poppers near their reference elements. | |
|  * @version 1.12.9 | |
|  * @license | |
|  * Copyright (c) 2016 Federico Zivolo and contributors | |
|  * | |
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | |
|  * of this software and associated documentation files (the "Software"), to deal | |
|  * in the Software without restriction, including without limitation the rights | |
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
|  * copies of the Software, and to permit persons to whom the Software is | |
|  * furnished to do so, subject to the following conditions: | |
|  * | |
|  * The above copyright notice and this permission notice shall be included in all | |
|  * copies or substantial portions of the Software. | |
|  * | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
|  * SOFTWARE. | |
|  */ | |
| /** | |
|  * Get CSS computed property of the given element | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Eement} element | |
|  * @argument {String} property | |
|  */ | |
| function getStyleComputedProperty(element, property) { | |
|   if (element.nodeType !== 1) { | |
|     return []; | |
|   } | |
|   // NOTE: 1 DOM access here | |
|   const css = getComputedStyle(element, null); | |
|   return property ? css[property] : css; | |
| } | |
| 
 | |
| /** | |
|  * Returns the parentNode or the host of the element | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Element} element | |
|  * @returns {Element} parent | |
|  */ | |
| function getParentNode(element) { | |
|   if (element.nodeName === 'HTML') { | |
|     return element; | |
|   } | |
|   return element.parentNode || element.host; | |
| } | |
| 
 | |
| /** | |
|  * Returns the scrolling parent of the given element | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Element} element | |
|  * @returns {Element} scroll parent | |
|  */ | |
| function getScrollParent(element) { | |
|   // Return body, `getScroll` will take care to get the correct `scrollTop` from it | |
|   if (!element) { | |
|     return document.body; | |
|   } | |
| 
 | |
|   switch (element.nodeName) { | |
|     case 'HTML': | |
|     case 'BODY': | |
|       return element.ownerDocument.body; | |
|     case '#document': | |
|       return element.body; | |
|   } | |
| 
 | |
|   // Firefox want us to check `-x` and `-y` variations as well | |
|   const { overflow, overflowX, overflowY } = getStyleComputedProperty(element); | |
|   if (/(auto|scroll)/.test(overflow + overflowY + overflowX)) { | |
|     return element; | |
|   } | |
| 
 | |
|   return getScrollParent(getParentNode(element)); | |
| } | |
| 
 | |
| /** | |
|  * Returns the offset parent of the given element | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Element} element | |
|  * @returns {Element} offset parent | |
|  */ | |
| function getOffsetParent(element) { | |
|   // NOTE: 1 DOM access here | |
|   const offsetParent = element && element.offsetParent; | |
|   const nodeName = offsetParent && offsetParent.nodeName; | |
| 
 | |
|   if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') { | |
|     if (element) { | |
|       return element.ownerDocument.documentElement; | |
|     } | |
| 
 | |
|     return document.documentElement; | |
|   } | |
| 
 | |
|   // .offsetParent will return the closest TD or TABLE in case | |
|   // no offsetParent is present, I hate this job... | |
|   if (['TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') { | |
|     return getOffsetParent(offsetParent); | |
|   } | |
| 
 | |
|   return offsetParent; | |
| } | |
| 
 | |
| function isOffsetContainer(element) { | |
|   const { nodeName } = element; | |
|   if (nodeName === 'BODY') { | |
|     return false; | |
|   } | |
|   return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element; | |
| } | |
| 
 | |
| /** | |
|  * Finds the root node (document, shadowDOM root) of the given element | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Element} node | |
|  * @returns {Element} root node | |
|  */ | |
| function getRoot(node) { | |
|   if (node.parentNode !== null) { | |
|     return getRoot(node.parentNode); | |
|   } | |
| 
 | |
|   return node; | |
| } | |
| 
 | |
| /** | |
|  * Finds the offset parent common to the two provided nodes | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Element} element1 | |
|  * @argument {Element} element2 | |
|  * @returns {Element} common offset parent | |
|  */ | |
| function findCommonOffsetParent(element1, element2) { | |
|   // This check is needed to avoid errors in case one of the elements isn't defined for any reason | |
|   if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) { | |
|     return document.documentElement; | |
|   } | |
| 
 | |
|   // Here we make sure to give as "start" the element that comes first in the DOM | |
|   const order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING; | |
|   const start = order ? element1 : element2; | |
|   const end = order ? element2 : element1; | |
| 
 | |
|   // Get common ancestor container | |
|   const range = document.createRange(); | |
|   range.setStart(start, 0); | |
|   range.setEnd(end, 0); | |
|   const { commonAncestorContainer } = range; | |
| 
 | |
|   // Both nodes are inside #document | |
|   if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) { | |
|     if (isOffsetContainer(commonAncestorContainer)) { | |
|       return commonAncestorContainer; | |
|     } | |
| 
 | |
|     return getOffsetParent(commonAncestorContainer); | |
|   } | |
| 
 | |
|   // one of the nodes is inside shadowDOM, find which one | |
|   const element1root = getRoot(element1); | |
|   if (element1root.host) { | |
|     return findCommonOffsetParent(element1root.host, element2); | |
|   } else { | |
|     return findCommonOffsetParent(element1, getRoot(element2).host); | |
|   } | |
| } | |
| 
 | |
| /** | |
|  * Gets the scroll value of the given element in the given side (top and left) | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Element} element | |
|  * @argument {String} side `top` or `left` | |
|  * @returns {number} amount of scrolled pixels | |
|  */ | |
| function getScroll(element, side = 'top') { | |
|   const upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft'; | |
|   const nodeName = element.nodeName; | |
| 
 | |
|   if (nodeName === 'BODY' || nodeName === 'HTML') { | |
|     const html = element.ownerDocument.documentElement; | |
|     const scrollingElement = element.ownerDocument.scrollingElement || html; | |
|     return scrollingElement[upperSide]; | |
|   } | |
| 
 | |
|   return element[upperSide]; | |
| } | |
| 
 | |
| /* | |
|  * Sum or subtract the element scroll values (left and top) from a given rect object | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @param {Object} rect - Rect object you want to change | |
|  * @param {HTMLElement} element - The element from the function reads the scroll values | |
|  * @param {Boolean} subtract - set to true if you want to subtract the scroll values | |
|  * @return {Object} rect - The modifier rect object | |
|  */ | |
| function includeScroll(rect, element, subtract = false) { | |
|   const scrollTop = getScroll(element, 'top'); | |
|   const scrollLeft = getScroll(element, 'left'); | |
|   const modifier = subtract ? -1 : 1; | |
|   rect.top += scrollTop * modifier; | |
|   rect.bottom += scrollTop * modifier; | |
|   rect.left += scrollLeft * modifier; | |
|   rect.right += scrollLeft * modifier; | |
|   return rect; | |
| } | |
| 
 | |
| /* | |
|  * Helper to detect borders of a given element | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @param {CSSStyleDeclaration} styles | |
|  * Result of `getStyleComputedProperty` on the given element | |
|  * @param {String} axis - `x` or `y` | |
|  * @return {number} borders - The borders size of the given axis | |
|  */ | |
| 
 | |
| function getBordersSize(styles, axis) { | |
|   const sideA = axis === 'x' ? 'Left' : 'Top'; | |
|   const sideB = sideA === 'Left' ? 'Right' : 'Bottom'; | |
| 
 | |
|   return parseFloat(styles[`border${sideA}Width`], 10) + parseFloat(styles[`border${sideB}Width`], 10); | |
| } | |
| 
 | |
| /** | |
|  * Tells if you are running Internet Explorer 10 | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @returns {Boolean} isIE10 | |
|  */ | |
| let isIE10 = undefined; | |
| 
 | |
| var isIE10$1 = function () { | |
|   if (isIE10 === undefined) { | |
|     isIE10 = navigator.appVersion.indexOf('MSIE 10') !== -1; | |
|   } | |
|   return isIE10; | |
| }; | |
| 
 | |
| function getSize(axis, body, html, computedStyle) { | |
|   return Math.max(body[`offset${axis}`], body[`scroll${axis}`], html[`client${axis}`], html[`offset${axis}`], html[`scroll${axis}`], isIE10$1() ? html[`offset${axis}`] + computedStyle[`margin${axis === 'Height' ? 'Top' : 'Left'}`] + computedStyle[`margin${axis === 'Height' ? 'Bottom' : 'Right'}`] : 0); | |
| } | |
| 
 | |
| function getWindowSizes() { | |
|   const body = document.body; | |
|   const html = document.documentElement; | |
|   const computedStyle = isIE10$1() && getComputedStyle(html); | |
| 
 | |
|   return { | |
|     height: getSize('Height', body, html, computedStyle), | |
|     width: getSize('Width', body, html, computedStyle) | |
|   }; | |
| } | |
| 
 | |
| var _extends = Object.assign || function (target) { | |
|   for (var i = 1; i < arguments.length; i++) { | |
|     var source = arguments[i]; | |
| 
 | |
|     for (var key in source) { | |
|       if (Object.prototype.hasOwnProperty.call(source, key)) { | |
|         target[key] = source[key]; | |
|       } | |
|     } | |
|   } | |
| 
 | |
|   return target; | |
| }; | |
| 
 | |
| /** | |
|  * Given element offsets, generate an output similar to getBoundingClientRect | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Object} offsets | |
|  * @returns {Object} ClientRect like output | |
|  */ | |
| function getClientRect(offsets) { | |
|   return _extends({}, offsets, { | |
|     right: offsets.left + offsets.width, | |
|     bottom: offsets.top + offsets.height | |
|   }); | |
| } | |
| 
 | |
| /** | |
|  * Get bounding client rect of given element | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @param {HTMLElement} element | |
|  * @return {Object} client rect | |
|  */ | |
| function getBoundingClientRect(element) { | |
|   let rect = {}; | |
| 
 | |
|   // IE10 10 FIX: Please, don't ask, the element isn't | |
|   // considered in DOM in some circumstances... | |
|   // This isn't reproducible in IE10 compatibility mode of IE11 | |
|   if (isIE10$1()) { | |
|     try { | |
|       rect = element.getBoundingClientRect(); | |
|       const scrollTop = getScroll(element, 'top'); | |
|       const scrollLeft = getScroll(element, 'left'); | |
|       rect.top += scrollTop; | |
|       rect.left += scrollLeft; | |
|       rect.bottom += scrollTop; | |
|       rect.right += scrollLeft; | |
|     } catch (err) {} | |
|   } else { | |
|     rect = element.getBoundingClientRect(); | |
|   } | |
| 
 | |
|   const result = { | |
|     left: rect.left, | |
|     top: rect.top, | |
|     width: rect.right - rect.left, | |
|     height: rect.bottom - rect.top | |
|   }; | |
| 
 | |
|   // subtract scrollbar size from sizes | |
|   const sizes = element.nodeName === 'HTML' ? getWindowSizes() : {}; | |
|   const width = sizes.width || element.clientWidth || result.right - result.left; | |
|   const height = sizes.height || element.clientHeight || result.bottom - result.top; | |
| 
 | |
|   let horizScrollbar = element.offsetWidth - width; | |
|   let vertScrollbar = element.offsetHeight - height; | |
| 
 | |
|   // if an hypothetical scrollbar is detected, we must be sure it's not a `border` | |
|   // we make this check conditional for performance reasons | |
|   if (horizScrollbar || vertScrollbar) { | |
|     const styles = getStyleComputedProperty(element); | |
|     horizScrollbar -= getBordersSize(styles, 'x'); | |
|     vertScrollbar -= getBordersSize(styles, 'y'); | |
| 
 | |
|     result.width -= horizScrollbar; | |
|     result.height -= vertScrollbar; | |
|   } | |
| 
 | |
|   return getClientRect(result); | |
| } | |
| 
 | |
| function getOffsetRectRelativeToArbitraryNode(children, parent) { | |
|   const isIE10 = isIE10$1(); | |
|   const isHTML = parent.nodeName === 'HTML'; | |
|   const childrenRect = getBoundingClientRect(children); | |
|   const parentRect = getBoundingClientRect(parent); | |
|   const scrollParent = getScrollParent(children); | |
| 
 | |
|   const styles = getStyleComputedProperty(parent); | |
|   const borderTopWidth = parseFloat(styles.borderTopWidth, 10); | |
|   const borderLeftWidth = parseFloat(styles.borderLeftWidth, 10); | |
| 
 | |
|   let offsets = getClientRect({ | |
|     top: childrenRect.top - parentRect.top - borderTopWidth, | |
|     left: childrenRect.left - parentRect.left - borderLeftWidth, | |
|     width: childrenRect.width, | |
|     height: childrenRect.height | |
|   }); | |
|   offsets.marginTop = 0; | |
|   offsets.marginLeft = 0; | |
| 
 | |
|   // Subtract margins of documentElement in case it's being used as parent | |
|   // we do this only on HTML because it's the only element that behaves | |
|   // differently when margins are applied to it. The margins are included in | |
|   // the box of the documentElement, in the other cases not. | |
|   if (!isIE10 && isHTML) { | |
|     const marginTop = parseFloat(styles.marginTop, 10); | |
|     const marginLeft = parseFloat(styles.marginLeft, 10); | |
| 
 | |
|     offsets.top -= borderTopWidth - marginTop; | |
|     offsets.bottom -= borderTopWidth - marginTop; | |
|     offsets.left -= borderLeftWidth - marginLeft; | |
|     offsets.right -= borderLeftWidth - marginLeft; | |
| 
 | |
|     // Attach marginTop and marginLeft because in some circumstances we may need them | |
|     offsets.marginTop = marginTop; | |
|     offsets.marginLeft = marginLeft; | |
|   } | |
| 
 | |
|   if (isIE10 ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') { | |
|     offsets = includeScroll(offsets, parent); | |
|   } | |
| 
 | |
|   return offsets; | |
| } | |
| 
 | |
| function getViewportOffsetRectRelativeToArtbitraryNode(element) { | |
|   const html = element.ownerDocument.documentElement; | |
|   const relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html); | |
|   const width = Math.max(html.clientWidth, window.innerWidth || 0); | |
|   const height = Math.max(html.clientHeight, window.innerHeight || 0); | |
| 
 | |
|   const scrollTop = getScroll(html); | |
|   const scrollLeft = getScroll(html, 'left'); | |
| 
 | |
|   const offset = { | |
|     top: scrollTop - relativeOffset.top + relativeOffset.marginTop, | |
|     left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft, | |
|     width, | |
|     height | |
|   }; | |
| 
 | |
|   return getClientRect(offset); | |
| } | |
| 
 | |
| /** | |
|  * Check if the given element is fixed or is inside a fixed parent | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Element} element | |
|  * @argument {Element} customContainer | |
|  * @returns {Boolean} answer to "isFixed?" | |
|  */ | |
| function isFixed(element) { | |
|   const nodeName = element.nodeName; | |
|   if (nodeName === 'BODY' || nodeName === 'HTML') { | |
|     return false; | |
|   } | |
|   if (getStyleComputedProperty(element, 'position') === 'fixed') { | |
|     return true; | |
|   } | |
|   return isFixed(getParentNode(element)); | |
| } | |
| 
 | |
| /** | |
|  * Computed the boundaries limits and return them | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @param {HTMLElement} popper | |
|  * @param {HTMLElement} reference | |
|  * @param {number} padding | |
|  * @param {HTMLElement} boundariesElement - Element used to define the boundaries | |
|  * @returns {Object} Coordinates of the boundaries | |
|  */ | |
| function getBoundaries(popper, reference, padding, boundariesElement) { | |
|   // NOTE: 1 DOM access here | |
|   let boundaries = { top: 0, left: 0 }; | |
|   const offsetParent = findCommonOffsetParent(popper, reference); | |
| 
 | |
|   // Handle viewport case | |
|   if (boundariesElement === 'viewport') { | |
|     boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent); | |
|   } else { | |
|     // Handle other cases based on DOM element used as boundaries | |
|     let boundariesNode; | |
|     if (boundariesElement === 'scrollParent') { | |
|       boundariesNode = getScrollParent(getParentNode(reference)); | |
|       if (boundariesNode.nodeName === 'BODY') { | |
|         boundariesNode = popper.ownerDocument.documentElement; | |
|       } | |
|     } else if (boundariesElement === 'window') { | |
|       boundariesNode = popper.ownerDocument.documentElement; | |
|     } else { | |
|       boundariesNode = boundariesElement; | |
|     } | |
| 
 | |
|     const offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent); | |
| 
 | |
|     // In case of HTML, we need a different computation | |
|     if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) { | |
|       const { height, width } = getWindowSizes(); | |
|       boundaries.top += offsets.top - offsets.marginTop; | |
|       boundaries.bottom = height + offsets.top; | |
|       boundaries.left += offsets.left - offsets.marginLeft; | |
|       boundaries.right = width + offsets.left; | |
|     } else { | |
|       // for all the other DOM elements, this one is good | |
|       boundaries = offsets; | |
|     } | |
|   } | |
| 
 | |
|   // Add paddings | |
|   boundaries.left += padding; | |
|   boundaries.top += padding; | |
|   boundaries.right -= padding; | |
|   boundaries.bottom -= padding; | |
| 
 | |
|   return boundaries; | |
| } | |
| 
 | |
| function getArea({ width, height }) { | |
|   return width * height; | |
| } | |
| 
 | |
| /** | |
|  * Utility used to transform the `auto` placement to the placement with more | |
|  * available space. | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Object} data - The data object generated by update method | |
|  * @argument {Object} options - Modifiers configuration and options | |
|  * @returns {Object} The data object, properly modified | |
|  */ | |
| function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement, padding = 0) { | |
|   if (placement.indexOf('auto') === -1) { | |
|     return placement; | |
|   } | |
| 
 | |
|   const boundaries = getBoundaries(popper, reference, padding, boundariesElement); | |
| 
 | |
|   const rects = { | |
|     top: { | |
|       width: boundaries.width, | |
|       height: refRect.top - boundaries.top | |
|     }, | |
|     right: { | |
|       width: boundaries.right - refRect.right, | |
|       height: boundaries.height | |
|     }, | |
|     bottom: { | |
|       width: boundaries.width, | |
|       height: boundaries.bottom - refRect.bottom | |
|     }, | |
|     left: { | |
|       width: refRect.left - boundaries.left, | |
|       height: boundaries.height | |
|     } | |
|   }; | |
| 
 | |
|   const sortedAreas = Object.keys(rects).map(key => _extends({ | |
|     key | |
|   }, rects[key], { | |
|     area: getArea(rects[key]) | |
|   })).sort((a, b) => b.area - a.area); | |
| 
 | |
|   const filteredAreas = sortedAreas.filter(({ width, height }) => width >= popper.clientWidth && height >= popper.clientHeight); | |
| 
 | |
|   const computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key; | |
| 
 | |
|   const variation = placement.split('-')[1]; | |
| 
 | |
|   return computedPlacement + (variation ? `-${variation}` : ''); | |
| } | |
| 
 | |
| const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined'; | |
| const longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox']; | |
| let timeoutDuration = 0; | |
| for (let i = 0; i < longerTimeoutBrowsers.length; i += 1) { | |
|   if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) { | |
|     timeoutDuration = 1; | |
|     break; | |
|   } | |
| } | |
| 
 | |
| function microtaskDebounce(fn) { | |
|   let called = false; | |
|   return () => { | |
|     if (called) { | |
|       return; | |
|     } | |
|     called = true; | |
|     window.Promise.resolve().then(() => { | |
|       called = false; | |
|       fn(); | |
|     }); | |
|   }; | |
| } | |
| 
 | |
| function taskDebounce(fn) { | |
|   let scheduled = false; | |
|   return () => { | |
|     if (!scheduled) { | |
|       scheduled = true; | |
|       setTimeout(() => { | |
|         scheduled = false; | |
|         fn(); | |
|       }, timeoutDuration); | |
|     } | |
|   }; | |
| } | |
| 
 | |
| const supportsMicroTasks = isBrowser && window.Promise; | |
| 
 | |
| /** | |
| * Create a debounced version of a method, that's asynchronously deferred | |
| * but called in the minimum time possible. | |
| * | |
| * @method | |
| * @memberof Popper.Utils | |
| * @argument {Function} fn | |
| * @returns {Function} | |
| */ | |
| var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce; | |
| 
 | |
| /** | |
|  * Mimics the `find` method of Array | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Array} arr | |
|  * @argument prop | |
|  * @argument value | |
|  * @returns index or -1 | |
|  */ | |
| function find(arr, check) { | |
|   // use native find if supported | |
|   if (Array.prototype.find) { | |
|     return arr.find(check); | |
|   } | |
| 
 | |
|   // use `filter` to obtain the same behavior of `find` | |
|   return arr.filter(check)[0]; | |
| } | |
| 
 | |
| /** | |
|  * Return the index of the matching object | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Array} arr | |
|  * @argument prop | |
|  * @argument value | |
|  * @returns index or -1 | |
|  */ | |
| function findIndex(arr, prop, value) { | |
|   // use native findIndex if supported | |
|   if (Array.prototype.findIndex) { | |
|     return arr.findIndex(cur => cur[prop] === value); | |
|   } | |
| 
 | |
|   // use `find` + `indexOf` if `findIndex` isn't supported | |
|   const match = find(arr, obj => obj[prop] === value); | |
|   return arr.indexOf(match); | |
| } | |
| 
 | |
| /** | |
|  * Get the position of the given element, relative to its offset parent | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @param {Element} element | |
|  * @return {Object} position - Coordinates of the element and its `scrollTop` | |
|  */ | |
| function getOffsetRect(element) { | |
|   let elementRect; | |
|   if (element.nodeName === 'HTML') { | |
|     const { width, height } = getWindowSizes(); | |
|     elementRect = { | |
|       width, | |
|       height, | |
|       left: 0, | |
|       top: 0 | |
|     }; | |
|   } else { | |
|     elementRect = { | |
|       width: element.offsetWidth, | |
|       height: element.offsetHeight, | |
|       left: element.offsetLeft, | |
|       top: element.offsetTop | |
|     }; | |
|   } | |
| 
 | |
|   // position | |
|   return getClientRect(elementRect); | |
| } | |
| 
 | |
| /** | |
|  * Get the outer sizes of the given element (offset size + margins) | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Element} element | |
|  * @returns {Object} object containing width and height properties | |
|  */ | |
| function getOuterSizes(element) { | |
|   const styles = getComputedStyle(element); | |
|   const x = parseFloat(styles.marginTop) + parseFloat(styles.marginBottom); | |
|   const y = parseFloat(styles.marginLeft) + parseFloat(styles.marginRight); | |
|   const result = { | |
|     width: element.offsetWidth + y, | |
|     height: element.offsetHeight + x | |
|   }; | |
|   return result; | |
| } | |
| 
 | |
| /** | |
|  * Get the opposite placement of the given one | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {String} placement | |
|  * @returns {String} flipped placement | |
|  */ | |
| function getOppositePlacement(placement) { | |
|   const hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' }; | |
|   return placement.replace(/left|right|bottom|top/g, matched => hash[matched]); | |
| } | |
| 
 | |
| /** | |
|  * Get offsets to the popper | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @param {Object} position - CSS position the Popper will get applied | |
|  * @param {HTMLElement} popper - the popper element | |
|  * @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this) | |
|  * @param {String} placement - one of the valid placement options | |
|  * @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper | |
|  */ | |
| function getPopperOffsets(popper, referenceOffsets, placement) { | |
|   placement = placement.split('-')[0]; | |
| 
 | |
|   // Get popper node sizes | |
|   const popperRect = getOuterSizes(popper); | |
| 
 | |
|   // Add position, width and height to our offsets object | |
|   const popperOffsets = { | |
|     width: popperRect.width, | |
|     height: popperRect.height | |
|   }; | |
| 
 | |
|   // depending by the popper placement we have to compute its offsets slightly differently | |
|   const isHoriz = ['right', 'left'].indexOf(placement) !== -1; | |
|   const mainSide = isHoriz ? 'top' : 'left'; | |
|   const secondarySide = isHoriz ? 'left' : 'top'; | |
|   const measurement = isHoriz ? 'height' : 'width'; | |
|   const secondaryMeasurement = !isHoriz ? 'height' : 'width'; | |
| 
 | |
|   popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2; | |
|   if (placement === secondarySide) { | |
|     popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement]; | |
|   } else { | |
|     popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)]; | |
|   } | |
| 
 | |
|   return popperOffsets; | |
| } | |
| 
 | |
| /** | |
|  * Get offsets to the reference element | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @param {Object} state | |
|  * @param {Element} popper - the popper element | |
|  * @param {Element} reference - the reference element (the popper will be relative to this) | |
|  * @returns {Object} An object containing the offsets which will be applied to the popper | |
|  */ | |
| function getReferenceOffsets(state, popper, reference) { | |
|   const commonOffsetParent = findCommonOffsetParent(popper, reference); | |
|   return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent); | |
| } | |
| 
 | |
| /** | |
|  * Get the prefixed supported property name | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {String} property (camelCase) | |
|  * @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix) | |
|  */ | |
| function getSupportedPropertyName(property) { | |
|   const prefixes = [false, 'ms', 'Webkit', 'Moz', 'O']; | |
|   const upperProp = property.charAt(0).toUpperCase() + property.slice(1); | |
| 
 | |
|   for (let i = 0; i < prefixes.length - 1; i++) { | |
|     const prefix = prefixes[i]; | |
|     const toCheck = prefix ? `${prefix}${upperProp}` : property; | |
|     if (typeof document.body.style[toCheck] !== 'undefined') { | |
|       return toCheck; | |
|     } | |
|   } | |
|   return null; | |
| } | |
| 
 | |
| /** | |
|  * Check if the given variable is a function | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Any} functionToCheck - variable to check | |
|  * @returns {Boolean} answer to: is a function? | |
|  */ | |
| function isFunction(functionToCheck) { | |
|   const getType = {}; | |
|   return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; | |
| } | |
| 
 | |
| /** | |
|  * Helper used to know if the given modifier is enabled. | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @returns {Boolean} | |
|  */ | |
| function isModifierEnabled(modifiers, modifierName) { | |
|   return modifiers.some(({ name, enabled }) => enabled && name === modifierName); | |
| } | |
| 
 | |
| /** | |
|  * Helper used to know if the given modifier depends from another one.<br /> | |
|  * It checks if the needed modifier is listed and enabled. | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @param {Array} modifiers - list of modifiers | |
|  * @param {String} requestingName - name of requesting modifier | |
|  * @param {String} requestedName - name of requested modifier | |
|  * @returns {Boolean} | |
|  */ | |
| function isModifierRequired(modifiers, requestingName, requestedName) { | |
|   const requesting = find(modifiers, ({ name }) => name === requestingName); | |
| 
 | |
|   const isRequired = !!requesting && modifiers.some(modifier => { | |
|     return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order; | |
|   }); | |
| 
 | |
|   if (!isRequired) { | |
|     const requesting = `\`${requestingName}\``; | |
|     const requested = `\`${requestedName}\``; | |
|     console.warn(`${requested} modifier is required by ${requesting} modifier in order to work, be sure to include it before ${requesting}!`); | |
|   } | |
|   return isRequired; | |
| } | |
| 
 | |
| /** | |
|  * Tells if a given input is a number | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @param {*} input to check | |
|  * @return {Boolean} | |
|  */ | |
| function isNumeric(n) { | |
|   return n !== '' && !isNaN(parseFloat(n)) && isFinite(n); | |
| } | |
| 
 | |
| /** | |
|  * Get the window associated with the element | |
|  * @argument {Element} element | |
|  * @returns {Window} | |
|  */ | |
| function getWindow(element) { | |
|   const ownerDocument = element.ownerDocument; | |
|   return ownerDocument ? ownerDocument.defaultView : window; | |
| } | |
| 
 | |
| /** | |
|  * Remove event listeners used to update the popper position | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @private | |
|  */ | |
| function removeEventListeners(reference, state) { | |
|   // Remove resize event listener on window | |
|   getWindow(reference).removeEventListener('resize', state.updateBound); | |
| 
 | |
|   // Remove scroll event listener on scroll parents | |
|   state.scrollParents.forEach(target => { | |
|     target.removeEventListener('scroll', state.updateBound); | |
|   }); | |
| 
 | |
|   // Reset state | |
|   state.updateBound = null; | |
|   state.scrollParents = []; | |
|   state.scrollElement = null; | |
|   state.eventsEnabled = false; | |
|   return state; | |
| } | |
| 
 | |
| /** | |
|  * Loop trough the list of modifiers and run them in order, | |
|  * each of them will then edit the data object. | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @param {dataObject} data | |
|  * @param {Array} modifiers | |
|  * @param {String} ends - Optional modifier name used as stopper | |
|  * @returns {dataObject} | |
|  */ | |
| function runModifiers(modifiers, data, ends) { | |
|   const modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends)); | |
| 
 | |
|   modifiersToRun.forEach(modifier => { | |
|     if (modifier['function']) { | |
|       // eslint-disable-line dot-notation | |
|       console.warn('`modifier.function` is deprecated, use `modifier.fn`!'); | |
|     } | |
|     const fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation | |
|     if (modifier.enabled && isFunction(fn)) { | |
|       // Add properties to offsets to make them a complete clientRect object | |
|       // we do this before each modifier to make sure the previous one doesn't | |
|       // mess with these values | |
|       data.offsets.popper = getClientRect(data.offsets.popper); | |
|       data.offsets.reference = getClientRect(data.offsets.reference); | |
| 
 | |
|       data = fn(data, modifier); | |
|     } | |
|   }); | |
| 
 | |
|   return data; | |
| } | |
| 
 | |
| /** | |
|  * Set the attributes to the given popper | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Element} element - Element to apply the attributes to | |
|  * @argument {Object} styles | |
|  * Object with a list of properties and values which will be applied to the element | |
|  */ | |
| function setAttributes(element, attributes) { | |
|   Object.keys(attributes).forEach(function (prop) { | |
|     const value = attributes[prop]; | |
|     if (value !== false) { | |
|       element.setAttribute(prop, attributes[prop]); | |
|     } else { | |
|       element.removeAttribute(prop); | |
|     } | |
|   }); | |
| } | |
| 
 | |
| /** | |
|  * Set the style to the given popper | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @argument {Element} element - Element to apply the style to | |
|  * @argument {Object} styles | |
|  * Object with a list of properties and values which will be applied to the element | |
|  */ | |
| function setStyles(element, styles) { | |
|   Object.keys(styles).forEach(prop => { | |
|     let unit = ''; | |
|     // add unit if the value is numeric and is one of the following | |
|     if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) { | |
|       unit = 'px'; | |
|     } | |
|     element.style[prop] = styles[prop] + unit; | |
|   }); | |
| } | |
| 
 | |
| function attachToScrollParents(scrollParent, event, callback, scrollParents) { | |
|   const isBody = scrollParent.nodeName === 'BODY'; | |
|   const target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent; | |
|   target.addEventListener(event, callback, { passive: true }); | |
| 
 | |
|   if (!isBody) { | |
|     attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents); | |
|   } | |
|   scrollParents.push(target); | |
| } | |
| 
 | |
| /** | |
|  * Setup needed event listeners used to update the popper position | |
|  * @method | |
|  * @memberof Popper.Utils | |
|  * @private | |
|  */ | |
| function setupEventListeners(reference, options, state, updateBound) { | |
|   // Resize event listener on window | |
|   state.updateBound = updateBound; | |
|   getWindow(reference).addEventListener('resize', state.updateBound, { passive: true }); | |
| 
 | |
|   // Scroll event listener on scroll parents | |
|   const scrollElement = getScrollParent(reference); | |
|   attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents); | |
|   state.scrollElement = scrollElement; | |
|   state.eventsEnabled = true; | |
| 
 | |
|   return state; | |
| } | |
| 
 | |
| // This is here just for backward compatibility with versions lower than v1.10.3 | |
| // you should import the utilities using named exports, if you want them all use: | |
| // ``` | |
| // import * as PopperUtils from 'popper-utils'; | |
| // ``` | |
| // The default export will be removed in the next major version. | |
| var index = { | |
|   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 | |
| }; | |
| 
 | |
| export { 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 }; | |
| export default index; | |
| //# sourceMappingURL=popper-utils.js.map
 |