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