GPQAPP
1/**!
2* @fileOverview Kickass library to create and place poppers near their reference elements.
3* @version 1.16.1
4* @license
5* Copyright (c) 2016 Federico Zivolo and contributors
6*
7* Permission is hereby granted, free of charge, to any person obtaining a copy
8* of this software and associated documentation files (the "Software"), to deal
9* in the Software without restriction, including without limitation the rights
10* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11* copies of the Software, and to permit persons to whom the Software is
12* furnished to do so, subject to the following conditions:
13*
14* The above copyright notice and this permission notice shall be included in all
15* copies or substantial portions of the Software.
16*
17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23* SOFTWARE.
24*/
25var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && typeof navigator !== 'undefined';26
27var timeoutDuration = function () {28var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];29for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) {30if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {31return 1;32}33}34return 0;35}();36
37function microtaskDebounce(fn) {38var called = false;39return function () {40if (called) {41return;42}43called = true;44window.Promise.resolve().then(function () {45called = false;46fn();47});48};49}
50
51function taskDebounce(fn) {52var scheduled = false;53return function () {54if (!scheduled) {55scheduled = true;56setTimeout(function () {57scheduled = false;58fn();59}, timeoutDuration);60}61};62}
63
64var supportsMicroTasks = isBrowser && window.Promise;65
66/**
67* Create a debounced version of a method, that's asynchronously deferred
68* but called in the minimum time possible.
69*
70* @method
71* @memberof Popper.Utils
72* @argument {Function} fn
73* @returns {Function}
74*/
75var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce;76
77/**
78* Check if the given variable is a function
79* @method
80* @memberof Popper.Utils
81* @argument {Any} functionToCheck - variable to check
82* @returns {Boolean} answer to: is a function?
83*/
84function isFunction(functionToCheck) {85var getType = {};86return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';87}
88
89/**
90* Get CSS computed property of the given element
91* @method
92* @memberof Popper.Utils
93* @argument {Eement} element
94* @argument {String} property
95*/
96function getStyleComputedProperty(element, property) {97if (element.nodeType !== 1) {98return [];99}100// NOTE: 1 DOM access here101var window = element.ownerDocument.defaultView;102var css = window.getComputedStyle(element, null);103return property ? css[property] : css;104}
105
106/**
107* Returns the parentNode or the host of the element
108* @method
109* @memberof Popper.Utils
110* @argument {Element} element
111* @returns {Element} parent
112*/
113function getParentNode(element) {114if (element.nodeName === 'HTML') {115return element;116}117return element.parentNode || element.host;118}
119
120/**
121* Returns the scrolling parent of the given element
122* @method
123* @memberof Popper.Utils
124* @argument {Element} element
125* @returns {Element} scroll parent
126*/
127function getScrollParent(element) {128// Return body, `getScroll` will take care to get the correct `scrollTop` from it129if (!element) {130return document.body;131}132
133switch (element.nodeName) {134case 'HTML':135case 'BODY':136return element.ownerDocument.body;137case '#document':138return element.body;139}140
141// Firefox want us to check `-x` and `-y` variations as well142
143var _getStyleComputedProp = getStyleComputedProperty(element),144overflow = _getStyleComputedProp.overflow,145overflowX = _getStyleComputedProp.overflowX,146overflowY = _getStyleComputedProp.overflowY;147
148if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) {149return element;150}151
152return getScrollParent(getParentNode(element));153}
154
155/**
156* Returns the reference node of the reference object, or the reference object itself.
157* @method
158* @memberof Popper.Utils
159* @param {Element|Object} reference - the reference element (the popper will be relative to this)
160* @returns {Element} parent
161*/
162function getReferenceNode(reference) {163return reference && reference.referenceNode ? reference.referenceNode : reference;164}
165
166var isIE11 = isBrowser && !!(window.MSInputMethodContext && document.documentMode);167var isIE10 = isBrowser && /MSIE 10/.test(navigator.userAgent);168
169/**
170* Determines if the browser is Internet Explorer
171* @method
172* @memberof Popper.Utils
173* @param {Number} version to check
174* @returns {Boolean} isIE
175*/
176function isIE(version) {177if (version === 11) {178return isIE11;179}180if (version === 10) {181return isIE10;182}183return isIE11 || isIE10;184}
185
186/**
187* Returns the offset parent of the given element
188* @method
189* @memberof Popper.Utils
190* @argument {Element} element
191* @returns {Element} offset parent
192*/
193function getOffsetParent(element) {194if (!element) {195return document.documentElement;196}197
198var noOffsetParent = isIE(10) ? document.body : null;199
200// NOTE: 1 DOM access here201var offsetParent = element.offsetParent || null;202// Skip hidden elements which don't have an offsetParent203while (offsetParent === noOffsetParent && element.nextElementSibling) {204offsetParent = (element = element.nextElementSibling).offsetParent;205}206
207var nodeName = offsetParent && offsetParent.nodeName;208
209if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {210return element ? element.ownerDocument.documentElement : document.documentElement;211}212
213// .offsetParent will return the closest TH, TD or TABLE in case214// no offsetParent is present, I hate this job...215if (['TH', 'TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') {216return getOffsetParent(offsetParent);217}218
219return offsetParent;220}
221
222function isOffsetContainer(element) {223var nodeName = element.nodeName;224
225if (nodeName === 'BODY') {226return false;227}228return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element;229}
230
231/**
232* Finds the root node (document, shadowDOM root) of the given element
233* @method
234* @memberof Popper.Utils
235* @argument {Element} node
236* @returns {Element} root node
237*/
238function getRoot(node) {239if (node.parentNode !== null) {240return getRoot(node.parentNode);241}242
243return node;244}
245
246/**
247* Finds the offset parent common to the two provided nodes
248* @method
249* @memberof Popper.Utils
250* @argument {Element} element1
251* @argument {Element} element2
252* @returns {Element} common offset parent
253*/
254function findCommonOffsetParent(element1, element2) {255// This check is needed to avoid errors in case one of the elements isn't defined for any reason256if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) {257return document.documentElement;258}259
260// Here we make sure to give as "start" the element that comes first in the DOM261var order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING;262var start = order ? element1 : element2;263var end = order ? element2 : element1;264
265// Get common ancestor container266var range = document.createRange();267range.setStart(start, 0);268range.setEnd(end, 0);269var commonAncestorContainer = range.commonAncestorContainer;270
271// Both nodes are inside #document272
273if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) {274if (isOffsetContainer(commonAncestorContainer)) {275return commonAncestorContainer;276}277
278return getOffsetParent(commonAncestorContainer);279}280
281// one of the nodes is inside shadowDOM, find which one282var element1root = getRoot(element1);283if (element1root.host) {284return findCommonOffsetParent(element1root.host, element2);285} else {286return findCommonOffsetParent(element1, getRoot(element2).host);287}288}
289
290/**
291* Gets the scroll value of the given element in the given side (top and left)
292* @method
293* @memberof Popper.Utils
294* @argument {Element} element
295* @argument {String} side `top` or `left`
296* @returns {number} amount of scrolled pixels
297*/
298function getScroll(element) {299var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top';300
301var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft';302var nodeName = element.nodeName;303
304if (nodeName === 'BODY' || nodeName === 'HTML') {305var html = element.ownerDocument.documentElement;306var scrollingElement = element.ownerDocument.scrollingElement || html;307return scrollingElement[upperSide];308}309
310return element[upperSide];311}
312
313/*
314* Sum or subtract the element scroll values (left and top) from a given rect object
315* @method
316* @memberof Popper.Utils
317* @param {Object} rect - Rect object you want to change
318* @param {HTMLElement} element - The element from the function reads the scroll values
319* @param {Boolean} subtract - set to true if you want to subtract the scroll values
320* @return {Object} rect - The modifier rect object
321*/
322function includeScroll(rect, element) {323var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;324
325var scrollTop = getScroll(element, 'top');326var scrollLeft = getScroll(element, 'left');327var modifier = subtract ? -1 : 1;328rect.top += scrollTop * modifier;329rect.bottom += scrollTop * modifier;330rect.left += scrollLeft * modifier;331rect.right += scrollLeft * modifier;332return rect;333}
334
335/*
336* Helper to detect borders of a given element
337* @method
338* @memberof Popper.Utils
339* @param {CSSStyleDeclaration} styles
340* Result of `getStyleComputedProperty` on the given element
341* @param {String} axis - `x` or `y`
342* @return {number} borders - The borders size of the given axis
343*/
344
345function getBordersSize(styles, axis) {346var sideA = axis === 'x' ? 'Left' : 'Top';347var sideB = sideA === 'Left' ? 'Right' : 'Bottom';348
349return parseFloat(styles['border' + sideA + 'Width']) + parseFloat(styles['border' + sideB + 'Width']);350}
351
352function getSize(axis, body, html, computedStyle) {353return Math.max(body['offset' + axis], body['scroll' + axis], html['client' + axis], html['offset' + axis], html['scroll' + axis], isIE(10) ? parseInt(html['offset' + axis]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')]) : 0);354}
355
356function getWindowSizes(document) {357var body = document.body;358var html = document.documentElement;359var computedStyle = isIE(10) && getComputedStyle(html);360
361return {362height: getSize('Height', body, html, computedStyle),363width: getSize('Width', body, html, computedStyle)364};365}
366
367var classCallCheck = function (instance, Constructor) {368if (!(instance instanceof Constructor)) {369throw new TypeError("Cannot call a class as a function");370}371};372
373var createClass = function () {374function defineProperties(target, props) {375for (var i = 0; i < props.length; i++) {376var descriptor = props[i];377descriptor.enumerable = descriptor.enumerable || false;378descriptor.configurable = true;379if ("value" in descriptor) descriptor.writable = true;380Object.defineProperty(target, descriptor.key, descriptor);381}382}383
384return function (Constructor, protoProps, staticProps) {385if (protoProps) defineProperties(Constructor.prototype, protoProps);386if (staticProps) defineProperties(Constructor, staticProps);387return Constructor;388};389}();390
391
392
393
394
395var defineProperty = function (obj, key, value) {396if (key in obj) {397Object.defineProperty(obj, key, {398value: value,399enumerable: true,400configurable: true,401writable: true402});403} else {404obj[key] = value;405}406
407return obj;408};409
410var _extends = Object.assign || function (target) {411for (var i = 1; i < arguments.length; i++) {412var source = arguments[i];413
414for (var key in source) {415if (Object.prototype.hasOwnProperty.call(source, key)) {416target[key] = source[key];417}418}419}420
421return target;422};423
424/**
425* Given element offsets, generate an output similar to getBoundingClientRect
426* @method
427* @memberof Popper.Utils
428* @argument {Object} offsets
429* @returns {Object} ClientRect like output
430*/
431function getClientRect(offsets) {432return _extends({}, offsets, {433right: offsets.left + offsets.width,434bottom: offsets.top + offsets.height435});436}
437
438/**
439* Get bounding client rect of given element
440* @method
441* @memberof Popper.Utils
442* @param {HTMLElement} element
443* @return {Object} client rect
444*/
445function getBoundingClientRect(element) {446var rect = {};447
448// IE10 10 FIX: Please, don't ask, the element isn't449// considered in DOM in some circumstances...450// This isn't reproducible in IE10 compatibility mode of IE11451try {452if (isIE(10)) {453rect = element.getBoundingClientRect();454var scrollTop = getScroll(element, 'top');455var scrollLeft = getScroll(element, 'left');456rect.top += scrollTop;457rect.left += scrollLeft;458rect.bottom += scrollTop;459rect.right += scrollLeft;460} else {461rect = element.getBoundingClientRect();462}463} catch (e) {}464
465var result = {466left: rect.left,467top: rect.top,468width: rect.right - rect.left,469height: rect.bottom - rect.top470};471
472// subtract scrollbar size from sizes473var sizes = element.nodeName === 'HTML' ? getWindowSizes(element.ownerDocument) : {};474var width = sizes.width || element.clientWidth || result.width;475var height = sizes.height || element.clientHeight || result.height;476
477var horizScrollbar = element.offsetWidth - width;478var vertScrollbar = element.offsetHeight - height;479
480// if an hypothetical scrollbar is detected, we must be sure it's not a `border`481// we make this check conditional for performance reasons482if (horizScrollbar || vertScrollbar) {483var styles = getStyleComputedProperty(element);484horizScrollbar -= getBordersSize(styles, 'x');485vertScrollbar -= getBordersSize(styles, 'y');486
487result.width -= horizScrollbar;488result.height -= vertScrollbar;489}490
491return getClientRect(result);492}
493
494function getOffsetRectRelativeToArbitraryNode(children, parent) {495var fixedPosition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;496
497var isIE10 = isIE(10);498var isHTML = parent.nodeName === 'HTML';499var childrenRect = getBoundingClientRect(children);500var parentRect = getBoundingClientRect(parent);501var scrollParent = getScrollParent(children);502
503var styles = getStyleComputedProperty(parent);504var borderTopWidth = parseFloat(styles.borderTopWidth);505var borderLeftWidth = parseFloat(styles.borderLeftWidth);506
507// In cases where the parent is fixed, we must ignore negative scroll in offset calc508if (fixedPosition && isHTML) {509parentRect.top = Math.max(parentRect.top, 0);510parentRect.left = Math.max(parentRect.left, 0);511}512var offsets = getClientRect({513top: childrenRect.top - parentRect.top - borderTopWidth,514left: childrenRect.left - parentRect.left - borderLeftWidth,515width: childrenRect.width,516height: childrenRect.height517});518offsets.marginTop = 0;519offsets.marginLeft = 0;520
521// Subtract margins of documentElement in case it's being used as parent522// we do this only on HTML because it's the only element that behaves523// differently when margins are applied to it. The margins are included in524// the box of the documentElement, in the other cases not.525if (!isIE10 && isHTML) {526var marginTop = parseFloat(styles.marginTop);527var marginLeft = parseFloat(styles.marginLeft);528
529offsets.top -= borderTopWidth - marginTop;530offsets.bottom -= borderTopWidth - marginTop;531offsets.left -= borderLeftWidth - marginLeft;532offsets.right -= borderLeftWidth - marginLeft;533
534// Attach marginTop and marginLeft because in some circumstances we may need them535offsets.marginTop = marginTop;536offsets.marginLeft = marginLeft;537}538
539if (isIE10 && !fixedPosition ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') {540offsets = includeScroll(offsets, parent);541}542
543return offsets;544}
545
546function getViewportOffsetRectRelativeToArtbitraryNode(element) {547var excludeScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;548
549var html = element.ownerDocument.documentElement;550var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html);551var width = Math.max(html.clientWidth, window.innerWidth || 0);552var height = Math.max(html.clientHeight, window.innerHeight || 0);553
554var scrollTop = !excludeScroll ? getScroll(html) : 0;555var scrollLeft = !excludeScroll ? getScroll(html, 'left') : 0;556
557var offset = {558top: scrollTop - relativeOffset.top + relativeOffset.marginTop,559left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft,560width: width,561height: height562};563
564return getClientRect(offset);565}
566
567/**
568* Check if the given element is fixed or is inside a fixed parent
569* @method
570* @memberof Popper.Utils
571* @argument {Element} element
572* @argument {Element} customContainer
573* @returns {Boolean} answer to "isFixed?"
574*/
575function isFixed(element) {576var nodeName = element.nodeName;577if (nodeName === 'BODY' || nodeName === 'HTML') {578return false;579}580if (getStyleComputedProperty(element, 'position') === 'fixed') {581return true;582}583var parentNode = getParentNode(element);584if (!parentNode) {585return false;586}587return isFixed(parentNode);588}
589
590/**
591* Finds the first parent of an element that has a transformed property defined
592* @method
593* @memberof Popper.Utils
594* @argument {Element} element
595* @returns {Element} first transformed parent or documentElement
596*/
597
598function getFixedPositionOffsetParent(element) {599// This check is needed to avoid errors in case one of the elements isn't defined for any reason600if (!element || !element.parentElement || isIE()) {601return document.documentElement;602}603var el = element.parentElement;604while (el && getStyleComputedProperty(el, 'transform') === 'none') {605el = el.parentElement;606}607return el || document.documentElement;608}
609
610/**
611* Computed the boundaries limits and return them
612* @method
613* @memberof Popper.Utils
614* @param {HTMLElement} popper
615* @param {HTMLElement} reference
616* @param {number} padding
617* @param {HTMLElement} boundariesElement - Element used to define the boundaries
618* @param {Boolean} fixedPosition - Is in fixed position mode
619* @returns {Object} Coordinates of the boundaries
620*/
621function getBoundaries(popper, reference, padding, boundariesElement) {622var fixedPosition = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;623
624// NOTE: 1 DOM access here625
626var boundaries = { top: 0, left: 0 };627var offsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, getReferenceNode(reference));628
629// Handle viewport case630if (boundariesElement === 'viewport') {631boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent, fixedPosition);632} else {633// Handle other cases based on DOM element used as boundaries634var boundariesNode = void 0;635if (boundariesElement === 'scrollParent') {636boundariesNode = getScrollParent(getParentNode(reference));637if (boundariesNode.nodeName === 'BODY') {638boundariesNode = popper.ownerDocument.documentElement;639}640} else if (boundariesElement === 'window') {641boundariesNode = popper.ownerDocument.documentElement;642} else {643boundariesNode = boundariesElement;644}645
646var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent, fixedPosition);647
648// In case of HTML, we need a different computation649if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) {650var _getWindowSizes = getWindowSizes(popper.ownerDocument),651height = _getWindowSizes.height,652width = _getWindowSizes.width;653
654boundaries.top += offsets.top - offsets.marginTop;655boundaries.bottom = height + offsets.top;656boundaries.left += offsets.left - offsets.marginLeft;657boundaries.right = width + offsets.left;658} else {659// for all the other DOM elements, this one is good660boundaries = offsets;661}662}663
664// Add paddings665padding = padding || 0;666var isPaddingNumber = typeof padding === 'number';667boundaries.left += isPaddingNumber ? padding : padding.left || 0;668boundaries.top += isPaddingNumber ? padding : padding.top || 0;669boundaries.right -= isPaddingNumber ? padding : padding.right || 0;670boundaries.bottom -= isPaddingNumber ? padding : padding.bottom || 0;671
672return boundaries;673}
674
675function getArea(_ref) {676var width = _ref.width,677height = _ref.height;678
679return width * height;680}
681
682/**
683* Utility used to transform the `auto` placement to the placement with more
684* available space.
685* @method
686* @memberof Popper.Utils
687* @argument {Object} data - The data object generated by update method
688* @argument {Object} options - Modifiers configuration and options
689* @returns {Object} The data object, properly modified
690*/
691function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement) {692var padding = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;693
694if (placement.indexOf('auto') === -1) {695return placement;696}697
698var boundaries = getBoundaries(popper, reference, padding, boundariesElement);699
700var rects = {701top: {702width: boundaries.width,703height: refRect.top - boundaries.top704},705right: {706width: boundaries.right - refRect.right,707height: boundaries.height708},709bottom: {710width: boundaries.width,711height: boundaries.bottom - refRect.bottom712},713left: {714width: refRect.left - boundaries.left,715height: boundaries.height716}717};718
719var sortedAreas = Object.keys(rects).map(function (key) {720return _extends({721key: key722}, rects[key], {723area: getArea(rects[key])724});725}).sort(function (a, b) {726return b.area - a.area;727});728
729var filteredAreas = sortedAreas.filter(function (_ref2) {730var width = _ref2.width,731height = _ref2.height;732return width >= popper.clientWidth && height >= popper.clientHeight;733});734
735var computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key;736
737var variation = placement.split('-')[1];738
739return computedPlacement + (variation ? '-' + variation : '');740}
741
742/**
743* Get offsets to the reference element
744* @method
745* @memberof Popper.Utils
746* @param {Object} state
747* @param {Element} popper - the popper element
748* @param {Element} reference - the reference element (the popper will be relative to this)
749* @param {Element} fixedPosition - is in fixed position mode
750* @returns {Object} An object containing the offsets which will be applied to the popper
751*/
752function getReferenceOffsets(state, popper, reference) {753var fixedPosition = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;754
755var commonOffsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, getReferenceNode(reference));756return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent, fixedPosition);757}
758
759/**
760* Get the outer sizes of the given element (offset size + margins)
761* @method
762* @memberof Popper.Utils
763* @argument {Element} element
764* @returns {Object} object containing width and height properties
765*/
766function getOuterSizes(element) {767var window = element.ownerDocument.defaultView;768var styles = window.getComputedStyle(element);769var x = parseFloat(styles.marginTop || 0) + parseFloat(styles.marginBottom || 0);770var y = parseFloat(styles.marginLeft || 0) + parseFloat(styles.marginRight || 0);771var result = {772width: element.offsetWidth + y,773height: element.offsetHeight + x774};775return result;776}
777
778/**
779* Get the opposite placement of the given one
780* @method
781* @memberof Popper.Utils
782* @argument {String} placement
783* @returns {String} flipped placement
784*/
785function getOppositePlacement(placement) {786var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' };787return placement.replace(/left|right|bottom|top/g, function (matched) {788return hash[matched];789});790}
791
792/**
793* Get offsets to the popper
794* @method
795* @memberof Popper.Utils
796* @param {Object} position - CSS position the Popper will get applied
797* @param {HTMLElement} popper - the popper element
798* @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this)
799* @param {String} placement - one of the valid placement options
800* @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper
801*/
802function getPopperOffsets(popper, referenceOffsets, placement) {803placement = placement.split('-')[0];804
805// Get popper node sizes806var popperRect = getOuterSizes(popper);807
808// Add position, width and height to our offsets object809var popperOffsets = {810width: popperRect.width,811height: popperRect.height812};813
814// depending by the popper placement we have to compute its offsets slightly differently815var isHoriz = ['right', 'left'].indexOf(placement) !== -1;816var mainSide = isHoriz ? 'top' : 'left';817var secondarySide = isHoriz ? 'left' : 'top';818var measurement = isHoriz ? 'height' : 'width';819var secondaryMeasurement = !isHoriz ? 'height' : 'width';820
821popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2;822if (placement === secondarySide) {823popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement];824} else {825popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)];826}827
828return popperOffsets;829}
830
831/**
832* Mimics the `find` method of Array
833* @method
834* @memberof Popper.Utils
835* @argument {Array} arr
836* @argument prop
837* @argument value
838* @returns index or -1
839*/
840function find(arr, check) {841// use native find if supported842if (Array.prototype.find) {843return arr.find(check);844}845
846// use `filter` to obtain the same behavior of `find`847return arr.filter(check)[0];848}
849
850/**
851* Return the index of the matching object
852* @method
853* @memberof Popper.Utils
854* @argument {Array} arr
855* @argument prop
856* @argument value
857* @returns index or -1
858*/
859function findIndex(arr, prop, value) {860// use native findIndex if supported861if (Array.prototype.findIndex) {862return arr.findIndex(function (cur) {863return cur[prop] === value;864});865}866
867// use `find` + `indexOf` if `findIndex` isn't supported868var match = find(arr, function (obj) {869return obj[prop] === value;870});871return arr.indexOf(match);872}
873
874/**
875* Loop trough the list of modifiers and run them in order,
876* each of them will then edit the data object.
877* @method
878* @memberof Popper.Utils
879* @param {dataObject} data
880* @param {Array} modifiers
881* @param {String} ends - Optional modifier name used as stopper
882* @returns {dataObject}
883*/
884function runModifiers(modifiers, data, ends) {885var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends));886
887modifiersToRun.forEach(function (modifier) {888if (modifier['function']) {889// eslint-disable-line dot-notation890console.warn('`modifier.function` is deprecated, use `modifier.fn`!');891}892var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation893if (modifier.enabled && isFunction(fn)) {894// Add properties to offsets to make them a complete clientRect object895// we do this before each modifier to make sure the previous one doesn't896// mess with these values897data.offsets.popper = getClientRect(data.offsets.popper);898data.offsets.reference = getClientRect(data.offsets.reference);899
900data = fn(data, modifier);901}902});903
904return data;905}
906
907/**
908* Updates the position of the popper, computing the new offsets and applying
909* the new style.<br />
910* Prefer `scheduleUpdate` over `update` because of performance reasons.
911* @method
912* @memberof Popper
913*/
914function update() {915// if popper is destroyed, don't perform any further update916if (this.state.isDestroyed) {917return;918}919
920var data = {921instance: this,922styles: {},923arrowStyles: {},924attributes: {},925flipped: false,926offsets: {}927};928
929// compute reference element offsets930data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference, this.options.positionFixed);931
932// compute auto placement, store placement inside the data object,933// modifiers will be able to edit `placement` if needed934// and refer to originalPlacement to know the original value935data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper, this.reference, this.options.modifiers.flip.boundariesElement, this.options.modifiers.flip.padding);936
937// store the computed placement inside `originalPlacement`938data.originalPlacement = data.placement;939
940data.positionFixed = this.options.positionFixed;941
942// compute the popper offsets943data.offsets.popper = getPopperOffsets(this.popper, data.offsets.reference, data.placement);944
945data.offsets.popper.position = this.options.positionFixed ? 'fixed' : 'absolute';946
947// run the modifiers948data = runModifiers(this.modifiers, data);949
950// the first `update` will call `onCreate` callback951// the other ones will call `onUpdate` callback952if (!this.state.isCreated) {953this.state.isCreated = true;954this.options.onCreate(data);955} else {956this.options.onUpdate(data);957}958}
959
960/**
961* Helper used to know if the given modifier is enabled.
962* @method
963* @memberof Popper.Utils
964* @returns {Boolean}
965*/
966function isModifierEnabled(modifiers, modifierName) {967return modifiers.some(function (_ref) {968var name = _ref.name,969enabled = _ref.enabled;970return enabled && name === modifierName;971});972}
973
974/**
975* Get the prefixed supported property name
976* @method
977* @memberof Popper.Utils
978* @argument {String} property (camelCase)
979* @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix)
980*/
981function getSupportedPropertyName(property) {982var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O'];983var upperProp = property.charAt(0).toUpperCase() + property.slice(1);984
985for (var i = 0; i < prefixes.length; i++) {986var prefix = prefixes[i];987var toCheck = prefix ? '' + prefix + upperProp : property;988if (typeof document.body.style[toCheck] !== 'undefined') {989return toCheck;990}991}992return null;993}
994
995/**
996* Destroys the popper.
997* @method
998* @memberof Popper
999*/
1000function destroy() {1001this.state.isDestroyed = true;1002
1003// touch DOM only if `applyStyle` modifier is enabled1004if (isModifierEnabled(this.modifiers, 'applyStyle')) {1005this.popper.removeAttribute('x-placement');1006this.popper.style.position = '';1007this.popper.style.top = '';1008this.popper.style.left = '';1009this.popper.style.right = '';1010this.popper.style.bottom = '';1011this.popper.style.willChange = '';1012this.popper.style[getSupportedPropertyName('transform')] = '';1013}1014
1015this.disableEventListeners();1016
1017// remove the popper if user explicitly asked for the deletion on destroy1018// do not use `remove` because IE11 doesn't support it1019if (this.options.removeOnDestroy) {1020this.popper.parentNode.removeChild(this.popper);1021}1022return this;1023}
1024
1025/**
1026* Get the window associated with the element
1027* @argument {Element} element
1028* @returns {Window}
1029*/
1030function getWindow(element) {1031var ownerDocument = element.ownerDocument;1032return ownerDocument ? ownerDocument.defaultView : window;1033}
1034
1035function attachToScrollParents(scrollParent, event, callback, scrollParents) {1036var isBody = scrollParent.nodeName === 'BODY';1037var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent;1038target.addEventListener(event, callback, { passive: true });1039
1040if (!isBody) {1041attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents);1042}1043scrollParents.push(target);1044}
1045
1046/**
1047* Setup needed event listeners used to update the popper position
1048* @method
1049* @memberof Popper.Utils
1050* @private
1051*/
1052function setupEventListeners(reference, options, state, updateBound) {1053// Resize event listener on window1054state.updateBound = updateBound;1055getWindow(reference).addEventListener('resize', state.updateBound, { passive: true });1056
1057// Scroll event listener on scroll parents1058var scrollElement = getScrollParent(reference);1059attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents);1060state.scrollElement = scrollElement;1061state.eventsEnabled = true;1062
1063return state;1064}
1065
1066/**
1067* It will add resize/scroll events and start recalculating
1068* position of the popper element when they are triggered.
1069* @method
1070* @memberof Popper
1071*/
1072function enableEventListeners() {1073if (!this.state.eventsEnabled) {1074this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate);1075}1076}
1077
1078/**
1079* Remove event listeners used to update the popper position
1080* @method
1081* @memberof Popper.Utils
1082* @private
1083*/
1084function removeEventListeners(reference, state) {1085// Remove resize event listener on window1086getWindow(reference).removeEventListener('resize', state.updateBound);1087
1088// Remove scroll event listener on scroll parents1089state.scrollParents.forEach(function (target) {1090target.removeEventListener('scroll', state.updateBound);1091});1092
1093// Reset state1094state.updateBound = null;1095state.scrollParents = [];1096state.scrollElement = null;1097state.eventsEnabled = false;1098return state;1099}
1100
1101/**
1102* It will remove resize/scroll events and won't recalculate popper position
1103* when they are triggered. It also won't trigger `onUpdate` callback anymore,
1104* unless you call `update` method manually.
1105* @method
1106* @memberof Popper
1107*/
1108function disableEventListeners() {1109if (this.state.eventsEnabled) {1110cancelAnimationFrame(this.scheduleUpdate);1111this.state = removeEventListeners(this.reference, this.state);1112}1113}
1114
1115/**
1116* Tells if a given input is a number
1117* @method
1118* @memberof Popper.Utils
1119* @param {*} input to check
1120* @return {Boolean}
1121*/
1122function isNumeric(n) {1123return n !== '' && !isNaN(parseFloat(n)) && isFinite(n);1124}
1125
1126/**
1127* Set the style to the given popper
1128* @method
1129* @memberof Popper.Utils
1130* @argument {Element} element - Element to apply the style to
1131* @argument {Object} styles
1132* Object with a list of properties and values which will be applied to the element
1133*/
1134function setStyles(element, styles) {1135Object.keys(styles).forEach(function (prop) {1136var unit = '';1137// add unit if the value is numeric and is one of the following1138if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) {1139unit = 'px';1140}1141element.style[prop] = styles[prop] + unit;1142});1143}
1144
1145/**
1146* Set the attributes to the given popper
1147* @method
1148* @memberof Popper.Utils
1149* @argument {Element} element - Element to apply the attributes to
1150* @argument {Object} styles
1151* Object with a list of properties and values which will be applied to the element
1152*/
1153function setAttributes(element, attributes) {1154Object.keys(attributes).forEach(function (prop) {1155var value = attributes[prop];1156if (value !== false) {1157element.setAttribute(prop, attributes[prop]);1158} else {1159element.removeAttribute(prop);1160}1161});1162}
1163
1164/**
1165* @function
1166* @memberof Modifiers
1167* @argument {Object} data - The data object generated by `update` method
1168* @argument {Object} data.styles - List of style properties - values to apply to popper element
1169* @argument {Object} data.attributes - List of attribute properties - values to apply to popper element
1170* @argument {Object} options - Modifiers configuration and options
1171* @returns {Object} The same data object
1172*/
1173function applyStyle(data) {1174// any property present in `data.styles` will be applied to the popper,1175// in this way we can make the 3rd party modifiers add custom styles to it1176// Be aware, modifiers could override the properties defined in the previous1177// lines of this modifier!1178setStyles(data.instance.popper, data.styles);1179
1180// any property present in `data.attributes` will be applied to the popper,1181// they will be set as HTML attributes of the element1182setAttributes(data.instance.popper, data.attributes);1183
1184// if arrowElement is defined and arrowStyles has some properties1185if (data.arrowElement && Object.keys(data.arrowStyles).length) {1186setStyles(data.arrowElement, data.arrowStyles);1187}1188
1189return data;1190}
1191
1192/**
1193* Set the x-placement attribute before everything else because it could be used
1194* to add margins to the popper margins needs to be calculated to get the
1195* correct popper offsets.
1196* @method
1197* @memberof Popper.modifiers
1198* @param {HTMLElement} reference - The reference element used to position the popper
1199* @param {HTMLElement} popper - The HTML element used as popper
1200* @param {Object} options - Popper.js options
1201*/
1202function applyStyleOnLoad(reference, popper, options, modifierOptions, state) {1203// compute reference element offsets1204var referenceOffsets = getReferenceOffsets(state, popper, reference, options.positionFixed);1205
1206// compute auto placement, store placement inside the data object,1207// modifiers will be able to edit `placement` if needed1208// and refer to originalPlacement to know the original value1209var placement = computeAutoPlacement(options.placement, referenceOffsets, popper, reference, options.modifiers.flip.boundariesElement, options.modifiers.flip.padding);1210
1211popper.setAttribute('x-placement', placement);1212
1213// Apply `position` to popper before anything else because1214// without the position applied we can't guarantee correct computations1215setStyles(popper, { position: options.positionFixed ? 'fixed' : 'absolute' });1216
1217return options;1218}
1219
1220/**
1221* @function
1222* @memberof Popper.Utils
1223* @argument {Object} data - The data object generated by `update` method
1224* @argument {Boolean} shouldRound - If the offsets should be rounded at all
1225* @returns {Object} The popper's position offsets rounded
1226*
1227* The tale of pixel-perfect positioning. It's still not 100% perfect, but as
1228* good as it can be within reason.
1229* Discussion here: https://github.com/FezVrasta/popper.js/pull/715
1230*
1231* Low DPI screens cause a popper to be blurry if not using full pixels (Safari
1232* as well on High DPI screens).
1233*
1234* Firefox prefers no rounding for positioning and does not have blurriness on
1235* high DPI screens.
1236*
1237* Only horizontal placement and left/right values need to be considered.
1238*/
1239function getRoundedOffsets(data, shouldRound) {1240var _data$offsets = data.offsets,1241popper = _data$offsets.popper,1242reference = _data$offsets.reference;1243var round = Math.round,1244floor = Math.floor;1245
1246var noRound = function noRound(v) {1247return v;1248};1249
1250var referenceWidth = round(reference.width);1251var popperWidth = round(popper.width);1252
1253var isVertical = ['left', 'right'].indexOf(data.placement) !== -1;1254var isVariation = data.placement.indexOf('-') !== -1;1255var sameWidthParity = referenceWidth % 2 === popperWidth % 2;1256var bothOddWidth = referenceWidth % 2 === 1 && popperWidth % 2 === 1;1257
1258var horizontalToInteger = !shouldRound ? noRound : isVertical || isVariation || sameWidthParity ? round : floor;1259var verticalToInteger = !shouldRound ? noRound : round;1260
1261return {1262left: horizontalToInteger(bothOddWidth && !isVariation && shouldRound ? popper.left - 1 : popper.left),1263top: verticalToInteger(popper.top),1264bottom: verticalToInteger(popper.bottom),1265right: horizontalToInteger(popper.right)1266};1267}
1268
1269var isFirefox = isBrowser && /Firefox/i.test(navigator.userAgent);1270
1271/**
1272* @function
1273* @memberof Modifiers
1274* @argument {Object} data - The data object generated by `update` method
1275* @argument {Object} options - Modifiers configuration and options
1276* @returns {Object} The data object, properly modified
1277*/
1278function computeStyle(data, options) {1279var x = options.x,1280y = options.y;1281var popper = data.offsets.popper;1282
1283// Remove this legacy support in Popper.js v21284
1285var legacyGpuAccelerationOption = find(data.instance.modifiers, function (modifier) {1286return modifier.name === 'applyStyle';1287}).gpuAcceleration;1288if (legacyGpuAccelerationOption !== undefined) {1289console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!');1290}1291var gpuAcceleration = legacyGpuAccelerationOption !== undefined ? legacyGpuAccelerationOption : options.gpuAcceleration;1292
1293var offsetParent = getOffsetParent(data.instance.popper);1294var offsetParentRect = getBoundingClientRect(offsetParent);1295
1296// Styles1297var styles = {1298position: popper.position1299};1300
1301var offsets = getRoundedOffsets(data, window.devicePixelRatio < 2 || !isFirefox);1302
1303var sideA = x === 'bottom' ? 'top' : 'bottom';1304var sideB = y === 'right' ? 'left' : 'right';1305
1306// if gpuAcceleration is set to `true` and transform is supported,1307// we use `translate3d` to apply the position to the popper we1308// automatically use the supported prefixed version if needed1309var prefixedProperty = getSupportedPropertyName('transform');1310
1311// now, let's make a step back and look at this code closely (wtf?)1312// If the content of the popper grows once it's been positioned, it1313// may happen that the popper gets misplaced because of the new content1314// overflowing its reference element1315// To avoid this problem, we provide two options (x and y), which allow1316// the consumer to define the offset origin.1317// If we position a popper on top of a reference element, we can set1318// `x` to `top` to make the popper grow towards its top instead of1319// its bottom.1320var left = void 0,1321top = void 0;1322if (sideA === 'bottom') {1323// when offsetParent is <html> the positioning is relative to the bottom of the screen (excluding the scrollbar)1324// and not the bottom of the html element1325if (offsetParent.nodeName === 'HTML') {1326top = -offsetParent.clientHeight + offsets.bottom;1327} else {1328top = -offsetParentRect.height + offsets.bottom;1329}1330} else {1331top = offsets.top;1332}1333if (sideB === 'right') {1334if (offsetParent.nodeName === 'HTML') {1335left = -offsetParent.clientWidth + offsets.right;1336} else {1337left = -offsetParentRect.width + offsets.right;1338}1339} else {1340left = offsets.left;1341}1342if (gpuAcceleration && prefixedProperty) {1343styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)';1344styles[sideA] = 0;1345styles[sideB] = 0;1346styles.willChange = 'transform';1347} else {1348// othwerise, we use the standard `top`, `left`, `bottom` and `right` properties1349var invertTop = sideA === 'bottom' ? -1 : 1;1350var invertLeft = sideB === 'right' ? -1 : 1;1351styles[sideA] = top * invertTop;1352styles[sideB] = left * invertLeft;1353styles.willChange = sideA + ', ' + sideB;1354}1355
1356// Attributes1357var attributes = {1358'x-placement': data.placement1359};1360
1361// Update `data` attributes, styles and arrowStyles1362data.attributes = _extends({}, attributes, data.attributes);1363data.styles = _extends({}, styles, data.styles);1364data.arrowStyles = _extends({}, data.offsets.arrow, data.arrowStyles);1365
1366return data;1367}
1368
1369/**
1370* Helper used to know if the given modifier depends from another one.<br />
1371* It checks if the needed modifier is listed and enabled.
1372* @method
1373* @memberof Popper.Utils
1374* @param {Array} modifiers - list of modifiers
1375* @param {String} requestingName - name of requesting modifier
1376* @param {String} requestedName - name of requested modifier
1377* @returns {Boolean}
1378*/
1379function isModifierRequired(modifiers, requestingName, requestedName) {1380var requesting = find(modifiers, function (_ref) {1381var name = _ref.name;1382return name === requestingName;1383});1384
1385var isRequired = !!requesting && modifiers.some(function (modifier) {1386return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order;1387});1388
1389if (!isRequired) {1390var _requesting = '`' + requestingName + '`';1391var requested = '`' + requestedName + '`';1392console.warn(requested + ' modifier is required by ' + _requesting + ' modifier in order to work, be sure to include it before ' + _requesting + '!');1393}1394return isRequired;1395}
1396
1397/**
1398* @function
1399* @memberof Modifiers
1400* @argument {Object} data - The data object generated by update method
1401* @argument {Object} options - Modifiers configuration and options
1402* @returns {Object} The data object, properly modified
1403*/
1404function arrow(data, options) {1405var _data$offsets$arrow;1406
1407// arrow depends on keepTogether in order to work1408if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) {1409return data;1410}1411
1412var arrowElement = options.element;1413
1414// if arrowElement is a string, suppose it's a CSS selector1415if (typeof arrowElement === 'string') {1416arrowElement = data.instance.popper.querySelector(arrowElement);1417
1418// if arrowElement is not found, don't run the modifier1419if (!arrowElement) {1420return data;1421}1422} else {1423// if the arrowElement isn't a query selector we must check that the1424// provided DOM node is child of its popper node1425if (!data.instance.popper.contains(arrowElement)) {1426console.warn('WARNING: `arrow.element` must be child of its popper element!');1427return data;1428}1429}1430
1431var placement = data.placement.split('-')[0];1432var _data$offsets = data.offsets,1433popper = _data$offsets.popper,1434reference = _data$offsets.reference;1435
1436var isVertical = ['left', 'right'].indexOf(placement) !== -1;1437
1438var len = isVertical ? 'height' : 'width';1439var sideCapitalized = isVertical ? 'Top' : 'Left';1440var side = sideCapitalized.toLowerCase();1441var altSide = isVertical ? 'left' : 'top';1442var opSide = isVertical ? 'bottom' : 'right';1443var arrowElementSize = getOuterSizes(arrowElement)[len];1444
1445//1446// extends keepTogether behavior making sure the popper and its1447// reference have enough pixels in conjunction1448//1449
1450// top/left side1451if (reference[opSide] - arrowElementSize < popper[side]) {1452data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize);1453}1454// bottom/right side1455if (reference[side] + arrowElementSize > popper[opSide]) {1456data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide];1457}1458data.offsets.popper = getClientRect(data.offsets.popper);1459
1460// compute center of the popper1461var center = reference[side] + reference[len] / 2 - arrowElementSize / 2;1462
1463// Compute the sideValue using the updated popper offsets1464// take popper margin in account because we don't have this info available1465var css = getStyleComputedProperty(data.instance.popper);1466var popperMarginSide = parseFloat(css['margin' + sideCapitalized]);1467var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width']);1468var sideValue = center - data.offsets.popper[side] - popperMarginSide - popperBorderSide;1469
1470// prevent arrowElement from being placed not contiguously to its popper1471sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0);1472
1473data.arrowElement = arrowElement;1474data.offsets.arrow = (_data$offsets$arrow = {}, defineProperty(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty(_data$offsets$arrow, altSide, ''), _data$offsets$arrow);1475
1476return data;1477}
1478
1479/**
1480* Get the opposite placement variation of the given one
1481* @method
1482* @memberof Popper.Utils
1483* @argument {String} placement variation
1484* @returns {String} flipped placement variation
1485*/
1486function getOppositeVariation(variation) {1487if (variation === 'end') {1488return 'start';1489} else if (variation === 'start') {1490return 'end';1491}1492return variation;1493}
1494
1495/**
1496* List of accepted placements to use as values of the `placement` option.<br />
1497* Valid placements are:
1498* - `auto`
1499* - `top`
1500* - `right`
1501* - `bottom`
1502* - `left`
1503*
1504* Each placement can have a variation from this list:
1505* - `-start`
1506* - `-end`
1507*
1508* Variations are interpreted easily if you think of them as the left to right
1509* written languages. Horizontally (`top` and `bottom`), `start` is left and `end`
1510* is right.<br />
1511* Vertically (`left` and `right`), `start` is top and `end` is bottom.
1512*
1513* Some valid examples are:
1514* - `top-end` (on top of reference, right aligned)
1515* - `right-start` (on right of reference, top aligned)
1516* - `bottom` (on bottom, centered)
1517* - `auto-end` (on the side with more space available, alignment depends by placement)
1518*
1519* @static
1520* @type {Array}
1521* @enum {String}
1522* @readonly
1523* @method placements
1524* @memberof Popper
1525*/
1526var placements = ['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start'];1527
1528// Get rid of `auto` `auto-start` and `auto-end`
1529var validPlacements = placements.slice(3);1530
1531/**
1532* Given an initial placement, returns all the subsequent placements
1533* clockwise (or counter-clockwise).
1534*
1535* @method
1536* @memberof Popper.Utils
1537* @argument {String} placement - A valid placement (it accepts variations)
1538* @argument {Boolean} counter - Set to true to walk the placements counterclockwise
1539* @returns {Array} placements including their variations
1540*/
1541function clockwise(placement) {1542var counter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;1543
1544var index = validPlacements.indexOf(placement);1545var arr = validPlacements.slice(index + 1).concat(validPlacements.slice(0, index));1546return counter ? arr.reverse() : arr;1547}
1548
1549var BEHAVIORS = {1550FLIP: 'flip',1551CLOCKWISE: 'clockwise',1552COUNTERCLOCKWISE: 'counterclockwise'1553};1554
1555/**
1556* @function
1557* @memberof Modifiers
1558* @argument {Object} data - The data object generated by update method
1559* @argument {Object} options - Modifiers configuration and options
1560* @returns {Object} The data object, properly modified
1561*/
1562function flip(data, options) {1563// if `inner` modifier is enabled, we can't use the `flip` modifier1564if (isModifierEnabled(data.instance.modifiers, 'inner')) {1565return data;1566}1567
1568if (data.flipped && data.placement === data.originalPlacement) {1569// seems like flip is trying to loop, probably there's not enough space on any of the flippable sides1570return data;1571}1572
1573var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement, data.positionFixed);1574
1575var placement = data.placement.split('-')[0];1576var placementOpposite = getOppositePlacement(placement);1577var variation = data.placement.split('-')[1] || '';1578
1579var flipOrder = [];1580
1581switch (options.behavior) {1582case BEHAVIORS.FLIP:1583flipOrder = [placement, placementOpposite];1584break;1585case BEHAVIORS.CLOCKWISE:1586flipOrder = clockwise(placement);1587break;1588case BEHAVIORS.COUNTERCLOCKWISE:1589flipOrder = clockwise(placement, true);1590break;1591default:1592flipOrder = options.behavior;1593}1594
1595flipOrder.forEach(function (step, index) {1596if (placement !== step || flipOrder.length === index + 1) {1597return data;1598}1599
1600placement = data.placement.split('-')[0];1601placementOpposite = getOppositePlacement(placement);1602
1603var popperOffsets = data.offsets.popper;1604var refOffsets = data.offsets.reference;1605
1606// using floor because the reference offsets may contain decimals we are not going to consider here1607var floor = Math.floor;1608var 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);1609
1610var overflowsLeft = floor(popperOffsets.left) < floor(boundaries.left);1611var overflowsRight = floor(popperOffsets.right) > floor(boundaries.right);1612var overflowsTop = floor(popperOffsets.top) < floor(boundaries.top);1613var overflowsBottom = floor(popperOffsets.bottom) > floor(boundaries.bottom);1614
1615var overflowsBoundaries = placement === 'left' && overflowsLeft || placement === 'right' && overflowsRight || placement === 'top' && overflowsTop || placement === 'bottom' && overflowsBottom;1616
1617// flip the variation if required1618var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;1619
1620// flips variation if reference element overflows boundaries1621var flippedVariationByRef = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom);1622
1623// flips variation if popper content overflows boundaries1624var flippedVariationByContent = !!options.flipVariationsByContent && (isVertical && variation === 'start' && overflowsRight || isVertical && variation === 'end' && overflowsLeft || !isVertical && variation === 'start' && overflowsBottom || !isVertical && variation === 'end' && overflowsTop);1625
1626var flippedVariation = flippedVariationByRef || flippedVariationByContent;1627
1628if (overlapsRef || overflowsBoundaries || flippedVariation) {1629// this boolean to detect any flip loop1630data.flipped = true;1631
1632if (overlapsRef || overflowsBoundaries) {1633placement = flipOrder[index + 1];1634}1635
1636if (flippedVariation) {1637variation = getOppositeVariation(variation);1638}1639
1640data.placement = placement + (variation ? '-' + variation : '');1641
1642// this object contains `position`, we want to preserve it along with1643// any additional property we may add in the future1644data.offsets.popper = _extends({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement));1645
1646data = runModifiers(data.instance.modifiers, data, 'flip');1647}1648});1649return data;1650}
1651
1652/**
1653* @function
1654* @memberof Modifiers
1655* @argument {Object} data - The data object generated by update method
1656* @argument {Object} options - Modifiers configuration and options
1657* @returns {Object} The data object, properly modified
1658*/
1659function keepTogether(data) {1660var _data$offsets = data.offsets,1661popper = _data$offsets.popper,1662reference = _data$offsets.reference;1663
1664var placement = data.placement.split('-')[0];1665var floor = Math.floor;1666var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;1667var side = isVertical ? 'right' : 'bottom';1668var opSide = isVertical ? 'left' : 'top';1669var measurement = isVertical ? 'width' : 'height';1670
1671if (popper[side] < floor(reference[opSide])) {1672data.offsets.popper[opSide] = floor(reference[opSide]) - popper[measurement];1673}1674if (popper[opSide] > floor(reference[side])) {1675data.offsets.popper[opSide] = floor(reference[side]);1676}1677
1678return data;1679}
1680
1681/**
1682* Converts a string containing value + unit into a px value number
1683* @function
1684* @memberof {modifiers~offset}
1685* @private
1686* @argument {String} str - Value + unit string
1687* @argument {String} measurement - `height` or `width`
1688* @argument {Object} popperOffsets
1689* @argument {Object} referenceOffsets
1690* @returns {Number|String}
1691* Value in pixels, or original string if no values were extracted
1692*/
1693function toValue(str, measurement, popperOffsets, referenceOffsets) {1694// separate value from unit1695var split = str.match(/((?:\-|\+)?\d*\.?\d*)(.*)/);1696var value = +split[1];1697var unit = split[2];1698
1699// If it's not a number it's an operator, I guess1700if (!value) {1701return str;1702}1703
1704if (unit.indexOf('%') === 0) {1705var element = void 0;1706switch (unit) {1707case '%p':1708element = popperOffsets;1709break;1710case '%':1711case '%r':1712default:1713element = referenceOffsets;1714}1715
1716var rect = getClientRect(element);1717return rect[measurement] / 100 * value;1718} else if (unit === 'vh' || unit === 'vw') {1719// if is a vh or vw, we calculate the size based on the viewport1720var size = void 0;1721if (unit === 'vh') {1722size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);1723} else {1724size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);1725}1726return size / 100 * value;1727} else {1728// if is an explicit pixel unit, we get rid of the unit and keep the value1729// if is an implicit unit, it's px, and we return just the value1730return value;1731}1732}
1733
1734/**
1735* Parse an `offset` string to extrapolate `x` and `y` numeric offsets.
1736* @function
1737* @memberof {modifiers~offset}
1738* @private
1739* @argument {String} offset
1740* @argument {Object} popperOffsets
1741* @argument {Object} referenceOffsets
1742* @argument {String} basePlacement
1743* @returns {Array} a two cells array with x and y offsets in numbers
1744*/
1745function parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) {1746var offsets = [0, 0];1747
1748// Use height if placement is left or right and index is 0 otherwise use width1749// in this way the first offset will use an axis and the second one1750// will use the other one1751var useHeight = ['right', 'left'].indexOf(basePlacement) !== -1;1752
1753// Split the offset string to obtain a list of values and operands1754// The regex addresses values with the plus or minus sign in front (+10, -20, etc)1755var fragments = offset.split(/(\+|\-)/).map(function (frag) {1756return frag.trim();1757});1758
1759// Detect if the offset string contains a pair of values or a single one1760// they could be separated by comma or space1761var divider = fragments.indexOf(find(fragments, function (frag) {1762return frag.search(/,|\s/) !== -1;1763}));1764
1765if (fragments[divider] && fragments[divider].indexOf(',') === -1) {1766console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.');1767}1768
1769// If divider is found, we divide the list of values and operands to divide1770// them by ofset X and Y.1771var splitRegex = /\s*,\s*|\s+/;1772var ops = divider !== -1 ? [fragments.slice(0, divider).concat([fragments[divider].split(splitRegex)[0]]), [fragments[divider].split(splitRegex)[1]].concat(fragments.slice(divider + 1))] : [fragments];1773
1774// Convert the values with units to absolute pixels to allow our computations1775ops = ops.map(function (op, index) {1776// Most of the units rely on the orientation of the popper1777var measurement = (index === 1 ? !useHeight : useHeight) ? 'height' : 'width';1778var mergeWithPrevious = false;1779return op1780// This aggregates any `+` or `-` sign that aren't considered operators1781// e.g.: 10 + +5 => [10, +, +5]1782.reduce(function (a, b) {1783if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) {1784a[a.length - 1] = b;1785mergeWithPrevious = true;1786return a;1787} else if (mergeWithPrevious) {1788a[a.length - 1] += b;1789mergeWithPrevious = false;1790return a;1791} else {1792return a.concat(b);1793}1794}, [])1795// Here we convert the string values into number values (in px)1796.map(function (str) {1797return toValue(str, measurement, popperOffsets, referenceOffsets);1798});1799});1800
1801// Loop trough the offsets arrays and execute the operations1802ops.forEach(function (op, index) {1803op.forEach(function (frag, index2) {1804if (isNumeric(frag)) {1805offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1);1806}1807});1808});1809return offsets;1810}
1811
1812/**
1813* @function
1814* @memberof Modifiers
1815* @argument {Object} data - The data object generated by update method
1816* @argument {Object} options - Modifiers configuration and options
1817* @argument {Number|String} options.offset=0
1818* The offset value as described in the modifier description
1819* @returns {Object} The data object, properly modified
1820*/
1821function offset(data, _ref) {1822var offset = _ref.offset;1823var placement = data.placement,1824_data$offsets = data.offsets,1825popper = _data$offsets.popper,1826reference = _data$offsets.reference;1827
1828var basePlacement = placement.split('-')[0];1829
1830var offsets = void 0;1831if (isNumeric(+offset)) {1832offsets = [+offset, 0];1833} else {1834offsets = parseOffset(offset, popper, reference, basePlacement);1835}1836
1837if (basePlacement === 'left') {1838popper.top += offsets[0];1839popper.left -= offsets[1];1840} else if (basePlacement === 'right') {1841popper.top += offsets[0];1842popper.left += offsets[1];1843} else if (basePlacement === 'top') {1844popper.left += offsets[0];1845popper.top -= offsets[1];1846} else if (basePlacement === 'bottom') {1847popper.left += offsets[0];1848popper.top += offsets[1];1849}1850
1851data.popper = popper;1852return data;1853}
1854
1855/**
1856* @function
1857* @memberof Modifiers
1858* @argument {Object} data - The data object generated by `update` method
1859* @argument {Object} options - Modifiers configuration and options
1860* @returns {Object} The data object, properly modified
1861*/
1862function preventOverflow(data, options) {1863var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper);1864
1865// If offsetParent is the reference element, we really want to1866// go one step up and use the next offsetParent as reference to1867// avoid to make this modifier completely useless and look like broken1868if (data.instance.reference === boundariesElement) {1869boundariesElement = getOffsetParent(boundariesElement);1870}1871
1872// NOTE: DOM access here1873// resets the popper's position so that the document size can be calculated excluding1874// the size of the popper element itself1875var transformProp = getSupportedPropertyName('transform');1876var popperStyles = data.instance.popper.style; // assignment to help minification1877var top = popperStyles.top,1878left = popperStyles.left,1879transform = popperStyles[transformProp];1880
1881popperStyles.top = '';1882popperStyles.left = '';1883popperStyles[transformProp] = '';1884
1885var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement, data.positionFixed);1886
1887// NOTE: DOM access here1888// restores the original style properties after the offsets have been computed1889popperStyles.top = top;1890popperStyles.left = left;1891popperStyles[transformProp] = transform;1892
1893options.boundaries = boundaries;1894
1895var order = options.priority;1896var popper = data.offsets.popper;1897
1898var check = {1899primary: function primary(placement) {1900var value = popper[placement];1901if (popper[placement] < boundaries[placement] && !options.escapeWithReference) {1902value = Math.max(popper[placement], boundaries[placement]);1903}1904return defineProperty({}, placement, value);1905},1906secondary: function secondary(placement) {1907var mainSide = placement === 'right' ? 'left' : 'top';1908var value = popper[mainSide];1909if (popper[placement] > boundaries[placement] && !options.escapeWithReference) {1910value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height));1911}1912return defineProperty({}, mainSide, value);1913}1914};1915
1916order.forEach(function (placement) {1917var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary';1918popper = _extends({}, popper, check[side](placement));1919});1920
1921data.offsets.popper = popper;1922
1923return data;1924}
1925
1926/**
1927* @function
1928* @memberof Modifiers
1929* @argument {Object} data - The data object generated by `update` method
1930* @argument {Object} options - Modifiers configuration and options
1931* @returns {Object} The data object, properly modified
1932*/
1933function shift(data) {1934var placement = data.placement;1935var basePlacement = placement.split('-')[0];1936var shiftvariation = placement.split('-')[1];1937
1938// if shift shiftvariation is specified, run the modifier1939if (shiftvariation) {1940var _data$offsets = data.offsets,1941reference = _data$offsets.reference,1942popper = _data$offsets.popper;1943
1944var isVertical = ['bottom', 'top'].indexOf(basePlacement) !== -1;1945var side = isVertical ? 'left' : 'top';1946var measurement = isVertical ? 'width' : 'height';1947
1948var shiftOffsets = {1949start: defineProperty({}, side, reference[side]),1950end: defineProperty({}, side, reference[side] + reference[measurement] - popper[measurement])1951};1952
1953data.offsets.popper = _extends({}, popper, shiftOffsets[shiftvariation]);1954}1955
1956return data;1957}
1958
1959/**
1960* @function
1961* @memberof Modifiers
1962* @argument {Object} data - The data object generated by update method
1963* @argument {Object} options - Modifiers configuration and options
1964* @returns {Object} The data object, properly modified
1965*/
1966function hide(data) {1967if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) {1968return data;1969}1970
1971var refRect = data.offsets.reference;1972var bound = find(data.instance.modifiers, function (modifier) {1973return modifier.name === 'preventOverflow';1974}).boundaries;1975
1976if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) {1977// Avoid unnecessary DOM access if visibility hasn't changed1978if (data.hide === true) {1979return data;1980}1981
1982data.hide = true;1983data.attributes['x-out-of-boundaries'] = '';1984} else {1985// Avoid unnecessary DOM access if visibility hasn't changed1986if (data.hide === false) {1987return data;1988}1989
1990data.hide = false;1991data.attributes['x-out-of-boundaries'] = false;1992}1993
1994return data;1995}
1996
1997/**
1998* @function
1999* @memberof Modifiers
2000* @argument {Object} data - The data object generated by `update` method
2001* @argument {Object} options - Modifiers configuration and options
2002* @returns {Object} The data object, properly modified
2003*/
2004function inner(data) {2005var placement = data.placement;2006var basePlacement = placement.split('-')[0];2007var _data$offsets = data.offsets,2008popper = _data$offsets.popper,2009reference = _data$offsets.reference;2010
2011var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1;2012
2013var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1;2014
2015popper[isHoriz ? 'left' : 'top'] = reference[basePlacement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0);2016
2017data.placement = getOppositePlacement(placement);2018data.offsets.popper = getClientRect(popper);2019
2020return data;2021}
2022
2023/**
2024* Modifier function, each modifier can have a function of this type assigned
2025* to its `fn` property.<br />
2026* These functions will be called on each update, this means that you must
2027* make sure they are performant enough to avoid performance bottlenecks.
2028*
2029* @function ModifierFn
2030* @argument {dataObject} data - The data object generated by `update` method
2031* @argument {Object} options - Modifiers configuration and options
2032* @returns {dataObject} The data object, properly modified
2033*/
2034
2035/**
2036* Modifiers are plugins used to alter the behavior of your poppers.<br />
2037* Popper.js uses a set of 9 modifiers to provide all the basic functionalities
2038* needed by the library.
2039*
2040* Usually you don't want to override the `order`, `fn` and `onLoad` props.
2041* All the other properties are configurations that could be tweaked.
2042* @namespace modifiers
2043*/
2044var modifiers = {2045/**2046* Modifier used to shift the popper on the start or end of its reference
2047* element.<br />
2048* It will read the variation of the `placement` property.<br />
2049* It can be one either `-end` or `-start`.
2050* @memberof modifiers
2051* @inner
2052*/
2053shift: {2054/** @prop {number} order=100 - Index used to define the order of execution */2055order: 100,2056/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */2057enabled: true,2058/** @prop {ModifierFn} */2059fn: shift2060},2061
2062/**2063* The `offset` modifier can shift your popper on both its axis.
2064*
2065* It accepts the following units:
2066* - `px` or unit-less, interpreted as pixels
2067* - `%` or `%r`, percentage relative to the length of the reference element
2068* - `%p`, percentage relative to the length of the popper element
2069* - `vw`, CSS viewport width unit
2070* - `vh`, CSS viewport height unit
2071*
2072* For length is intended the main axis relative to the placement of the popper.<br />
2073* This means that if the placement is `top` or `bottom`, the length will be the
2074* `width`. In case of `left` or `right`, it will be the `height`.
2075*
2076* You can provide a single value (as `Number` or `String`), or a pair of values
2077* as `String` divided by a comma or one (or more) white spaces.<br />
2078* The latter is a deprecated method because it leads to confusion and will be
2079* removed in v2.<br />
2080* Additionally, it accepts additions and subtractions between different units.
2081* Note that multiplications and divisions aren't supported.
2082*
2083* Valid examples are:
2084* ```
2085* 10
2086* '10%'
2087* '10, 10'
2088* '10%, 10'
2089* '10 + 10%'
2090* '10 - 5vh + 3%'
2091* '-10px + 5vh, 5px - 6%'
2092* ```
2093* > **NB**: If you desire to apply offsets to your poppers in a way that may make them overlap
2094* > with their reference element, unfortunately, you will have to disable the `flip` modifier.
2095* > You can read more on this at this [issue](https://github.com/FezVrasta/popper.js/issues/373).
2096*
2097* @memberof modifiers
2098* @inner
2099*/
2100offset: {2101/** @prop {number} order=200 - Index used to define the order of execution */2102order: 200,2103/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */2104enabled: true,2105/** @prop {ModifierFn} */2106fn: offset,2107/** @prop {Number|String} offset=02108* The offset value as described in the modifier description
2109*/
2110offset: 02111},2112
2113/**2114* Modifier used to prevent the popper from being positioned outside the boundary.
2115*
2116* A scenario exists where the reference itself is not within the boundaries.<br />
2117* We can say it has "escaped the boundaries" — or just "escaped".<br />
2118* In this case we need to decide whether the popper should either:
2119*
2120* - detach from the reference and remain "trapped" in the boundaries, or
2121* - if it should ignore the boundary and "escape with its reference"
2122*
2123* When `escapeWithReference` is set to`true` and reference is completely
2124* outside its boundaries, the popper will overflow (or completely leave)
2125* the boundaries in order to remain attached to the edge of the reference.
2126*
2127* @memberof modifiers
2128* @inner
2129*/
2130preventOverflow: {2131/** @prop {number} order=300 - Index used to define the order of execution */2132order: 300,2133/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */2134enabled: true,2135/** @prop {ModifierFn} */2136fn: preventOverflow,2137/**2138* @prop {Array} [priority=['left','right','top','bottom']]
2139* Popper will try to prevent overflow following these priorities by default,
2140* then, it could overflow on the left and on top of the `boundariesElement`
2141*/
2142priority: ['left', 'right', 'top', 'bottom'],2143/**2144* @prop {number} padding=5
2145* Amount of pixel used to define a minimum distance between the boundaries
2146* and the popper. This makes sure the popper always has a little padding
2147* between the edges of its container
2148*/
2149padding: 5,2150/**2151* @prop {String|HTMLElement} boundariesElement='scrollParent'
2152* Boundaries used by the modifier. Can be `scrollParent`, `window`,
2153* `viewport` or any DOM element.
2154*/
2155boundariesElement: 'scrollParent'2156},2157
2158/**2159* Modifier used to make sure the reference and its popper stay near each other
2160* without leaving any gap between the two. Especially useful when the arrow is
2161* enabled and you want to ensure that it points to its reference element.
2162* It cares only about the first axis. You can still have poppers with margin
2163* between the popper and its reference element.
2164* @memberof modifiers
2165* @inner
2166*/
2167keepTogether: {2168/** @prop {number} order=400 - Index used to define the order of execution */2169order: 400,2170/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */2171enabled: true,2172/** @prop {ModifierFn} */2173fn: keepTogether2174},2175
2176/**2177* This modifier is used to move the `arrowElement` of the popper to make
2178* sure it is positioned between the reference element and its popper element.
2179* It will read the outer size of the `arrowElement` node to detect how many
2180* pixels of conjunction are needed.
2181*
2182* It has no effect if no `arrowElement` is provided.
2183* @memberof modifiers
2184* @inner
2185*/
2186arrow: {2187/** @prop {number} order=500 - Index used to define the order of execution */2188order: 500,2189/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */2190enabled: true,2191/** @prop {ModifierFn} */2192fn: arrow,2193/** @prop {String|HTMLElement} element='[x-arrow]' - Selector or node used as arrow */2194element: '[x-arrow]'2195},2196
2197/**2198* Modifier used to flip the popper's placement when it starts to overlap its
2199* reference element.
2200*
2201* Requires the `preventOverflow` modifier before it in order to work.
2202*
2203* **NOTE:** this modifier will interrupt the current update cycle and will
2204* restart it if it detects the need to flip the placement.
2205* @memberof modifiers
2206* @inner
2207*/
2208flip: {2209/** @prop {number} order=600 - Index used to define the order of execution */2210order: 600,2211/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */2212enabled: true,2213/** @prop {ModifierFn} */2214fn: flip,2215/**2216* @prop {String|Array} behavior='flip'
2217* The behavior used to change the popper's placement. It can be one of
2218* `flip`, `clockwise`, `counterclockwise` or an array with a list of valid
2219* placements (with optional variations)
2220*/
2221behavior: 'flip',2222/**2223* @prop {number} padding=5
2224* The popper will flip if it hits the edges of the `boundariesElement`
2225*/
2226padding: 5,2227/**2228* @prop {String|HTMLElement} boundariesElement='viewport'
2229* The element which will define the boundaries of the popper position.
2230* The popper will never be placed outside of the defined boundaries
2231* (except if `keepTogether` is enabled)
2232*/
2233boundariesElement: 'viewport',2234/**2235* @prop {Boolean} flipVariations=false
2236* The popper will switch placement variation between `-start` and `-end` when
2237* the reference element overlaps its boundaries.
2238*
2239* The original placement should have a set variation.
2240*/
2241flipVariations: false,2242/**2243* @prop {Boolean} flipVariationsByContent=false
2244* The popper will switch placement variation between `-start` and `-end` when
2245* the popper element overlaps its reference boundaries.
2246*
2247* The original placement should have a set variation.
2248*/
2249flipVariationsByContent: false2250},2251
2252/**2253* Modifier used to make the popper flow toward the inner of the reference element.
2254* By default, when this modifier is disabled, the popper will be placed outside
2255* the reference element.
2256* @memberof modifiers
2257* @inner
2258*/
2259inner: {2260/** @prop {number} order=700 - Index used to define the order of execution */2261order: 700,2262/** @prop {Boolean} enabled=false - Whether the modifier is enabled or not */2263enabled: false,2264/** @prop {ModifierFn} */2265fn: inner2266},2267
2268/**2269* Modifier used to hide the popper when its reference element is outside of the
2270* popper boundaries. It will set a `x-out-of-boundaries` attribute which can
2271* be used to hide with a CSS selector the popper when its reference is
2272* out of boundaries.
2273*
2274* Requires the `preventOverflow` modifier before it in order to work.
2275* @memberof modifiers
2276* @inner
2277*/
2278hide: {2279/** @prop {number} order=800 - Index used to define the order of execution */2280order: 800,2281/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */2282enabled: true,2283/** @prop {ModifierFn} */2284fn: hide2285},2286
2287/**2288* Computes the style that will be applied to the popper element to gets
2289* properly positioned.
2290*
2291* Note that this modifier will not touch the DOM, it just prepares the styles
2292* so that `applyStyle` modifier can apply it. This separation is useful
2293* in case you need to replace `applyStyle` with a custom implementation.
2294*
2295* This modifier has `850` as `order` value to maintain backward compatibility
2296* with previous versions of Popper.js. Expect the modifiers ordering method
2297* to change in future major versions of the library.
2298*
2299* @memberof modifiers
2300* @inner
2301*/
2302computeStyle: {2303/** @prop {number} order=850 - Index used to define the order of execution */2304order: 850,2305/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */2306enabled: true,2307/** @prop {ModifierFn} */2308fn: computeStyle,2309/**2310* @prop {Boolean} gpuAcceleration=true
2311* If true, it uses the CSS 3D transformation to position the popper.
2312* Otherwise, it will use the `top` and `left` properties
2313*/
2314gpuAcceleration: true,2315/**2316* @prop {string} [x='bottom']
2317* Where to anchor the X axis (`bottom` or `top`). AKA X offset origin.
2318* Change this if your popper should grow in a direction different from `bottom`
2319*/
2320x: 'bottom',2321/**2322* @prop {string} [x='left']
2323* Where to anchor the Y axis (`left` or `right`). AKA Y offset origin.
2324* Change this if your popper should grow in a direction different from `right`
2325*/
2326y: 'right'2327},2328
2329/**2330* Applies the computed styles to the popper element.
2331*
2332* All the DOM manipulations are limited to this modifier. This is useful in case
2333* you want to integrate Popper.js inside a framework or view library and you
2334* want to delegate all the DOM manipulations to it.
2335*
2336* Note that if you disable this modifier, you must make sure the popper element
2337* has its position set to `absolute` before Popper.js can do its work!
2338*
2339* Just disable this modifier and define your own to achieve the desired effect.
2340*
2341* @memberof modifiers
2342* @inner
2343*/
2344applyStyle: {2345/** @prop {number} order=900 - Index used to define the order of execution */2346order: 900,2347/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */2348enabled: true,2349/** @prop {ModifierFn} */2350fn: applyStyle,2351/** @prop {Function} */2352onLoad: applyStyleOnLoad,2353/**2354* @deprecated since version 1.10.0, the property moved to `computeStyle` modifier
2355* @prop {Boolean} gpuAcceleration=true
2356* If true, it uses the CSS 3D transformation to position the popper.
2357* Otherwise, it will use the `top` and `left` properties
2358*/
2359gpuAcceleration: undefined2360}2361};2362
2363/**
2364* The `dataObject` is an object containing all the information used by Popper.js.
2365* This object is passed to modifiers and to the `onCreate` and `onUpdate` callbacks.
2366* @name dataObject
2367* @property {Object} data.instance The Popper.js instance
2368* @property {String} data.placement Placement applied to popper
2369* @property {String} data.originalPlacement Placement originally defined on init
2370* @property {Boolean} data.flipped True if popper has been flipped by flip modifier
2371* @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper
2372* @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier
2373* @property {Object} data.styles Any CSS property defined here will be applied to the popper. It expects the JavaScript nomenclature (eg. `marginBottom`)
2374* @property {Object} data.arrowStyles Any CSS property defined here will be applied to the popper arrow. It expects the JavaScript nomenclature (eg. `marginBottom`)
2375* @property {Object} data.boundaries Offsets of the popper boundaries
2376* @property {Object} data.offsets The measurements of popper, reference and arrow elements
2377* @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values
2378* @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values
2379* @property {Object} data.offsets.arrow] `top` and `left` offsets, only one of them will be different from 0
2380*/
2381
2382/**
2383* Default options provided to Popper.js constructor.<br />
2384* These can be overridden using the `options` argument of Popper.js.<br />
2385* To override an option, simply pass an object with the same
2386* structure of the `options` object, as the 3rd argument. For example:
2387* ```
2388* new Popper(ref, pop, {
2389* modifiers: {
2390* preventOverflow: { enabled: false }
2391* }
2392* })
2393* ```
2394* @type {Object}
2395* @static
2396* @memberof Popper
2397*/
2398var Defaults = {2399/**2400* Popper's placement.
2401* @prop {Popper.placements} placement='bottom'
2402*/
2403placement: 'bottom',2404
2405/**2406* Set this to true if you want popper to position it self in 'fixed' mode
2407* @prop {Boolean} positionFixed=false
2408*/
2409positionFixed: false,2410
2411/**2412* Whether events (resize, scroll) are initially enabled.
2413* @prop {Boolean} eventsEnabled=true
2414*/
2415eventsEnabled: true,2416
2417/**2418* Set to true if you want to automatically remove the popper when
2419* you call the `destroy` method.
2420* @prop {Boolean} removeOnDestroy=false
2421*/
2422removeOnDestroy: false,2423
2424/**2425* Callback called when the popper is created.<br />
2426* By default, it is set to no-op.<br />
2427* Access Popper.js instance with `data.instance`.
2428* @prop {onCreate}
2429*/
2430onCreate: function onCreate() {},2431
2432/**2433* Callback called when the popper is updated. This callback is not called
2434* on the initialization/creation of the popper, but only on subsequent
2435* updates.<br />
2436* By default, it is set to no-op.<br />
2437* Access Popper.js instance with `data.instance`.
2438* @prop {onUpdate}
2439*/
2440onUpdate: function onUpdate() {},2441
2442/**2443* List of modifiers used to modify the offsets before they are applied to the popper.
2444* They provide most of the functionalities of Popper.js.
2445* @prop {modifiers}
2446*/
2447modifiers: modifiers2448};2449
2450/**
2451* @callback onCreate
2452* @param {dataObject} data
2453*/
2454
2455/**
2456* @callback onUpdate
2457* @param {dataObject} data
2458*/
2459
2460// Utils
2461// Methods
2462var Popper = function () {2463/**2464* Creates a new Popper.js instance.
2465* @class Popper
2466* @param {Element|referenceObject} reference - The reference element used to position the popper
2467* @param {Element} popper - The HTML / XML element used as the popper
2468* @param {Object} options - Your custom options to override the ones defined in [Defaults](#defaults)
2469* @return {Object} instance - The generated Popper.js instance
2470*/
2471function Popper(reference, popper) {2472var _this = this;2473
2474var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};2475classCallCheck(this, Popper);2476
2477this.scheduleUpdate = function () {2478return requestAnimationFrame(_this.update);2479};2480
2481// make update() debounced, so that it only runs at most once-per-tick2482this.update = debounce(this.update.bind(this));2483
2484// with {} we create a new object with the options inside it2485this.options = _extends({}, Popper.Defaults, options);2486
2487// init state2488this.state = {2489isDestroyed: false,2490isCreated: false,2491scrollParents: []2492};2493
2494// get reference and popper elements (allow jQuery wrappers)2495this.reference = reference && reference.jquery ? reference[0] : reference;2496this.popper = popper && popper.jquery ? popper[0] : popper;2497
2498// Deep merge modifiers options2499this.options.modifiers = {};2500Object.keys(_extends({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) {2501_this.options.modifiers[name] = _extends({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {});2502});2503
2504// Refactoring modifiers' list (Object => Array)2505this.modifiers = Object.keys(this.options.modifiers).map(function (name) {2506return _extends({2507name: name2508}, _this.options.modifiers[name]);2509})2510// sort the modifiers by order2511.sort(function (a, b) {2512return a.order - b.order;2513});2514
2515// modifiers have the ability to execute arbitrary code when Popper.js get inited2516// such code is executed in the same order of its modifier2517// they could add new properties to their options configuration2518// BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`!2519this.modifiers.forEach(function (modifierOptions) {2520if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) {2521modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state);2522}2523});2524
2525// fire the first update to position the popper in the right place2526this.update();2527
2528var eventsEnabled = this.options.eventsEnabled;2529if (eventsEnabled) {2530// setup event listeners, they will take care of update the position in specific situations2531this.enableEventListeners();2532}2533
2534this.state.eventsEnabled = eventsEnabled;2535}2536
2537// We can't use class properties because they don't get listed in the2538// class prototype and break stuff like Sinon stubs2539
2540
2541createClass(Popper, [{2542key: 'update',2543value: function update$$1() {2544return update.call(this);2545}2546}, {2547key: 'destroy',2548value: function destroy$$1() {2549return destroy.call(this);2550}2551}, {2552key: 'enableEventListeners',2553value: function enableEventListeners$$1() {2554return enableEventListeners.call(this);2555}2556}, {2557key: 'disableEventListeners',2558value: function disableEventListeners$$1() {2559return disableEventListeners.call(this);2560}2561
2562/**2563* Schedules an update. It will run on the next UI update available.
2564* @method scheduleUpdate
2565* @memberof Popper
2566*/
2567
2568
2569/**2570* Collection of utilities useful when writing custom modifiers.
2571* Starting from version 1.7, this method is available only if you
2572* include `popper-utils.js` before `popper.js`.
2573*
2574* **DEPRECATION**: This way to access PopperUtils is deprecated
2575* and will be removed in v2! Use the PopperUtils module directly instead.
2576* Due to the high instability of the methods contained in Utils, we can't
2577* guarantee them to follow semver. Use them at your own risk!
2578* @static
2579* @private
2580* @type {Object}
2581* @deprecated since version 1.8
2582* @member Utils
2583* @memberof Popper
2584*/
2585
2586}]);2587return Popper;2588}();2589
2590/**
2591* The `referenceObject` is an object that provides an interface compatible with Popper.js
2592* and lets you use it as replacement of a real DOM node.<br />
2593* You can use this method to position a popper relatively to a set of coordinates
2594* in case you don't have a DOM node to use as reference.
2595*
2596* ```
2597* new Popper(referenceObject, popperNode);
2598* ```
2599*
2600* NB: This feature isn't supported in Internet Explorer 10.
2601* @name referenceObject
2602* @property {Function} data.getBoundingClientRect
2603* A function that returns a set of coordinates compatible with the native `getBoundingClientRect` method.
2604* @property {number} data.clientWidth
2605* An ES6 getter that will return the width of the virtual reference element.
2606* @property {number} data.clientHeight
2607* An ES6 getter that will return the height of the virtual reference element.
2608*/
2609
2610
2611Popper.Utils = (typeof window !== 'undefined' ? window : global).PopperUtils;2612Popper.placements = placements;2613Popper.Defaults = Defaults;2614
2615export default Popper;2616//# sourceMappingURL=popper.js.map
2617