a1d9d8c5468a30d1fbb70a1e3bc522d92a533de3
[moodle.git] / admin / tool / usertours / amd / src / popper.js
1 /**!
2  * @fileOverview Kickass library to create and place poppers near their reference elements.
3  * @version 1.0.8
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 (function (global, factory) {
26         typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
27         typeof define === 'function' && define.amd ? define(factory) :
28         (global.Popper = factory());
29 }(this, (function () { 'use strict';
31 /**
32  * Returns the offset parent of the given element
33  * @method
34  * @memberof Popper.Utils
35  * @argument {Element} element
36  * @returns {Element} offset parent
37  */
38 function getOffsetParent(element) {
39     // NOTE: 1 DOM access here
40     var offsetParent = element.offsetParent;
41     var nodeName = offsetParent && offsetParent.nodeName;
43     if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {
44         return window.document.documentElement;
45     }
47     return offsetParent;
48 }
50 /**
51  * Get CSS computed property of the given element
52  * @method
53  * @memberof Popper.Utils
54  * @argument {Eement} element
55  * @argument {String} property
56  */
57 function getStyleComputedProperty(element, property) {
58     if (element.nodeType !== 1) {
59         return [];
60     }
61     // NOTE: 1 DOM access here
62     var css = window.getComputedStyle(element, null);
63     return property ? css[property] : css;
64 }
66 /**
67  * Returns the parentNode or the host of the element
68  * @method
69  * @memberof Popper.Utils
70  * @argument {Element} element
71  * @returns {Element} parent
72  */
73 function getParentNode(element) {
74     if (element.nodeName === 'HTML') {
75         return element;
76     }
77     return element.parentNode || element.host;
78 }
80 /**
81  * Returns the scrolling parent of the given element
82  * @method
83  * @memberof Popper.Utils
84  * @argument {Element} element
85  * @returns {Element} scroll parent
86  */
87 function getScrollParent(element) {
88     // Return body, `getScroll` will take care to get the correct `scrollTop` from it
89     if (!element || ['HTML', 'BODY', '#document'].indexOf(element.nodeName) !== -1) {
90         return window.document.body;
91     }
93     // Firefox want us to check `-x` and `-y` variations as well
95     var _getStyleComputedProp = getStyleComputedProperty(element),
96         overflow = _getStyleComputedProp.overflow,
97         overflowX = _getStyleComputedProp.overflowX,
98         overflowY = _getStyleComputedProp.overflowY;
100     if (/(auto|scroll)/.test(overflow + overflowY + overflowX)) {
101         return element;
102     }
104     return getScrollParent(getParentNode(element));
107 /**
108  * Check if the given element is fixed or is inside a fixed parent
109  * @method
110  * @memberof Popper.Utils
111  * @argument {Element} element
112  * @argument {Element} customContainer
113  * @returns {Boolean} answer to "isFixed?"
114  */
115 function isFixed(element) {
116     var nodeName = element.nodeName;
117     if (nodeName === 'BODY' || nodeName === 'HTML') {
118         return false;
119     }
120     if (getStyleComputedProperty(element, 'position') === 'fixed') {
121         return true;
122     }
123     return isFixed(getParentNode(element));
126 /**
127  * Helper used to get the position which will be applied to the popper
128  * @method
129  * @memberof Popper.Utils
130  * @param {HTMLElement} element - popper element
131  * @returns {String} position
132  */
133 function getPosition(element) {
134   var container = getOffsetParent(element);
136   // Decide if the popper will be fixed
137   // If the reference element is inside a fixed context, the popper will be fixed as well to allow them to scroll together
138   var isParentFixed = isFixed(container);
139   return isParentFixed ? 'fixed' : 'absolute';
142 /*
143  * Helper to detect borders of a given element
144  * @method
145  * @memberof Popper.Utils
146  * @param {CSSStyleDeclaration} styles - result of `getStyleComputedProperty` on the given element
147  * @param {String} axis - `x` or `y`
148  * @return {Number} borders - the borders size of the given axis
149  */
151 function getBordersSize(styles, axis) {
152   var sideA = axis === 'x' ? 'Left' : 'Top';
153   var sideB = sideA === 'Left' ? 'Right' : 'Bottom';
155   return Number(styles['border' + sideA + 'Width'].split('px')[0]) + Number(styles['border' + sideB + 'Width'].split('px')[0]);
158 /**
159  * Get bounding client rect of given element
160  * @method
161  * @memberof Popper.Utils
162  * @param {HTMLElement} element
163  * @return {Object} client rect
164  */
165 function getBoundingClientRect(element) {
166     var isIE10 = navigator.appVersion.indexOf('MSIE 10') !== -1;
167     var rect = void 0;
169     // IE10 10 FIX: Please, don't ask, the element isn't
170     // considered in DOM in some circumstances...
171     // This isn't reproducible in IE10 compatibility mode of IE11
172     if (isIE10) {
173         try {
174             rect = element.getBoundingClientRect();
175         } catch (err) {
176             rect = {};
177         }
178     } else {
179         rect = element.getBoundingClientRect();
180     }
182     var result = {
183         left: rect.left,
184         top: rect.top,
185         right: rect.right,
186         bottom: rect.bottom,
187         width: rect.right - rect.left,
188         height: rect.bottom - rect.top
189     };
191     // IE10 FIX: `getBoundingClientRect`, when executed on `documentElement`
192     // will not take in account the `scrollTop` and `scrollLeft`
193     if (element.nodeName === 'HTML' && isIE10) {
194         var _window$document$docu = window.document.documentElement,
195             scrollTop = _window$document$docu.scrollTop,
196             scrollLeft = _window$document$docu.scrollLeft;
198         result.top -= scrollTop;
199         result.bottom -= scrollTop;
200         result.left -= scrollLeft;
201         result.right -= scrollLeft;
202     }
204     // subtract scrollbar size from sizes
205     var horizScrollbar = rect.width - (element.clientWidth || rect.right - rect.left);
206     var vertScrollbar = rect.height - (element.clientHeight || rect.bottom - rect.top);
208     // if an hypothetical scrollbar is detected, we must be sure it's not a `border`
209     // we make this check conditional for performance reasons
210     if (horizScrollbar || vertScrollbar) {
211         var styles = getStyleComputedProperty(element);
212         horizScrollbar -= getBordersSize(styles, 'x');
213         vertScrollbar -= getBordersSize(styles, 'y');
214     }
216     result.right -= horizScrollbar;
217     result.width -= horizScrollbar;
218     result.bottom -= vertScrollbar;
219     result.height -= vertScrollbar;
221     return result;
224 function getScroll(element) {
225     var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top';
227     var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft';
228     var nodeName = element.nodeName;
230     if (nodeName === 'BODY' || nodeName === 'HTML') {
231         var html = window.document.documentElement;
232         var scrollingElement = window.document.scrollingElement || html;
233         return scrollingElement[upperSide];
234     }
236     return element[upperSide];
239 /*
240  * Sum or subtract the element scroll values (left and top) from a given rect object
241  * @method
242  * @memberof Popper.Utils
243  * @param {Object} rect - Rect object you want to change
244  * @param {HTMLElement} element - The element from the function reads the scroll values
245  * @param {Boolean} subtract - set to true if you want to subtract the scroll values
246  * @return {Object} rect - The modifier rect object
247  */
248 function includeScroll(rect, element) {
249   var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
251   var scrollTop = getScroll(element, 'top');
252   var scrollLeft = getScroll(element, 'left');
253   var modifier = subtract ? -1 : 1;
254   rect.top += scrollTop * modifier;
255   rect.bottom += scrollTop * modifier;
256   rect.left += scrollLeft * modifier;
257   rect.right += scrollLeft * modifier;
258   return rect;
261 /**
262  * Given an element and one of its parents, return the offset
263  * @method
264  * @memberof Popper.Utils
265  * @param {HTMLElement} element
266  * @param {HTMLElement} parent
267  * @return {Object} rect
268  */
269 function getOffsetRectRelativeToCustomParent(element, parent) {
270     var fixed = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
271     var transformed = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
273     var scrollParent = getScrollParent(parent);
274     var elementRect = getBoundingClientRect(element);
275     var parentRect = getBoundingClientRect(parent);
277     var rect = {
278         top: elementRect.top - parentRect.top,
279         left: elementRect.left - parentRect.left,
280         bottom: elementRect.top - parentRect.top + elementRect.height,
281         right: elementRect.left - parentRect.left + elementRect.width,
282         width: elementRect.width,
283         height: elementRect.height
284     };
286     if (fixed && !transformed) {
287         rect = includeScroll(rect, scrollParent, true);
288     }
289     // When a popper doesn't have any positioned or scrollable parents, `offsetParent.contains(scrollParent)`
290     // will return a "false positive". This is happening because `getOffsetParent` returns `html` node,
291     // and `scrollParent` is the `body` node. Hence the additional check.
292     else if (getOffsetParent(element).contains(scrollParent) && scrollParent.nodeName !== 'BODY') {
293             rect = includeScroll(rect, parent);
294         }
296     // subtract borderTopWidth and borderTopWidth from final result
297     var styles = getStyleComputedProperty(parent);
298     var borderTopWidth = Number(styles.borderTopWidth.split('px')[0]);
299     var borderLeftWidth = Number(styles.borderLeftWidth.split('px')[0]);
301     rect.top -= borderTopWidth;
302     rect.bottom -= borderTopWidth;
303     rect.left -= borderLeftWidth;
304     rect.right -= borderLeftWidth;
306     return rect;
309 function getWindowSizes() {
310     var body = window.document.body;
311     var html = window.document.documentElement;
312     return {
313         height: Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),
314         width: Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth)
315     };
318 /**
319  * Get the position of the given element, relative to its offset parent
320  * @method
321  * @memberof Popper.Utils
322  * @param {Element} element
323  * @return {Object} position - Coordinates of the element and its `scrollTop`
324  */
325 function getOffsetRect(element) {
326     var elementRect = void 0;
327     if (element.nodeName === 'HTML') {
328         var _getWindowSizes = getWindowSizes(),
329             width = _getWindowSizes.width,
330             height = _getWindowSizes.height;
332         elementRect = {
333             width: width,
334             height: height,
335             left: 0,
336             top: 0
337         };
338     } else {
339         elementRect = {
340             width: element.offsetWidth,
341             height: element.offsetHeight,
342             left: element.offsetLeft,
343             top: element.offsetTop
344         };
345     }
347     elementRect.right = elementRect.left + elementRect.width;
348     elementRect.bottom = elementRect.top + elementRect.height;
350     // position
351     return elementRect;
354 function getOffsetRectRelativeToViewport(element) {
355     // Offset relative to offsetParent
356     var relativeOffset = getOffsetRect(element);
358     if (element.nodeName !== 'HTML') {
359         var offsetParent = getOffsetParent(element);
360         var parentOffset = getOffsetRectRelativeToViewport(offsetParent);
361         var offset = {
362             width: relativeOffset.offsetWidth,
363             height: relativeOffset.offsetHeight,
364             left: relativeOffset.left + parentOffset.left,
365             top: relativeOffset.top + parentOffset.top,
366             right: relativeOffset.right - parentOffset.right,
367             bottom: relativeOffset.bottom - parentOffset.bottom
368         };
369         return offset;
370     }
372     return relativeOffset;
375 function getTotalScroll(element) {
376     var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top';
378     var scrollParent = getScrollParent(element);
379     var scroll = getScroll(scrollParent, side);
381     if (['BODY', 'HTML'].indexOf(scrollParent.nodeName) === -1) {
382         return scroll + getTotalScroll(getParentNode(scrollParent), side);
383     }
384     return scroll;
387 /**
388  * Computed the boundaries limits and return them
389  * @method
390  * @memberof Popper.Utils
391  * @param {Object} data - Object containing the property "offsets" generated by `_getOffsets`
392  * @param {Number} padding - Boundaries padding
393  * @param {Element} boundariesElement - Element used to define the boundaries
394  * @returns {Object} Coordinates of the boundaries
395  */
396 function getBoundaries(popper, padding, boundariesElement) {
397     // NOTE: 1 DOM access here
398     var boundaries = { top: 0, left: 0 };
399     var offsetParent = getOffsetParent(popper);
401     // Handle viewport case
402     if (boundariesElement === 'viewport') {
403         var _getOffsetRectRelativ = getOffsetRectRelativeToViewport(offsetParent),
404             left = _getOffsetRectRelativ.left,
405             top = _getOffsetRectRelativ.top;
407         var _window$document$docu = window.document.documentElement,
408             width = _window$document$docu.clientWidth,
409             height = _window$document$docu.clientHeight;
412         if (getPosition(popper) === 'fixed') {
413             boundaries.right = width;
414             boundaries.bottom = height;
415         } else {
416             var scrollLeft = getTotalScroll(popper, 'left');
417             var scrollTop = getTotalScroll(popper, 'top');
419             boundaries = {
420                 top: 0 - top,
421                 right: width - left + scrollLeft,
422                 bottom: height - top + scrollTop,
423                 left: 0 - left
424             };
425         }
426     }
427     // Handle other cases based on DOM element used as boundaries
428     else {
429             var boundariesNode = void 0;
430             if (boundariesElement === 'scrollParent') {
431                 boundariesNode = getScrollParent(getParentNode(popper));
432             } else if (boundariesElement === 'window') {
433                 boundariesNode = window.document.body;
434             } else {
435                 boundariesNode = boundariesElement;
436             }
438             // In case of BODY, we need a different computation
439             if (boundariesNode.nodeName === 'BODY') {
440                 var _getWindowSizes = getWindowSizes(),
441                     _height = _getWindowSizes.height,
442                     _width = _getWindowSizes.width;
444                 boundaries.right = _width;
445                 boundaries.bottom = _height;
446             }
447             // for all the other DOM elements, this one is good
448             else {
449                     boundaries = getOffsetRectRelativeToCustomParent(boundariesNode, offsetParent, isFixed(popper));
450                 }
451         }
453     // Add paddings
454     boundaries.left += padding;
455     boundaries.top += padding;
456     boundaries.right -= padding;
457     boundaries.bottom -= padding;
459     return boundaries;
462 /**
463  * Utility used to transform the `auto` placement to the placement with more
464  * available space.
465  * @method
466  * @memberof Popper.Utils
467  * @argument {Object} data - The data object generated by update method
468  * @argument {Object} options - Modifiers configuration and options
469  * @returns {Object} The data object, properly modified
470  */
471 function computeAutoPlacement(placement, refRect, popper) {
472     if (placement.indexOf('auto') === -1) {
473         return placement;
474     }
476     var boundaries = getBoundaries(popper, 0, 'scrollParent');
478     var sides = {
479         top: refRect.top - boundaries.top,
480         right: boundaries.right - refRect.right,
481         bottom: boundaries.bottom - refRect.bottom,
482         left: refRect.left - boundaries.left
483     };
485     var computedPlacement = Object.keys(sides).sort(function (a, b) {
486         return sides[b] - sides[a];
487     })[0];
488     var variation = placement.split('-')[1];
490     return computedPlacement + (variation ? '-' + variation : '');
493 var nativeHints = ['native code', '[object MutationObserverConstructor]' // for mobile safari iOS 9.0
494 ];
496 /**
497  * Determine if a function is implemented natively (as opposed to a polyfill).
498  * @argument {Function | undefined} fn the function to check
499  * @returns {boolean}
500  */
501 var isNative = (function (fn) {
502   return nativeHints.some(function (hint) {
503     return (fn || '').toString().indexOf(hint) > -1;
504   });
505 });
507 var isBrowser = typeof window !== 'undefined';
508 var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];
509 var timeoutDuration = 0;
510 for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) {
511     if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {
512         timeoutDuration = 1;
513         break;
514     }
517 function microtaskDebounce(fn) {
518     var scheduled = false;
519     var i = 0;
520     var elem = document.createElement('span');
522     // MutationObserver provides a mechanism for scheduling microtasks, which
523     // are scheduled *before* the next task. This gives us a way to debounce
524     // a function but ensure it's called *before* the next paint.
525     var observer = new MutationObserver(function () {
526         fn();
527         scheduled = false;
528     });
530     observer.observe(elem, { attributes: true });
532     return function () {
533         if (!scheduled) {
534             scheduled = true;
535             elem.setAttribute('x-index', i);
536             i = i + 1; // don't use compund (+=) because it doesn't get optimized in V8
537         }
538     };
541 function taskDebounce(fn) {
542     var scheduled = false;
543     return function () {
544         if (!scheduled) {
545             scheduled = true;
546             setTimeout(function () {
547                 scheduled = false;
548                 fn();
549             }, timeoutDuration);
550         }
551     };
554 // It's common for MutationObserver polyfills to be seen in the wild, however
555 // these rely on Mutation Events which only occur when an element is connected
556 // to the DOM. The algorithm used in this module does not use a connected element,
557 // and so we must ensure that a *native* MutationObserver is available.
558 var supportsNativeMutationObserver = isBrowser && isNative(window.MutationObserver);
560 /**
561 * Create a debounced version of a method, that's asynchronously deferred
562 * but called in the minimum time possible.
564 * @method
565 * @memberof Popper.Utils
566 * @argument {Function} fn
567 * @returns {Function}
568 */
569 var debounce = supportsNativeMutationObserver ? microtaskDebounce : taskDebounce;
571 /**
572  * Mimics the `find` method of Array
573  * @method
574  * @memberof Popper.Utils
575  * @argument {Array} arr
576  * @argument prop
577  * @argument value
578  * @returns index or -1
579  */
580 function find(arr, check) {
581     // use native find if supported
582     if (Array.prototype.find) {
583         return arr.find(check);
584     }
586     // use `filter` to obtain the same behavior of `find`
587     return arr.filter(check)[0];
590 /**
591  * Return the index of the matching object
592  * @method
593  * @memberof Popper.Utils
594  * @argument {Array} arr
595  * @argument prop
596  * @argument value
597  * @returns index or -1
598  */
599 function findIndex(arr, prop, value) {
600     // use native findIndex if supported
601     if (Array.prototype.findIndex) {
602         return arr.findIndex(function (cur) {
603             return cur[prop] === value;
604         });
605     }
607     // use `find` + `indexOf` if `findIndex` isn't supported
608     var match = find(arr, function (obj) {
609         return obj[prop] === value;
610     });
611     return arr.indexOf(match);
614 var classCallCheck = function (instance, Constructor) {
615   if (!(instance instanceof Constructor)) {
616     throw new TypeError("Cannot call a class as a function");
617   }
618 };
620 var createClass = function () {
621   function defineProperties(target, props) {
622     for (var i = 0; i < props.length; i++) {
623       var descriptor = props[i];
624       descriptor.enumerable = descriptor.enumerable || false;
625       descriptor.configurable = true;
626       if ("value" in descriptor) descriptor.writable = true;
627       Object.defineProperty(target, descriptor.key, descriptor);
628     }
629   }
631   return function (Constructor, protoProps, staticProps) {
632     if (protoProps) defineProperties(Constructor.prototype, protoProps);
633     if (staticProps) defineProperties(Constructor, staticProps);
634     return Constructor;
635   };
636 }();
642 var defineProperty = function (obj, key, value) {
643   if (key in obj) {
644     Object.defineProperty(obj, key, {
645       value: value,
646       enumerable: true,
647       configurable: true,
648       writable: true
649     });
650   } else {
651     obj[key] = value;
652   }
654   return obj;
655 };
657 var _extends = Object.assign || function (target) {
658   for (var i = 1; i < arguments.length; i++) {
659     var source = arguments[i];
661     for (var key in source) {
662       if (Object.prototype.hasOwnProperty.call(source, key)) {
663         target[key] = source[key];
664       }
665     }
666   }
668   return target;
669 };
671 /**
672  * Given the popper offsets, generate an output similar to getBoundingClientRect
673  * @method
674  * @memberof Popper.Utils
675  * @argument {Object} popperOffsets
676  * @returns {Object} ClientRect like output
677  */
678 function getClientRect(popperOffsets) {
679     return _extends({}, popperOffsets, {
680         right: popperOffsets.left + popperOffsets.width,
681         bottom: popperOffsets.top + popperOffsets.height
682     });
685 /**
686  * Get the outer sizes of the given element (offset size + margins)
687  * @method
688  * @memberof Popper.Utils
689  * @argument {Element} element
690  * @returns {Object} object containing width and height properties
691  */
692 function getOuterSizes(element) {
693     var styles = window.getComputedStyle(element);
694     var x = parseFloat(styles.marginTop) + parseFloat(styles.marginBottom);
695     var y = parseFloat(styles.marginLeft) + parseFloat(styles.marginRight);
696     var result = {
697         width: element.offsetWidth + y,
698         height: element.offsetHeight + x
699     };
700     return result;
703 /**
704  * Get the opposite placement of the given one/
705  * @method
706  * @memberof Popper.Utils
707  * @argument {String} placement
708  * @returns {String} flipped placement
709  */
710 function getOppositePlacement(placement) {
711   var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' };
712   return placement.replace(/left|right|bottom|top/g, function (matched) {
713     return hash[matched];
714   });
717 /**
718  * Get offsets to the popper
719  * @method
720  * @memberof Popper.Utils
721  * @param {Object} position - CSS position the Popper will get applied
722  * @param {HTMLElement} popper - the popper element
723  * @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this)
724  * @param {String} placement - one of the valid placement options
725  * @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper
726  */
727 function getPopperOffsets(position, popper, referenceOffsets, placement) {
728     placement = placement.split('-')[0];
730     // Get popper node sizes
731     var popperRect = getOuterSizes(popper);
733     // Add position, width and height to our offsets object
734     var popperOffsets = {
735         position: position,
736         width: popperRect.width,
737         height: popperRect.height
738     };
740     // depending by the popper placement we have to compute its offsets slightly differently
741     var isHoriz = ['right', 'left'].indexOf(placement) !== -1;
742     var mainSide = isHoriz ? 'top' : 'left';
743     var secondarySide = isHoriz ? 'left' : 'top';
744     var measurement = isHoriz ? 'height' : 'width';
745     var secondaryMeasurement = !isHoriz ? 'height' : 'width';
747     popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2;
748     if (placement === secondarySide) {
749         popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement];
750     } else {
751         popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)];
752     }
754     return popperOffsets;
757 /**
758  * Get offsets to the reference element
759  * @method
760  * @memberof Popper.Utils
761  * @param {Object} state
762  * @param {Element} popper - the popper element
763  * @param {Element} reference - the reference element (the popper will be relative to this)
764  * @returns {Object} An object containing the offsets which will be applied to the popper
765  */
766 function getReferenceOffsets(state, popper, reference) {
767   var isParentFixed = state.position === 'fixed';
768   var isParentTransformed = state.isParentTransformed;
769   var offsetParent = getOffsetParent(isParentFixed && isParentTransformed ? reference : popper);
771   return getOffsetRectRelativeToCustomParent(reference, offsetParent, isParentFixed, isParentTransformed);
774 /**
775  * Get the prefixed supported property name
776  * @method
777  * @memberof Popper.Utils
778  * @argument {String} property (camelCase)
779  * @returns {String} prefixed property (camelCase)
780  */
781 function getSupportedPropertyName(property) {
782     var prefixes = [false, 'ms', 'webkit', 'moz', 'o'];
783     var upperProp = property.charAt(0).toUpperCase() + property.slice(1);
785     for (var i = 0; i < prefixes.length - 1; i++) {
786         var prefix = prefixes[i];
787         var toCheck = prefix ? '' + prefix + upperProp : property;
788         if (typeof window.document.body.style[toCheck] !== 'undefined') {
789             return toCheck;
790         }
791     }
792     return null;
795 /**
796  * Check if the given variable is a function
797  * @method
798  * @memberof Popper.Utils
799  * @argument {*} functionToCheck - variable to check
800  * @returns {Boolean} answer to: is a function?
801  */
802 function isFunction(functionToCheck) {
803   var getType = {};
804   return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
807 /**
808  * Helper used to know if the given modifier is enabled.
809  * @method
810  * @memberof Popper.Utils
811  * @returns {Boolean}
812  */
813 function isModifierEnabled(modifiers, modifierName) {
814     return modifiers.some(function (_ref) {
815         var name = _ref.name,
816             enabled = _ref.enabled;
817         return enabled && name === modifierName;
818     });
821 /**
822  * Helper used to know if the given modifier depends from another one.
823  * It checks if the needed modifier is listed and enabled.
824  * @method
825  * @memberof Popper.Utils
826  * @param {Array} modifiers - list of modifiers
827  * @param {String} requestingName - name of requesting modifier
828  * @param {String} requestedName - name of requested modifier
829  * @returns {Boolean}
830  */
831 function isModifierRequired(modifiers, requestingName, requestedName) {
832     var requesting = find(modifiers, function (_ref) {
833         var name = _ref.name;
834         return name === requestingName;
835     });
837     return !!requesting && modifiers.some(function (modifier) {
838         return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order;
839     });
842 /**
843  * Tells if a given input is a number
844  * @method
845  * @memberof Popper.Utils
846  * @param {*} input to check
847  * @return {Boolean}
848  */
849 function isNumeric(n) {
850   return n !== '' && !isNaN(parseFloat(n)) && isFinite(n);
853 /**
854  * Check if the given element has transforms applied to itself or a parent
855  * @method
856  * @memberof Popper.Utils
857  * @param  {Element} element
858  * @return {Boolean} answer to "isTransformed?"
859  */
860 function isTransformed(element) {
861     if (element.nodeName === 'BODY') {
862         return false;
863     }
864     if (getStyleComputedProperty(element, 'transform') !== 'none') {
865         return true;
866     }
867     return getParentNode(element) ? isTransformed(getParentNode(element)) : element;
870 /**
871  * Remove event listeners used to update the popper position
872  * @method
873  * @memberof Popper.Utils
874  * @private
875  */
876 function removeEventListeners(reference, state) {
877     // Remove resize event listener on window
878     window.removeEventListener('resize', state.updateBound);
880     // Remove scroll event listener on scroll parents
881     state.scrollParents.forEach(function (target) {
882         target.removeEventListener('scroll', state.updateBound);
883     });
885     // Reset state
886     state.updateBound = null;
887     state.scrollParents = [];
888     state.scrollElement = null;
889     state.eventsEnabled = false;
890     return state;
893 /**
894  * Loop trough the list of modifiers and run them in order, each of them will then edit the data object
895  * @method
896  * @memberof Popper.Utils
897  * @param {Object} data
898  * @param {Array} modifiers
899  * @param {Function} ends
900  */
901 function runModifiers(modifiers, data, ends) {
902     var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends));
904     modifiersToRun.forEach(function (modifier) {
905         if (modifier.enabled && isFunction(modifier.function)) {
906             data = modifier.function(data, modifier);
907         }
908     });
910     return data;
913 /**
914  * Set the attributes to the given popper
915  * @method
916  * @memberof Popper.Utils
917  * @argument {Element} element - Element to apply the attributes to
918  * @argument {Object} styles - Object with a list of properties and values which will be applied to the element
919  */
920 function setAttributes(element, attributes) {
921     Object.keys(attributes).forEach(function (prop) {
922         var value = attributes[prop];
923         if (value !== false) {
924             element.setAttribute(prop, attributes[prop]);
925         } else {
926             element.removeAttribute(prop);
927         }
928     });
931 /**
932  * Set the style to the given popper
933  * @method
934  * @memberof Popper.Utils
935  * @argument {Element} element - Element to apply the style to
936  * @argument {Object} styles - Object with a list of properties and values which will be applied to the element
937  */
938 function setStyles(element, styles) {
939     Object.keys(styles).forEach(function (prop) {
940         var unit = '';
941         // add unit if the value is numeric and is one of the following
942         if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) {
943             unit = 'px';
944         }
945         element.style[prop] = styles[prop] + unit;
946     });
949 function attachToScrollParents(scrollParent, event, callback, scrollParents) {
950     var isBody = scrollParent.nodeName === 'BODY';
951     var target = isBody ? window : scrollParent;
952     target.addEventListener(event, callback, { passive: true });
954     if (!isBody) {
955         attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents);
956     }
957     scrollParents.push(target);
960 /**
961  * Setup needed event listeners used to update the popper position
962  * @method
963  * @memberof Popper.Utils
964  * @private
965  */
966 function setupEventListeners(reference, options, state, updateBound) {
967     // Resize event listener on window
968     state.updateBound = updateBound;
969     window.addEventListener('resize', state.updateBound, { passive: true });
971     // Scroll event listener on scroll parents
972     var scrollElement = getScrollParent(reference);
973     attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents);
974     state.scrollElement = scrollElement;
975     state.eventsEnabled = true;
977     return state;
980 /** @namespace Popper.Utils */
981 var Utils = {
982     computeAutoPlacement: computeAutoPlacement,
983     debounce: debounce,
984     findIndex: findIndex,
985     getBordersSize: getBordersSize,
986     getBoundaries: getBoundaries,
987     getBoundingClientRect: getBoundingClientRect,
988     getClientRect: getClientRect,
989     getOffsetParent: getOffsetParent,
990     getOffsetRect: getOffsetRect,
991     getOffsetRectRelativeToCustomParent: getOffsetRectRelativeToCustomParent,
992     getOuterSizes: getOuterSizes,
993     getParentNode: getParentNode,
994     getPopperOffsets: getPopperOffsets,
995     getPosition: getPosition,
996     getReferenceOffsets: getReferenceOffsets,
997     getScroll: getScroll,
998     getScrollParent: getScrollParent,
999     getStyleComputedProperty: getStyleComputedProperty,
1000     getSupportedPropertyName: getSupportedPropertyName,
1001     getTotalScroll: getTotalScroll,
1002     getWindowSizes: getWindowSizes,
1003     includeScroll: includeScroll,
1004     isFixed: isFixed,
1005     isFunction: isFunction,
1006     isModifierEnabled: isModifierEnabled,
1007     isModifierRequired: isModifierRequired,
1008     isNative: isNative,
1009     isNumeric: isNumeric,
1010     isTransformed: isTransformed,
1011     removeEventListeners: removeEventListeners,
1012     runModifiers: runModifiers,
1013     setAttributes: setAttributes,
1014     setStyles: setStyles,
1015     setupEventListeners: setupEventListeners
1016 };
1018 /**
1019  * Apply the computed styles to the popper element
1020  * @method
1021  * @memberof Modifiers
1022  * @argument {Object} data - The data object generated by `update` method
1023  * @argument {Object} data.styles - List of style properties - values to apply to popper element
1024  * @argument {Object} data.attributes - List of attribute properties - values to apply to popper element
1025  * @argument {Object} options - Modifiers configuration and options
1026  * @returns {Object} The same data object
1027  */
1028 function applyStyle(data, options) {
1029     // apply the final offsets to the popper
1030     // NOTE: 1 DOM access here
1031     var styles = {
1032         position: data.offsets.popper.position
1033     };
1035     var attributes = {
1036         'x-placement': data.placement
1037     };
1039     // round top and left to avoid blurry text
1040     var left = Math.round(data.offsets.popper.left);
1041     var top = Math.round(data.offsets.popper.top);
1043     // if gpuAcceleration is set to true and transform is supported,
1044     //  we use `translate3d` to apply the position to the popper we
1045     // automatically use the supported prefixed version if needed
1046     var prefixedProperty = getSupportedPropertyName('transform');
1047     if (options.gpuAcceleration && prefixedProperty) {
1048         styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)';
1049         styles.top = 0;
1050         styles.left = 0;
1051         styles.willChange = 'transform';
1052     }
1053     // othwerise, we use the standard `left` and `top` properties
1054     else {
1055             styles.left = left;
1056             styles.top = top;
1057             styles.willChange = 'top, left';
1058         }
1060     // any property present in `data.styles` will be applied to the popper,
1061     // in this way we can make the 3rd party modifiers add custom styles to it
1062     // Be aware, modifiers could override the properties defined in the previous
1063     // lines of this modifier!
1064     setStyles(data.instance.popper, _extends({}, styles, data.styles));
1066     // any property present in `data.attributes` will be applied to the popper,
1067     // they will be set as HTML attributes of the element
1068     setAttributes(data.instance.popper, _extends({}, attributes, data.attributes));
1070     // if the arrow style has been computed, apply the arrow style
1071     if (data.offsets.arrow) {
1072         setStyles(data.arrowElement, data.offsets.arrow);
1073     }
1075     return data;
1078 /**
1079  * Set the x-placement attribute before everything else because it could be used to add margins to the popper
1080  * margins needs to be calculated to get the correct popper offsets
1081  * @method
1082  * @memberof Popper.modifiers
1083  * @param {HTMLElement} reference - The reference element used to position the popper
1084  * @param {HTMLElement} popper - The HTML element used as popper.
1085  * @param {Object} options - Popper.js options
1086  */
1087 function applyStyleOnLoad(reference, popper, options, modifierOptions, state) {
1088     // compute reference element offsets
1089     var referenceOffsets = getReferenceOffsets(state, popper, reference);
1091     // compute auto placement, store placement inside the data object,
1092     // modifiers will be able to edit `placement` if needed
1093     // and refer to originalPlacement to know the original value
1094     options.placement = computeAutoPlacement(options.placement, referenceOffsets, popper);
1096     popper.setAttribute('x-placement', options.placement);
1097     return options;
1100 /**
1101  * Modifier used to move the arrowElements on the edge of the popper to make sure them are always between the popper and the reference element
1102  * It will use the CSS outer size of the arrowElement element to know how many pixels of conjuction are needed
1103  * @method
1104  * @memberof Modifiers
1105  * @argument {Object} data - The data object generated by update method
1106  * @argument {Object} options - Modifiers configuration and options
1107  * @returns {Object} The data object, properly modified
1108  */
1109 function arrow(data, options) {
1110     // arrow depends on keepTogether in order to work
1111     if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) {
1112         console.warn('WARNING: `keepTogether` modifier is required by arrow modifier in order to work, be sure to include it before `arrow`!');
1113         return data;
1114     }
1116     var arrowElement = options.element;
1118     // if arrowElement is a string, suppose it's a CSS selector
1119     if (typeof arrowElement === 'string') {
1120         arrowElement = data.instance.popper.querySelector(arrowElement);
1122         // if arrowElement is not found, don't run the modifier
1123         if (!arrowElement) {
1124             return data;
1125         }
1126     } else {
1127         // if the arrowElement isn't a query selector we must check that the
1128         // provided DOM node is child of its popper node
1129         if (!data.instance.popper.contains(arrowElement)) {
1130             console.warn('WARNING: `arrow.element` must be child of its popper element!');
1131             return data;
1132         }
1133     }
1135     var placement = data.placement.split('-')[0];
1136     var popper = getClientRect(data.offsets.popper);
1137     var reference = data.offsets.reference;
1138     var isVertical = ['left', 'right'].indexOf(placement) !== -1;
1140     var len = isVertical ? 'height' : 'width';
1141     var side = isVertical ? 'top' : 'left';
1142     var altSide = isVertical ? 'left' : 'top';
1143     var opSide = isVertical ? 'bottom' : 'right';
1144     var arrowElementSize = getOuterSizes(arrowElement)[len];
1146     //
1147     // extends keepTogether behavior making sure the popper and its reference have enough pixels in conjuction
1148     //
1150     // top/left side
1151     if (reference[opSide] - arrowElementSize < popper[side]) {
1152         data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize);
1153     }
1154     // bottom/right side
1155     if (reference[side] + arrowElementSize > popper[opSide]) {
1156         data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide];
1157     }
1159     // compute center of the popper
1160     var center = reference[side] + reference[len] / 2 - arrowElementSize / 2;
1162     // Compute the sideValue using the updated popper offsets
1163     var sideValue = center - getClientRect(data.offsets.popper)[side];
1165     // prevent arrowElement from being placed not contiguously to its popper
1166     sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0);
1168     data.arrowElement = arrowElement;
1169     data.offsets.arrow = {};
1170     data.offsets.arrow[side] = sideValue;
1171     data.offsets.arrow[altSide] = ''; // make sure to unset any eventual altSide value from the DOM node
1173     return data;
1176 /**
1177  * Get the opposite placement variation of the given one/
1178  * @method
1179  * @memberof Popper.Utils
1180  * @argument {String} placement variation
1181  * @returns {String} flipped placement variation
1182  */
1183 function getOppositeVariation(variation) {
1184     if (variation === 'end') {
1185         return 'start';
1186     } else if (variation === 'start') {
1187         return 'end';
1188     }
1189     return variation;
1192 /**
1193  * Modifier used to flip the placement of the popper when the latter is starting overlapping its reference element.
1194  * Requires the `preventOverflow` modifier before it in order to work.
1195  * **NOTE:** data.instance modifier will run all its previous modifiers everytime it tries to flip the popper!
1196  * @method
1197  * @memberof Modifiers
1198  * @argument {Object} data - The data object generated by update method
1199  * @argument {Object} options - Modifiers configuration and options
1200  * @returns {Object} The data object, properly modified
1201  */
1202 function flip(data, options) {
1203     // if `inner` modifier is enabled, we can't use the `flip` modifier
1204     if (isModifierEnabled(data.instance.modifiers, 'inner')) {
1205         return data;
1206     }
1208     if (data.flipped && data.placement === data.originalPlacement) {
1209         // seems like flip is trying to loop, probably there's not enough space on any of the flippable sides
1210         return data;
1211     }
1213     var boundaries = getBoundaries(data.instance.popper, options.padding, options.boundariesElement);
1215     var placement = data.placement.split('-')[0];
1216     var placementOpposite = getOppositePlacement(placement);
1217     var variation = data.placement.split('-')[1] || '';
1219     var flipOrder = [];
1221     if (options.behavior === 'flip') {
1222         flipOrder = [placement, placementOpposite];
1223     } else {
1224         flipOrder = options.behavior;
1225     }
1227     flipOrder.forEach(function (step, index) {
1228         if (placement !== step || flipOrder.length === index + 1) {
1229             return data;
1230         }
1232         placement = data.placement.split('-')[0];
1233         placementOpposite = getOppositePlacement(placement);
1235         var popperOffsets = getClientRect(data.offsets.popper);
1236         var refOffsets = data.offsets.reference;
1238         // using floor because the reference offsets may contain decimals we are not going to consider here
1239         var floor = Math.floor;
1240         var overlapsRef = placement === 'left' && floor(popperOffsets.right) > floor(refOffsets.left) || placement === 'right' && floor(popperOffsets.left) < floor(refOffsets.right) || placement === 'top' && floor(popperOffsets.bottom) > floor(refOffsets.top) || placement === 'bottom' && floor(popperOffsets.top) < floor(refOffsets.bottom);
1242         var overflowsLeft = floor(popperOffsets.left) < floor(boundaries.left);
1243         var overflowsRight = floor(popperOffsets.right) > floor(boundaries.right);
1244         var overflowsTop = floor(popperOffsets.top) < floor(boundaries.top);
1245         var overflowsBottom = floor(popperOffsets.bottom) > floor(boundaries.bottom);
1247         var overflowsBoundaries = placement === 'left' && overflowsLeft || placement === 'right' && overflowsRight || placement === 'top' && overflowsTop || placement === 'bottom' && overflowsBottom;
1249         // flip the variation if required
1250         var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
1251         var flippedVariation = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom);
1253         if (overlapsRef || overflowsBoundaries || flippedVariation) {
1254             // this boolean to detect any flip loop
1255             data.flipped = true;
1257             if (overlapsRef || overflowsBoundaries) {
1258                 placement = flipOrder[index + 1];
1259             }
1261             if (flippedVariation) {
1262                 variation = getOppositeVariation(variation);
1263             }
1265             data.placement = placement + (variation ? '-' + variation : '');
1266             data.offsets.popper = getPopperOffsets(data.instance.state.position, data.instance.popper, data.offsets.reference, data.placement);
1268             data = runModifiers(data.instance.modifiers, data, 'flip');
1269         }
1270     });
1271     return data;
1274 /**
1275  * Modifier used to make sure the popper is always near its reference element
1276  * It cares only about the first axis, you can still have poppers with margin
1277  * between the popper and its reference element.
1278  * @method
1279  * @memberof Modifiers
1280  * @argument {Object} data - The data object generated by update method
1281  * @argument {Object} options - Modifiers configuration and options
1282  * @returns {Object} The data object, properly modified
1283  */
1284 function keepTogether(data) {
1285     var popper = getClientRect(data.offsets.popper);
1286     var reference = data.offsets.reference;
1287     var placement = data.placement.split('-')[0];
1288     var floor = Math.floor;
1289     var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
1290     var side = isVertical ? 'right' : 'bottom';
1291     var opSide = isVertical ? 'left' : 'top';
1292     var measurement = isVertical ? 'width' : 'height';
1294     if (popper[side] < floor(reference[opSide])) {
1295         data.offsets.popper[opSide] = floor(reference[opSide]) - popper[measurement];
1296     }
1297     if (popper[opSide] > floor(reference[side])) {
1298         data.offsets.popper[opSide] = floor(reference[side]);
1299     }
1301     return data;
1304 /**
1305  * Modifier used to add an offset to the popper, useful if you more granularity positioning your popper.
1306  * The offsets will shift the popper on the side of its reference element.
1307  * @method
1308  * @memberof Modifiers
1309  * @argument {Object} data - The data object generated by update method
1310  * @argument {Object} options - Modifiers configuration and options
1311  * @argument {Number|String} options.offset=0
1312  *      Basic usage allows a number used to nudge the popper by the given amount of pixels.
1313  *      You can pass a percentage value as string (eg. `20%`) to nudge by the given percentage (relative to reference element size)
1314  *      Other supported units are `vh` and `vw` (relative to viewport)
1315  *      Additionally, you can pass a pair of values (eg. `10 20` or `2vh 20%`) to nudge the popper
1316  *      on both axis.
1317  *      A note about percentage values, if you want to refer a percentage to the popper size instead of the reference element size,
1318  *      use `%p` instead of `%` (eg: `20%p`). To make it clearer, you can replace `%` with `%r` and use eg.`10%p 25%r`.
1319  *      > **Heads up!** The order of the axis is relative to the popper placement: `bottom` or `top` are `X,Y`, the other are `Y,X`
1320  * @returns {Object} The data object, properly modified
1321  */
1322 function offset(data, options) {
1323     var placement = data.placement;
1324     var popper = data.offsets.popper;
1326     var offsets = void 0;
1327     if (isNumeric(options.offset)) {
1328         offsets = [options.offset, 0];
1329     } else {
1330         // split the offset in case we are providing a pair of offsets separated
1331         // by a blank space
1332         offsets = options.offset.split(' ');
1334         // itherate through each offset to compute them in case they are percentages
1335         offsets = offsets.map(function (offset, index) {
1336             // separate value from unit
1337             var split = offset.match(/(\d*\.?\d*)(.*)/);
1338             var value = +split[1];
1339             var unit = split[2];
1341             // use height if placement is left or right and index is 0 otherwise use width
1342             // in this way the first offset will use an axis and the second one
1343             // will use the other one
1344             var useHeight = placement.indexOf('right') !== -1 || placement.indexOf('left') !== -1;
1346             if (index === 1) {
1347                 useHeight = !useHeight;
1348             }
1350             var measurement = useHeight ? 'height' : 'width';
1352             // if is a percentage relative to the popper (%p), we calculate the value of it using
1353             // as base the sizes of the popper
1354             // if is a percentage (% or %r), we calculate the value of it using as base the
1355             // sizes of the reference element
1356             if (unit.indexOf('%') === 0) {
1357                 var element = void 0;
1358                 switch (unit) {
1359                     case '%p':
1360                         element = data.offsets.popper;
1361                         break;
1362                     case '%':
1363                     case '$r':
1364                     default:
1365                         element = data.offsets.reference;
1366                 }
1368                 var rect = getClientRect(element);
1369                 var len = rect[measurement];
1370                 return len / 100 * value;
1371             }
1372             // if is a vh or vw, we calculate the size based on the viewport
1373             else if (unit === 'vh' || unit === 'vw') {
1374                     var size = void 0;
1375                     if (unit === 'vh') {
1376                         size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
1377                     } else {
1378                         size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
1379                     }
1380                     return size / 100 * value;
1381                 }
1382                 // if is an explicit pixel unit, we get rid of the unit and keep the value
1383                 else if (unit === 'px') {
1384                         return +value;
1385                     }
1386                     // if is an implicit unit, it's px, and we return just the value
1387                     else {
1388                             return +offset;
1389                         }
1390         });
1391     }
1393     if (data.placement.indexOf('left') !== -1) {
1394         popper.top += offsets[0];
1395         popper.left -= offsets[1] || 0;
1396     } else if (data.placement.indexOf('right') !== -1) {
1397         popper.top += offsets[0];
1398         popper.left += offsets[1] || 0;
1399     } else if (data.placement.indexOf('top') !== -1) {
1400         popper.left += offsets[0];
1401         popper.top -= offsets[1] || 0;
1402     } else if (data.placement.indexOf('bottom') !== -1) {
1403         popper.left += offsets[0];
1404         popper.top += offsets[1] || 0;
1405     }
1406     return data;
1409 /**
1410  * Modifier used to prevent the popper from being positioned outside the boundary.
1411  *
1412  * An scenario exists where the reference itself is not within the boundaries. We can
1413  * say it has "escaped the boundaries" — or just "escaped". In this case we need to
1414  * decide whether the popper should either:
1415  *
1416  * - detach from the reference and remain "trapped" in the boundaries, or
1417  * - if it should be ignore the boundary and "escape with the reference"
1418  *
1419  * When `escapeWithReference` is `true`, and reference is completely outside the
1420  * boundaries, the popper will overflow (or completely leave) the boundaries in order
1421  * to remain attached to the edge of the reference.
1422  *
1423  * @method
1424  * @memberof Modifiers
1425  * @argument {Object} data - The data object generated by `update` method
1426  * @argument {Object} options - Modifiers configuration and options
1427  * @returns {Object} The data object, properly modified
1428  */
1429 function preventOverflow(data, options) {
1430     var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper);
1431     var boundaries = getBoundaries(data.instance.popper, options.padding, boundariesElement);
1432     options.boundaries = boundaries;
1434     var order = options.priority;
1435     var popper = getClientRect(data.offsets.popper);
1437     var check = {
1438         primary: function primary(placement) {
1439             var value = popper[placement];
1440             if (popper[placement] < boundaries[placement] && !options.escapeWithReference) {
1441                 value = Math.max(popper[placement], boundaries[placement]);
1442             }
1443             return defineProperty({}, placement, value);
1444         },
1445         secondary: function secondary(placement) {
1446             var mainSide = placement === 'right' ? 'left' : 'top';
1447             var value = popper[mainSide];
1448             if (popper[placement] > boundaries[placement] && !options.escapeWithReference) {
1449                 value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height));
1450             }
1451             return defineProperty({}, mainSide, value);
1452         }
1453     };
1455     order.forEach(function (placement) {
1456         var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary';
1457         popper = _extends({}, popper, check[side](placement));
1458     });
1460     data.offsets.popper = popper;
1462     return data;
1465 /**
1466  * Modifier used to shift the popper on the start or end of its reference element side
1467  * @method
1468  * @memberof Modifiers
1469  * @argument {Object} data - The data object generated by `update` method
1470  * @argument {Object} options - Modifiers configuration and options
1471  * @returns {Object} The data object, properly modified
1472  */
1473 function shift(data) {
1474     var placement = data.placement;
1475     var basePlacement = placement.split('-')[0];
1476     var shiftvariation = placement.split('-')[1];
1478     // if shift shiftvariation is specified, run the modifier
1479     if (shiftvariation) {
1480         var reference = data.offsets.reference;
1481         var popper = getClientRect(data.offsets.popper);
1482         var isVertical = ['bottom', 'top'].indexOf(basePlacement) !== -1;
1483         var side = isVertical ? 'left' : 'top';
1484         var measurement = isVertical ? 'width' : 'height';
1486         var shiftOffsets = {
1487             start: defineProperty({}, side, reference[side]),
1488             end: defineProperty({}, side, reference[side] + reference[measurement] - popper[measurement])
1489         };
1491         data.offsets.popper = _extends({}, popper, shiftOffsets[shiftvariation]);
1492     }
1494     return data;
1497 /**
1498  * Modifier used to hide the popper when its reference element is outside of the
1499  * popper boundaries. It will set an x-hidden attribute which can be used to hide
1500  * the popper when its reference is out of boundaries.
1501  * @method
1502  * @memberof Modifiers
1503  * @argument {Object} data - The data object generated by update method
1504  * @argument {Object} options - Modifiers configuration and options
1505  * @returns {Object} The data object, properly modified
1506  */
1507 function hide(data) {
1508     if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) {
1509         console.warn('WARNING: preventOverflow modifier is required by hide modifier in order to work, be sure to include it before hide!');
1510         return data;
1511     }
1513     var refRect = data.offsets.reference;
1514     var bound = find(data.instance.modifiers, function (modifier) {
1515         return modifier.name === 'preventOverflow';
1516     }).boundaries;
1518     if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) {
1519         // Avoid unnecessary DOM access if visibility hasn't changed
1520         if (data.hide === true) {
1521             return data;
1522         }
1524         data.hide = true;
1525         data.attributes['x-out-of-boundaries'] = '';
1526     } else {
1527         // Avoid unnecessary DOM access if visibility hasn't changed
1528         if (data.hide === false) {
1529             return data;
1530         }
1532         data.hide = false;
1533         data.attributes['x-out-of-boundaries'] = false;
1534     }
1536     return data;
1539 /**
1540  * Modifier used to make the popper flow toward the inner of the reference element.
1541  * By default, when this modifier is disabled, the popper will be placed outside
1542  * the reference element.
1543  * @method
1544  * @memberof Modifiers
1545  * @argument {Object} data - The data object generated by `update` method
1546  * @argument {Object} options - Modifiers configuration and options
1547  * @returns {Object} The data object, properly modified
1548  */
1549 function inner(data) {
1550     var placement = data.placement;
1551     var basePlacement = placement.split('-')[0];
1552     var popper = getClientRect(data.offsets.popper);
1553     var reference = getClientRect(data.offsets.reference);
1554     var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1;
1556     var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1;
1558     popper[isHoriz ? 'left' : 'top'] = reference[placement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0);
1560     data.placement = getOppositePlacement(placement);
1561     data.offsets.popper = getClientRect(popper);
1563     return data;
1566 /**
1567  * Modifiers are plugins used to alter the behavior of your poppers.
1568  * Popper.js uses a set of 7 modifiers to provide all the basic functionalities
1569  * needed by the library.
1570  *
1571  * Each modifier is an object containing several properties listed below.
1572  * @namespace Modifiers
1573  * @param {Object} modifier - Modifier descriptor
1574  * @param {Integer} modifier.order
1575  *      The `order` property defines the execution order of the modifiers.
1576  *      The built-in modifiers have orders with a gap of 100 units in between,
1577  *      this allows you to inject additional modifiers between the existing ones
1578  *      without having to redefine the order of all of them.
1579  *      The modifiers are executed starting from the one with the lowest order.
1580  * @param {Boolean} modifier.enabled - When `true`, the modifier will be used.
1581  * @param {Modifiers~modifier} modifier.function - Modifier function.
1582  * @param {Modifiers~onLoad} modifier.onLoad - Function executed on popper initalization
1583  * @return {Object} data - Each modifier must return the modified `data` object.
1584  */
1585 var modifiers = {
1586   shift: {
1587     order: 100,
1588     enabled: true,
1589     function: shift
1590   },
1591   offset: {
1592     order: 200,
1593     enabled: true,
1594     function: offset,
1595     // nudges popper from its origin by the given amount of pixels (can be negative)
1596     offset: 0
1597   },
1598   preventOverflow: {
1599     order: 300,
1600     enabled: true,
1601     function: preventOverflow,
1602     // popper will try to prevent overflow following these priorities
1603     //  by default, then, it could overflow on the left and on top of the boundariesElement
1604     priority: ['left', 'right', 'top', 'bottom'],
1605     // amount of pixel used to define a minimum distance between the boundaries and the popper
1606     // this makes sure the popper has always a little padding between the edges of its container
1607     padding: 5,
1608     boundariesElement: 'scrollParent'
1609   },
1610   keepTogether: {
1611     order: 400,
1612     enabled: true,
1613     function: keepTogether
1614   },
1615   arrow: {
1616     order: 500,
1617     enabled: true,
1618     function: arrow,
1619     // selector or node used as arrow
1620     element: '[x-arrow]'
1621   },
1622   flip: {
1623     order: 600,
1624     enabled: true,
1625     function: flip,
1626     // the behavior used to change the popper's placement
1627     behavior: 'flip',
1628     // the popper will flip if it hits the edges of the boundariesElement - padding
1629     padding: 5,
1630     boundariesElement: 'viewport'
1631   },
1632   inner: {
1633     order: 700,
1634     enabled: false,
1635     function: inner
1636   },
1637   hide: {
1638     order: 800,
1639     enabled: true,
1640     function: hide
1641   },
1642   applyStyle: {
1643     order: 900,
1644     enabled: true,
1645     // if true, it uses the CSS 3d transformation to position the popper
1646     gpuAcceleration: true,
1647     function: applyStyle,
1648     onLoad: applyStyleOnLoad
1649   }
1650 };
1652 /**
1653  * Modifiers can edit the `data` object to change the beheavior of the popper.
1654  * This object contains all the informations used by Popper.js to compute the
1655  * popper position.
1656  * The modifier can edit the data as needed, and then `return` it as result.
1657  *
1658  * @callback Modifiers~modifier
1659  * @param {dataObject} data
1660  * @return {dataObject} modified data
1661  */
1663 /**
1664  * The `dataObject` is an object containing all the informations used by Popper.js
1665  * this object get passed to modifiers and to the `onCreate` and `onUpdate` callbacks.
1666  * @name dataObject
1667  * @property {Object} data.instance The Popper.js instance
1668  * @property {String} data.placement Placement applied to popper
1669  * @property {String} data.originalPlacement Placement originally defined on init
1670  * @property {Boolean} data.flipped True if popper has been flipped by flip modifier
1671  * @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper.
1672  * @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier
1673  * @property {Object} data.styles Any CSS property defined here will be applied to the popper, it expects the JavaScript nomenclature (eg. `marginBottom`)
1674  * @property {Object} data.boundaries Offsets of the popper boundaries
1675  * @property {Object} data.offsets The measurements of popper, reference and arrow elements.
1676  * @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values
1677  * @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values
1678  * @property {Object} data.offsets.arro] `top` and `left` offsets, only one of them will be different from 0
1679  */
1681 // Utils
1682 // Modifiers
1683 // default options
1684 var DEFAULTS = {
1685     // placement of the popper
1686     placement: 'bottom',
1688     // whether events (resize, scroll) are initially enabled
1689     eventsEnabled: true,
1691     /**
1692      * Callback called when the popper is created.
1693      * By default, is set to no-op.
1694      * Access Popper.js instance with `data.instance`.
1695      * @callback createCallback
1696      * @static
1697      * @param {dataObject} data
1698      */
1699     onCreate: function onCreate() {},
1701     /**
1702      * Callback called when the popper is updated, this callback is not called
1703      * on the initialization/creation of the popper, but only on subsequent
1704      * updates.
1705      * By default, is set to no-op.
1706      * Access Popper.js instance with `data.instance`.
1707      * @callback updateCallback
1708      * @static
1709      * @param {dataObject} data
1710      */
1711     onUpdate: function onUpdate() {},
1713     // list of functions used to modify the offsets before they are applied to the popper
1714     modifiers: modifiers
1715 };
1717 /**
1718  * Create a new Popper.js instance
1719  * @class Popper
1720  * @param {HTMLElement} reference - The reference element used to position the popper
1721  * @param {HTMLElement} popper - The HTML element used as popper.
1722  * @param {Object} options
1723  * @param {String} options.placement=bottom
1724  *      Placement of the popper accepted values: `top(-start, -end), right(-start, -end), bottom(-start, -end),
1725  *      left(-start, -end)`
1726  *
1727  * @param {Boolean} options.eventsEnabled=true
1728  *      Whether events (resize, scroll) are initially enabled
1729  * @param {Boolean} options.gpuAcceleration=true
1730  *      When this property is set to true, the popper position will be applied using CSS3 translate3d, allowing the
1731  *      browser to use the GPU to accelerate the rendering.
1732  *      If set to false, the popper will be placed using `top` and `left` properties, not using the GPU.
1733  *
1734  * @param {Boolean} options.removeOnDestroy=false
1735  *      Set to true if you want to automatically remove the popper when you call the `destroy` method.
1736  *
1737  * @param {Object} options.modifiers
1738  *      List of functions used to modify the data before they are applied to the popper (see source code for default values)
1739  *
1740  * @param {Object} options.modifiers.arrow - Arrow modifier configuration
1741  * @param {String|HTMLElement} options.modifiers.arrow.element='[x-arrow]'
1742  *      The DOM Node used as arrow for the popper, or a CSS selector used to get the DOM node. It must be child of
1743  *      its parent Popper. Popper.js will apply to the given element the style required to align the arrow with its
1744  *      reference element.
1745  *      By default, it will look for a child node of the popper with the `x-arrow` attribute.
1746  *
1747  * @param {Object} options.modifiers.offset - Offset modifier configuration
1748  * @param {Number} options.modifiers.offset.offset=0
1749  *      Amount of pixels the popper will be shifted (can be negative).
1750  *
1751  * @param {Object} options.modifiers.preventOverflow - PreventOverflow modifier configuration
1752  * @param {Array} [options.modifiers.preventOverflow.priority=['left', 'right', 'top', 'bottom']]
1753  *      Priority used when Popper.js tries to avoid overflows from the boundaries, they will be checked in order,
1754  *      this means that the last one will never overflow
1755  * @param {String|HTMLElement} options.modifiers.preventOverflow.boundariesElement='scrollParent'
1756  *      Boundaries used by the modifier, can be `scrollParent`, `window`, `viewport` or any DOM element.
1757  * @param {Number} options.modifiers.preventOverflow.padding=5
1758  *      Amount of pixel used to define a minimum distance between the boundaries and the popper
1759  *      this makes sure the popper has always a little padding between the edges of its container.
1760  *
1761  * @param {Object} options.modifiers.flip - Flip modifier configuration
1762  * @param {String|Array} options.modifiers.flip.behavior='flip'
1763  *      The behavior used by the `flip` modifier to change the placement of the popper when the latter is trying to
1764  *      overlap its reference element. Defining `flip` as value, the placement will be flipped on
1765  *      its axis (`right - left`, `top - bottom`).
1766  *      You can even pass an array of placements (eg: `['right', 'left', 'top']` ) to manually specify
1767  *      how alter the placement when a flip is needed. (eg. in the above example, it would first flip from right to left,
1768  *      then, if even in its new placement, the popper is overlapping its reference element, it will be moved to top)
1769  * @param {String|HTMLElement} options.modifiers.flip.boundariesElement='viewport'
1770  *      The element which will define the boundaries of the popper position, the popper will never be placed outside
1771  *      of the defined boundaries (except if `keepTogether` is enabled)
1772  *
1773  * @param {Object} options.modifiers.inner - Inner modifier configuration
1774  * @param {Number} options.modifiers.inner.enabled=false
1775  *      Set to `true` to make the popper flow toward the inner of the reference element.
1776  *
1777  * @param {Number} options.modifiers.flip.padding=5
1778  *      Amount of pixel used to define a minimum distance between the boundaries and the popper
1779  *      this makes sure the popper has always a little padding between the edges of its container.
1780  *
1781  * @param {createCallback} options.onCreate - onCreate callback
1782  *      Function called after the Popper has been instantiated.
1783  *
1784  * @param {updateCallback} options.onUpdate - onUpdate callback
1785  *      Function called on subsequent updates of Popper.
1786  *
1787  * @return {Object} instance - The generated Popper.js instance
1788  */
1790 var Popper = function () {
1791     function Popper(reference, popper) {
1792         var _this = this;
1794         var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
1795         classCallCheck(this, Popper);
1797         this.scheduleUpdate = function () {
1798             return requestAnimationFrame(_this.update);
1799         };
1801         // make update() debounced, so that it only runs at most once-per-tick
1802         this.update = debounce(this.update.bind(this));
1804         // with {} we create a new object with the options inside it
1805         this.options = _extends({}, Popper.Defaults, options);
1807         // init state
1808         this.state = {
1809             isDestroyed: false,
1810             isCreated: false,
1811             scrollParents: []
1812         };
1814         // get reference and popper elements (allow jQuery wrappers)
1815         this.reference = reference.jquery ? reference[0] : reference;
1816         this.popper = popper.jquery ? popper[0] : popper;
1818         // refactoring modifiers' list (Object => Array)
1819         this.modifiers = Object.keys(Popper.Defaults.modifiers).map(function (name) {
1820             return _extends({ name: name }, Popper.Defaults.modifiers[name]);
1821         });
1823         // assign default values to modifiers, making sure to override them with
1824         // the ones defined by user
1825         this.modifiers = this.modifiers.map(function (defaultConfig) {
1826             var userConfig = options.modifiers && options.modifiers[defaultConfig.name] || {};
1827             return _extends({}, defaultConfig, userConfig);
1828         });
1830         // add custom modifiers to the modifiers list
1831         if (options.modifiers) {
1832             this.options.modifiers = _extends({}, Popper.Defaults.modifiers, options.modifiers);
1833             Object.keys(options.modifiers).forEach(function (name) {
1834                 // take in account only custom modifiers
1835                 if (Popper.Defaults.modifiers[name] === undefined) {
1836                     var modifier = options.modifiers[name];
1837                     modifier.name = name;
1838                     _this.modifiers.push(modifier);
1839                 }
1840             });
1841         }
1843         // get the popper position type
1844         this.state.position = getPosition(this.reference);
1846         // sort the modifiers by order
1847         this.modifiers = this.modifiers.sort(function (a, b) {
1848             return a.order - b.order;
1849         });
1851         // modifiers have the ability to execute arbitrary code when Popper.js get inited
1852         // such code is executed in the same order of its modifier
1853         // they could add new properties to their options configuration
1854         // BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`!
1855         this.modifiers.forEach(function (modifierOptions) {
1856             if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) {
1857                 modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state);
1858             }
1859         });
1861         // determine how we should set the origin of offsets
1862         this.state.isParentTransformed = isTransformed(this.popper.parentNode);
1864         // fire the first update to position the popper in the right place
1865         this.update();
1867         var eventsEnabled = this.options.eventsEnabled;
1868         if (eventsEnabled) {
1869             // setup event listeners, they will take care of update the position in specific situations
1870             this.enableEventListeners();
1871         }
1873         this.state.eventsEnabled = eventsEnabled;
1874     }
1876     //
1877     // Methods
1878     //
1880     /**
1881      * Updates the position of the popper, computing the new offsets and applying the new style
1882      * Prefer `scheduleUpdate` over `update` because of performance reasons
1883      * @method
1884      * @memberof Popper
1885      */
1888     createClass(Popper, [{
1889         key: 'update',
1890         value: function update() {
1891             // if popper is destroyed, don't perform any further update
1892             if (this.state.isDestroyed) {
1893                 return;
1894             }
1896             var data = {
1897                 instance: this,
1898                 styles: {},
1899                 attributes: {},
1900                 flipped: false,
1901                 offsets: {}
1902             };
1904             // make sure to apply the popper position before any computation
1905             this.state.position = getPosition(this.reference);
1906             setStyles(this.popper, { position: this.state.position });
1908             // compute reference element offsets
1909             data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference);
1911             // compute auto placement, store placement inside the data object,
1912             // modifiers will be able to edit `placement` if needed
1913             // and refer to originalPlacement to know the original value
1914             data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper);
1916             // store the computed placement inside `originalPlacement`
1917             data.originalPlacement = this.options.placement;
1919             // compute the popper offsets
1920             data.offsets.popper = getPopperOffsets(this.state, this.popper, data.offsets.reference, data.placement);
1922             // run the modifiers
1923             data = runModifiers(this.modifiers, data);
1925             // the first `update` will call `onCreate` callback
1926             // the other ones will call `onUpdate` callback
1927             if (!this.state.isCreated) {
1928                 this.state.isCreated = true;
1929                 this.options.onCreate(data);
1930             } else {
1931                 this.options.onUpdate(data);
1932             }
1933         }
1935         /**
1936          * Schedule an update, it will run on the next UI update available
1937          * @method scheduleUpdate
1938          * @memberof Popper
1939          */
1941     }, {
1942         key: 'destroy',
1945         /**
1946          * Destroy the popper
1947          * @method
1948          * @memberof Popper
1949          */
1950         value: function destroy() {
1951             this.state.isDestroyed = true;
1953             // touch DOM only if `applyStyle` modifier is enabled
1954             if (isModifierEnabled(this.modifiers, 'applyStyle')) {
1955                 this.popper.removeAttribute('x-placement');
1956                 this.popper.style.left = '';
1957                 this.popper.style.position = '';
1958                 this.popper.style.top = '';
1959                 this.popper.style[getSupportedPropertyName('transform')] = '';
1960             }
1962             this.disableEventListeners();
1964             // remove the popper if user explicity asked for the deletion on destroy
1965             // do not use `remove` because IE11 doesn't support it
1966             if (this.options.removeOnDestroy) {
1967                 this.popper.parentNode.removeChild(this.popper);
1968             }
1969             return this;
1970         }
1972         /**
1973          * it will add resize/scroll events and start recalculating
1974          * position of the popper element when they are triggered
1975          * @method
1976          * @memberof Popper
1977          */
1979     }, {
1980         key: 'enableEventListeners',
1981         value: function enableEventListeners() {
1982             if (!this.state.eventsEnabled) {
1983                 this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate);
1984             }
1985         }
1987         /**
1988          * it will remove resize/scroll events and won't recalculate
1989          * popper position when they are triggered. It also won't trigger onUpdate callback anymore,
1990          * unless you call 'update' method manually.
1991          * @method
1992          * @memberof Popper
1993          */
1995     }, {
1996         key: 'disableEventListeners',
1997         value: function disableEventListeners() {
1998             if (this.state.eventsEnabled) {
1999                 window.cancelAnimationFrame(this.scheduleUpdate);
2000                 this.state = removeEventListeners(this.reference, this.state);
2001             }
2002         }
2004         /**
2005          * Collection of utilities useful when writing custom modifiers
2006          * @memberof Popper
2007          */
2010         /**
2011          * List of accepted placements to use as values of the `placement` option
2012          * @memberof Popper
2013          */
2016         /**
2017          * Default Popper.js options
2018          * @memberof Popper
2019          */
2021     }]);
2022     return Popper;
2023 }();
2025 Popper.Utils = Utils;
2026 Popper.placements = ['auto', 'auto-start', 'auto-end', 'top', 'top-start', 'top-end', 'right', 'right-start', 'right-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end'];
2027 Popper.Defaults = DEFAULTS;
2029 return Popper;
2031 })));
2032 //# sourceMappingURL=popper.es5.js.map