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