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