Built files from Bizgaze WebServer
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

popper-utils.js 35KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  1. /**!
  2. * @fileOverview Kickass library to create and place poppers near their reference elements.
  3. * @version 1.16.1
  4. * @license
  5. * Copyright (c) 2016 Federico Zivolo and contributors
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in all
  15. * copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. * SOFTWARE.
  24. */
  25. /**
  26. * Get CSS computed property of the given element
  27. * @method
  28. * @memberof Popper.Utils
  29. * @argument {Eement} element
  30. * @argument {String} property
  31. */
  32. function getStyleComputedProperty(element, property) {
  33. if (element.nodeType !== 1) {
  34. return [];
  35. }
  36. // NOTE: 1 DOM access here
  37. var window = element.ownerDocument.defaultView;
  38. var css = window.getComputedStyle(element, null);
  39. return property ? css[property] : css;
  40. }
  41. /**
  42. * Returns the parentNode or the host of the element
  43. * @method
  44. * @memberof Popper.Utils
  45. * @argument {Element} element
  46. * @returns {Element} parent
  47. */
  48. function getParentNode(element) {
  49. if (element.nodeName === 'HTML') {
  50. return element;
  51. }
  52. return element.parentNode || element.host;
  53. }
  54. /**
  55. * Returns the scrolling parent of the given element
  56. * @method
  57. * @memberof Popper.Utils
  58. * @argument {Element} element
  59. * @returns {Element} scroll parent
  60. */
  61. function getScrollParent(element) {
  62. // Return body, `getScroll` will take care to get the correct `scrollTop` from it
  63. if (!element) {
  64. return document.body;
  65. }
  66. switch (element.nodeName) {
  67. case 'HTML':
  68. case 'BODY':
  69. return element.ownerDocument.body;
  70. case '#document':
  71. return element.body;
  72. }
  73. // Firefox want us to check `-x` and `-y` variations as well
  74. var _getStyleComputedProp = getStyleComputedProperty(element),
  75. overflow = _getStyleComputedProp.overflow,
  76. overflowX = _getStyleComputedProp.overflowX,
  77. overflowY = _getStyleComputedProp.overflowY;
  78. if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) {
  79. return element;
  80. }
  81. return getScrollParent(getParentNode(element));
  82. }
  83. /**
  84. * Returns the reference node of the reference object, or the reference object itself.
  85. * @method
  86. * @memberof Popper.Utils
  87. * @param {Element|Object} reference - the reference element (the popper will be relative to this)
  88. * @returns {Element} parent
  89. */
  90. function getReferenceNode(reference) {
  91. return reference && reference.referenceNode ? reference.referenceNode : reference;
  92. }
  93. var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && typeof navigator !== 'undefined';
  94. var isIE11 = isBrowser && !!(window.MSInputMethodContext && document.documentMode);
  95. var isIE10 = isBrowser && /MSIE 10/.test(navigator.userAgent);
  96. /**
  97. * Determines if the browser is Internet Explorer
  98. * @method
  99. * @memberof Popper.Utils
  100. * @param {Number} version to check
  101. * @returns {Boolean} isIE
  102. */
  103. function isIE(version) {
  104. if (version === 11) {
  105. return isIE11;
  106. }
  107. if (version === 10) {
  108. return isIE10;
  109. }
  110. return isIE11 || isIE10;
  111. }
  112. /**
  113. * Returns the offset parent of the given element
  114. * @method
  115. * @memberof Popper.Utils
  116. * @argument {Element} element
  117. * @returns {Element} offset parent
  118. */
  119. function getOffsetParent(element) {
  120. if (!element) {
  121. return document.documentElement;
  122. }
  123. var noOffsetParent = isIE(10) ? document.body : null;
  124. // NOTE: 1 DOM access here
  125. var offsetParent = element.offsetParent || null;
  126. // Skip hidden elements which don't have an offsetParent
  127. while (offsetParent === noOffsetParent && element.nextElementSibling) {
  128. offsetParent = (element = element.nextElementSibling).offsetParent;
  129. }
  130. var nodeName = offsetParent && offsetParent.nodeName;
  131. if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {
  132. return element ? element.ownerDocument.documentElement : document.documentElement;
  133. }
  134. // .offsetParent will return the closest TH, TD or TABLE in case
  135. // no offsetParent is present, I hate this job...
  136. if (['TH', 'TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') {
  137. return getOffsetParent(offsetParent);
  138. }
  139. return offsetParent;
  140. }
  141. function isOffsetContainer(element) {
  142. var nodeName = element.nodeName;
  143. if (nodeName === 'BODY') {
  144. return false;
  145. }
  146. return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element;
  147. }
  148. /**
  149. * Finds the root node (document, shadowDOM root) of the given element
  150. * @method
  151. * @memberof Popper.Utils
  152. * @argument {Element} node
  153. * @returns {Element} root node
  154. */
  155. function getRoot(node) {
  156. if (node.parentNode !== null) {
  157. return getRoot(node.parentNode);
  158. }
  159. return node;
  160. }
  161. /**
  162. * Finds the offset parent common to the two provided nodes
  163. * @method
  164. * @memberof Popper.Utils
  165. * @argument {Element} element1
  166. * @argument {Element} element2
  167. * @returns {Element} common offset parent
  168. */
  169. function findCommonOffsetParent(element1, element2) {
  170. // This check is needed to avoid errors in case one of the elements isn't defined for any reason
  171. if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) {
  172. return document.documentElement;
  173. }
  174. // Here we make sure to give as "start" the element that comes first in the DOM
  175. var order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING;
  176. var start = order ? element1 : element2;
  177. var end = order ? element2 : element1;
  178. // Get common ancestor container
  179. var range = document.createRange();
  180. range.setStart(start, 0);
  181. range.setEnd(end, 0);
  182. var commonAncestorContainer = range.commonAncestorContainer;
  183. // Both nodes are inside #document
  184. if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) {
  185. if (isOffsetContainer(commonAncestorContainer)) {
  186. return commonAncestorContainer;
  187. }
  188. return getOffsetParent(commonAncestorContainer);
  189. }
  190. // one of the nodes is inside shadowDOM, find which one
  191. var element1root = getRoot(element1);
  192. if (element1root.host) {
  193. return findCommonOffsetParent(element1root.host, element2);
  194. } else {
  195. return findCommonOffsetParent(element1, getRoot(element2).host);
  196. }
  197. }
  198. /**
  199. * Gets the scroll value of the given element in the given side (top and left)
  200. * @method
  201. * @memberof Popper.Utils
  202. * @argument {Element} element
  203. * @argument {String} side `top` or `left`
  204. * @returns {number} amount of scrolled pixels
  205. */
  206. function getScroll(element) {
  207. var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top';
  208. var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft';
  209. var nodeName = element.nodeName;
  210. if (nodeName === 'BODY' || nodeName === 'HTML') {
  211. var html = element.ownerDocument.documentElement;
  212. var scrollingElement = element.ownerDocument.scrollingElement || html;
  213. return scrollingElement[upperSide];
  214. }
  215. return element[upperSide];
  216. }
  217. /*
  218. * Sum or subtract the element scroll values (left and top) from a given rect object
  219. * @method
  220. * @memberof Popper.Utils
  221. * @param {Object} rect - Rect object you want to change
  222. * @param {HTMLElement} element - The element from the function reads the scroll values
  223. * @param {Boolean} subtract - set to true if you want to subtract the scroll values
  224. * @return {Object} rect - The modifier rect object
  225. */
  226. function includeScroll(rect, element) {
  227. var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  228. var scrollTop = getScroll(element, 'top');
  229. var scrollLeft = getScroll(element, 'left');
  230. var modifier = subtract ? -1 : 1;
  231. rect.top += scrollTop * modifier;
  232. rect.bottom += scrollTop * modifier;
  233. rect.left += scrollLeft * modifier;
  234. rect.right += scrollLeft * modifier;
  235. return rect;
  236. }
  237. /*
  238. * Helper to detect borders of a given element
  239. * @method
  240. * @memberof Popper.Utils
  241. * @param {CSSStyleDeclaration} styles
  242. * Result of `getStyleComputedProperty` on the given element
  243. * @param {String} axis - `x` or `y`
  244. * @return {number} borders - The borders size of the given axis
  245. */
  246. function getBordersSize(styles, axis) {
  247. var sideA = axis === 'x' ? 'Left' : 'Top';
  248. var sideB = sideA === 'Left' ? 'Right' : 'Bottom';
  249. return parseFloat(styles['border' + sideA + 'Width']) + parseFloat(styles['border' + sideB + 'Width']);
  250. }
  251. function getSize(axis, body, html, computedStyle) {
  252. 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);
  253. }
  254. function getWindowSizes(document) {
  255. var body = document.body;
  256. var html = document.documentElement;
  257. var computedStyle = isIE(10) && getComputedStyle(html);
  258. return {
  259. height: getSize('Height', body, html, computedStyle),
  260. width: getSize('Width', body, html, computedStyle)
  261. };
  262. }
  263. var _extends = Object.assign || function (target) {
  264. for (var i = 1; i < arguments.length; i++) {
  265. var source = arguments[i];
  266. for (var key in source) {
  267. if (Object.prototype.hasOwnProperty.call(source, key)) {
  268. target[key] = source[key];
  269. }
  270. }
  271. }
  272. return target;
  273. };
  274. /**
  275. * Given element offsets, generate an output similar to getBoundingClientRect
  276. * @method
  277. * @memberof Popper.Utils
  278. * @argument {Object} offsets
  279. * @returns {Object} ClientRect like output
  280. */
  281. function getClientRect(offsets) {
  282. return _extends({}, offsets, {
  283. right: offsets.left + offsets.width,
  284. bottom: offsets.top + offsets.height
  285. });
  286. }
  287. /**
  288. * Get bounding client rect of given element
  289. * @method
  290. * @memberof Popper.Utils
  291. * @param {HTMLElement} element
  292. * @return {Object} client rect
  293. */
  294. function getBoundingClientRect(element) {
  295. var rect = {};
  296. // IE10 10 FIX: Please, don't ask, the element isn't
  297. // considered in DOM in some circumstances...
  298. // This isn't reproducible in IE10 compatibility mode of IE11
  299. try {
  300. if (isIE(10)) {
  301. rect = element.getBoundingClientRect();
  302. var scrollTop = getScroll(element, 'top');
  303. var scrollLeft = getScroll(element, 'left');
  304. rect.top += scrollTop;
  305. rect.left += scrollLeft;
  306. rect.bottom += scrollTop;
  307. rect.right += scrollLeft;
  308. } else {
  309. rect = element.getBoundingClientRect();
  310. }
  311. } catch (e) {}
  312. var result = {
  313. left: rect.left,
  314. top: rect.top,
  315. width: rect.right - rect.left,
  316. height: rect.bottom - rect.top
  317. };
  318. // subtract scrollbar size from sizes
  319. var sizes = element.nodeName === 'HTML' ? getWindowSizes(element.ownerDocument) : {};
  320. var width = sizes.width || element.clientWidth || result.width;
  321. var height = sizes.height || element.clientHeight || result.height;
  322. var horizScrollbar = element.offsetWidth - width;
  323. var vertScrollbar = element.offsetHeight - height;
  324. // if an hypothetical scrollbar is detected, we must be sure it's not a `border`
  325. // we make this check conditional for performance reasons
  326. if (horizScrollbar || vertScrollbar) {
  327. var styles = getStyleComputedProperty(element);
  328. horizScrollbar -= getBordersSize(styles, 'x');
  329. vertScrollbar -= getBordersSize(styles, 'y');
  330. result.width -= horizScrollbar;
  331. result.height -= vertScrollbar;
  332. }
  333. return getClientRect(result);
  334. }
  335. function getOffsetRectRelativeToArbitraryNode(children, parent) {
  336. var fixedPosition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  337. var isIE10 = isIE(10);
  338. var isHTML = parent.nodeName === 'HTML';
  339. var childrenRect = getBoundingClientRect(children);
  340. var parentRect = getBoundingClientRect(parent);
  341. var scrollParent = getScrollParent(children);
  342. var styles = getStyleComputedProperty(parent);
  343. var borderTopWidth = parseFloat(styles.borderTopWidth);
  344. var borderLeftWidth = parseFloat(styles.borderLeftWidth);
  345. // In cases where the parent is fixed, we must ignore negative scroll in offset calc
  346. if (fixedPosition && isHTML) {
  347. parentRect.top = Math.max(parentRect.top, 0);
  348. parentRect.left = Math.max(parentRect.left, 0);
  349. }
  350. var offsets = getClientRect({
  351. top: childrenRect.top - parentRect.top - borderTopWidth,
  352. left: childrenRect.left - parentRect.left - borderLeftWidth,
  353. width: childrenRect.width,
  354. height: childrenRect.height
  355. });
  356. offsets.marginTop = 0;
  357. offsets.marginLeft = 0;
  358. // Subtract margins of documentElement in case it's being used as parent
  359. // we do this only on HTML because it's the only element that behaves
  360. // differently when margins are applied to it. The margins are included in
  361. // the box of the documentElement, in the other cases not.
  362. if (!isIE10 && isHTML) {
  363. var marginTop = parseFloat(styles.marginTop);
  364. var marginLeft = parseFloat(styles.marginLeft);
  365. offsets.top -= borderTopWidth - marginTop;
  366. offsets.bottom -= borderTopWidth - marginTop;
  367. offsets.left -= borderLeftWidth - marginLeft;
  368. offsets.right -= borderLeftWidth - marginLeft;
  369. // Attach marginTop and marginLeft because in some circumstances we may need them
  370. offsets.marginTop = marginTop;
  371. offsets.marginLeft = marginLeft;
  372. }
  373. if (isIE10 && !fixedPosition ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') {
  374. offsets = includeScroll(offsets, parent);
  375. }
  376. return offsets;
  377. }
  378. function getViewportOffsetRectRelativeToArtbitraryNode(element) {
  379. var excludeScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  380. var html = element.ownerDocument.documentElement;
  381. var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html);
  382. var width = Math.max(html.clientWidth, window.innerWidth || 0);
  383. var height = Math.max(html.clientHeight, window.innerHeight || 0);
  384. var scrollTop = !excludeScroll ? getScroll(html) : 0;
  385. var scrollLeft = !excludeScroll ? getScroll(html, 'left') : 0;
  386. var offset = {
  387. top: scrollTop - relativeOffset.top + relativeOffset.marginTop,
  388. left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft,
  389. width: width,
  390. height: height
  391. };
  392. return getClientRect(offset);
  393. }
  394. /**
  395. * Check if the given element is fixed or is inside a fixed parent
  396. * @method
  397. * @memberof Popper.Utils
  398. * @argument {Element} element
  399. * @argument {Element} customContainer
  400. * @returns {Boolean} answer to "isFixed?"
  401. */
  402. function isFixed(element) {
  403. var nodeName = element.nodeName;
  404. if (nodeName === 'BODY' || nodeName === 'HTML') {
  405. return false;
  406. }
  407. if (getStyleComputedProperty(element, 'position') === 'fixed') {
  408. return true;
  409. }
  410. var parentNode = getParentNode(element);
  411. if (!parentNode) {
  412. return false;
  413. }
  414. return isFixed(parentNode);
  415. }
  416. /**
  417. * Finds the first parent of an element that has a transformed property defined
  418. * @method
  419. * @memberof Popper.Utils
  420. * @argument {Element} element
  421. * @returns {Element} first transformed parent or documentElement
  422. */
  423. function getFixedPositionOffsetParent(element) {
  424. // This check is needed to avoid errors in case one of the elements isn't defined for any reason
  425. if (!element || !element.parentElement || isIE()) {
  426. return document.documentElement;
  427. }
  428. var el = element.parentElement;
  429. while (el && getStyleComputedProperty(el, 'transform') === 'none') {
  430. el = el.parentElement;
  431. }
  432. return el || document.documentElement;
  433. }
  434. /**
  435. * Computed the boundaries limits and return them
  436. * @method
  437. * @memberof Popper.Utils
  438. * @param {HTMLElement} popper
  439. * @param {HTMLElement} reference
  440. * @param {number} padding
  441. * @param {HTMLElement} boundariesElement - Element used to define the boundaries
  442. * @param {Boolean} fixedPosition - Is in fixed position mode
  443. * @returns {Object} Coordinates of the boundaries
  444. */
  445. function getBoundaries(popper, reference, padding, boundariesElement) {
  446. var fixedPosition = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
  447. // NOTE: 1 DOM access here
  448. var boundaries = { top: 0, left: 0 };
  449. var offsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, getReferenceNode(reference));
  450. // Handle viewport case
  451. if (boundariesElement === 'viewport') {
  452. boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent, fixedPosition);
  453. } else {
  454. // Handle other cases based on DOM element used as boundaries
  455. var boundariesNode = void 0;
  456. if (boundariesElement === 'scrollParent') {
  457. boundariesNode = getScrollParent(getParentNode(reference));
  458. if (boundariesNode.nodeName === 'BODY') {
  459. boundariesNode = popper.ownerDocument.documentElement;
  460. }
  461. } else if (boundariesElement === 'window') {
  462. boundariesNode = popper.ownerDocument.documentElement;
  463. } else {
  464. boundariesNode = boundariesElement;
  465. }
  466. var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent, fixedPosition);
  467. // In case of HTML, we need a different computation
  468. if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) {
  469. var _getWindowSizes = getWindowSizes(popper.ownerDocument),
  470. height = _getWindowSizes.height,
  471. width = _getWindowSizes.width;
  472. boundaries.top += offsets.top - offsets.marginTop;
  473. boundaries.bottom = height + offsets.top;
  474. boundaries.left += offsets.left - offsets.marginLeft;
  475. boundaries.right = width + offsets.left;
  476. } else {
  477. // for all the other DOM elements, this one is good
  478. boundaries = offsets;
  479. }
  480. }
  481. // Add paddings
  482. padding = padding || 0;
  483. var isPaddingNumber = typeof padding === 'number';
  484. boundaries.left += isPaddingNumber ? padding : padding.left || 0;
  485. boundaries.top += isPaddingNumber ? padding : padding.top || 0;
  486. boundaries.right -= isPaddingNumber ? padding : padding.right || 0;
  487. boundaries.bottom -= isPaddingNumber ? padding : padding.bottom || 0;
  488. return boundaries;
  489. }
  490. function getArea(_ref) {
  491. var width = _ref.width,
  492. height = _ref.height;
  493. return width * height;
  494. }
  495. /**
  496. * Utility used to transform the `auto` placement to the placement with more
  497. * available space.
  498. * @method
  499. * @memberof Popper.Utils
  500. * @argument {Object} data - The data object generated by update method
  501. * @argument {Object} options - Modifiers configuration and options
  502. * @returns {Object} The data object, properly modified
  503. */
  504. function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement) {
  505. var padding = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
  506. if (placement.indexOf('auto') === -1) {
  507. return placement;
  508. }
  509. var boundaries = getBoundaries(popper, reference, padding, boundariesElement);
  510. var rects = {
  511. top: {
  512. width: boundaries.width,
  513. height: refRect.top - boundaries.top
  514. },
  515. right: {
  516. width: boundaries.right - refRect.right,
  517. height: boundaries.height
  518. },
  519. bottom: {
  520. width: boundaries.width,
  521. height: boundaries.bottom - refRect.bottom
  522. },
  523. left: {
  524. width: refRect.left - boundaries.left,
  525. height: boundaries.height
  526. }
  527. };
  528. var sortedAreas = Object.keys(rects).map(function (key) {
  529. return _extends({
  530. key: key
  531. }, rects[key], {
  532. area: getArea(rects[key])
  533. });
  534. }).sort(function (a, b) {
  535. return b.area - a.area;
  536. });
  537. var filteredAreas = sortedAreas.filter(function (_ref2) {
  538. var width = _ref2.width,
  539. height = _ref2.height;
  540. return width >= popper.clientWidth && height >= popper.clientHeight;
  541. });
  542. var computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key;
  543. var variation = placement.split('-')[1];
  544. return computedPlacement + (variation ? '-' + variation : '');
  545. }
  546. var timeoutDuration = function () {
  547. var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];
  548. for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) {
  549. if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {
  550. return 1;
  551. }
  552. }
  553. return 0;
  554. }();
  555. function microtaskDebounce(fn) {
  556. var called = false;
  557. return function () {
  558. if (called) {
  559. return;
  560. }
  561. called = true;
  562. window.Promise.resolve().then(function () {
  563. called = false;
  564. fn();
  565. });
  566. };
  567. }
  568. function taskDebounce(fn) {
  569. var scheduled = false;
  570. return function () {
  571. if (!scheduled) {
  572. scheduled = true;
  573. setTimeout(function () {
  574. scheduled = false;
  575. fn();
  576. }, timeoutDuration);
  577. }
  578. };
  579. }
  580. var supportsMicroTasks = isBrowser && window.Promise;
  581. /**
  582. * Create a debounced version of a method, that's asynchronously deferred
  583. * but called in the minimum time possible.
  584. *
  585. * @method
  586. * @memberof Popper.Utils
  587. * @argument {Function} fn
  588. * @returns {Function}
  589. */
  590. var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce;
  591. /**
  592. * Mimics the `find` method of Array
  593. * @method
  594. * @memberof Popper.Utils
  595. * @argument {Array} arr
  596. * @argument prop
  597. * @argument value
  598. * @returns index or -1
  599. */
  600. function find(arr, check) {
  601. // use native find if supported
  602. if (Array.prototype.find) {
  603. return arr.find(check);
  604. }
  605. // use `filter` to obtain the same behavior of `find`
  606. return arr.filter(check)[0];
  607. }
  608. /**
  609. * Return the index of the matching object
  610. * @method
  611. * @memberof Popper.Utils
  612. * @argument {Array} arr
  613. * @argument prop
  614. * @argument value
  615. * @returns index or -1
  616. */
  617. function findIndex(arr, prop, value) {
  618. // use native findIndex if supported
  619. if (Array.prototype.findIndex) {
  620. return arr.findIndex(function (cur) {
  621. return cur[prop] === value;
  622. });
  623. }
  624. // use `find` + `indexOf` if `findIndex` isn't supported
  625. var match = find(arr, function (obj) {
  626. return obj[prop] === value;
  627. });
  628. return arr.indexOf(match);
  629. }
  630. /**
  631. * Get the position of the given element, relative to its offset parent
  632. * @method
  633. * @memberof Popper.Utils
  634. * @param {Element} element
  635. * @return {Object} position - Coordinates of the element and its `scrollTop`
  636. */
  637. function getOffsetRect(element) {
  638. var elementRect = void 0;
  639. if (element.nodeName === 'HTML') {
  640. var _getWindowSizes = getWindowSizes(element.ownerDocument),
  641. width = _getWindowSizes.width,
  642. height = _getWindowSizes.height;
  643. elementRect = {
  644. width: width,
  645. height: height,
  646. left: 0,
  647. top: 0
  648. };
  649. } else {
  650. elementRect = {
  651. width: element.offsetWidth,
  652. height: element.offsetHeight,
  653. left: element.offsetLeft,
  654. top: element.offsetTop
  655. };
  656. }
  657. // position
  658. return getClientRect(elementRect);
  659. }
  660. /**
  661. * Get the outer sizes of the given element (offset size + margins)
  662. * @method
  663. * @memberof Popper.Utils
  664. * @argument {Element} element
  665. * @returns {Object} object containing width and height properties
  666. */
  667. function getOuterSizes(element) {
  668. var window = element.ownerDocument.defaultView;
  669. var styles = window.getComputedStyle(element);
  670. var x = parseFloat(styles.marginTop || 0) + parseFloat(styles.marginBottom || 0);
  671. var y = parseFloat(styles.marginLeft || 0) + parseFloat(styles.marginRight || 0);
  672. var result = {
  673. width: element.offsetWidth + y,
  674. height: element.offsetHeight + x
  675. };
  676. return result;
  677. }
  678. /**
  679. * Get the opposite placement of the given one
  680. * @method
  681. * @memberof Popper.Utils
  682. * @argument {String} placement
  683. * @returns {String} flipped placement
  684. */
  685. function getOppositePlacement(placement) {
  686. var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' };
  687. return placement.replace(/left|right|bottom|top/g, function (matched) {
  688. return hash[matched];
  689. });
  690. }
  691. /**
  692. * Get offsets to the popper
  693. * @method
  694. * @memberof Popper.Utils
  695. * @param {Object} position - CSS position the Popper will get applied
  696. * @param {HTMLElement} popper - the popper element
  697. * @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this)
  698. * @param {String} placement - one of the valid placement options
  699. * @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper
  700. */
  701. function getPopperOffsets(popper, referenceOffsets, placement) {
  702. placement = placement.split('-')[0];
  703. // Get popper node sizes
  704. var popperRect = getOuterSizes(popper);
  705. // Add position, width and height to our offsets object
  706. var popperOffsets = {
  707. width: popperRect.width,
  708. height: popperRect.height
  709. };
  710. // depending by the popper placement we have to compute its offsets slightly differently
  711. var isHoriz = ['right', 'left'].indexOf(placement) !== -1;
  712. var mainSide = isHoriz ? 'top' : 'left';
  713. var secondarySide = isHoriz ? 'left' : 'top';
  714. var measurement = isHoriz ? 'height' : 'width';
  715. var secondaryMeasurement = !isHoriz ? 'height' : 'width';
  716. popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2;
  717. if (placement === secondarySide) {
  718. popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement];
  719. } else {
  720. popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)];
  721. }
  722. return popperOffsets;
  723. }
  724. /**
  725. * Get offsets to the reference element
  726. * @method
  727. * @memberof Popper.Utils
  728. * @param {Object} state
  729. * @param {Element} popper - the popper element
  730. * @param {Element} reference - the reference element (the popper will be relative to this)
  731. * @param {Element} fixedPosition - is in fixed position mode
  732. * @returns {Object} An object containing the offsets which will be applied to the popper
  733. */
  734. function getReferenceOffsets(state, popper, reference) {
  735. var fixedPosition = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
  736. var commonOffsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, getReferenceNode(reference));
  737. return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent, fixedPosition);
  738. }
  739. /**
  740. * Get the prefixed supported property name
  741. * @method
  742. * @memberof Popper.Utils
  743. * @argument {String} property (camelCase)
  744. * @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix)
  745. */
  746. function getSupportedPropertyName(property) {
  747. var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O'];
  748. var upperProp = property.charAt(0).toUpperCase() + property.slice(1);
  749. for (var i = 0; i < prefixes.length; i++) {
  750. var prefix = prefixes[i];
  751. var toCheck = prefix ? '' + prefix + upperProp : property;
  752. if (typeof document.body.style[toCheck] !== 'undefined') {
  753. return toCheck;
  754. }
  755. }
  756. return null;
  757. }
  758. /**
  759. * Check if the given variable is a function
  760. * @method
  761. * @memberof Popper.Utils
  762. * @argument {Any} functionToCheck - variable to check
  763. * @returns {Boolean} answer to: is a function?
  764. */
  765. function isFunction(functionToCheck) {
  766. var getType = {};
  767. return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
  768. }
  769. /**
  770. * Helper used to know if the given modifier is enabled.
  771. * @method
  772. * @memberof Popper.Utils
  773. * @returns {Boolean}
  774. */
  775. function isModifierEnabled(modifiers, modifierName) {
  776. return modifiers.some(function (_ref) {
  777. var name = _ref.name,
  778. enabled = _ref.enabled;
  779. return enabled && name === modifierName;
  780. });
  781. }
  782. /**
  783. * Helper used to know if the given modifier depends from another one.<br />
  784. * It checks if the needed modifier is listed and enabled.
  785. * @method
  786. * @memberof Popper.Utils
  787. * @param {Array} modifiers - list of modifiers
  788. * @param {String} requestingName - name of requesting modifier
  789. * @param {String} requestedName - name of requested modifier
  790. * @returns {Boolean}
  791. */
  792. function isModifierRequired(modifiers, requestingName, requestedName) {
  793. var requesting = find(modifiers, function (_ref) {
  794. var name = _ref.name;
  795. return name === requestingName;
  796. });
  797. var isRequired = !!requesting && modifiers.some(function (modifier) {
  798. return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order;
  799. });
  800. if (!isRequired) {
  801. var _requesting = '`' + requestingName + '`';
  802. var requested = '`' + requestedName + '`';
  803. console.warn(requested + ' modifier is required by ' + _requesting + ' modifier in order to work, be sure to include it before ' + _requesting + '!');
  804. }
  805. return isRequired;
  806. }
  807. /**
  808. * Tells if a given input is a number
  809. * @method
  810. * @memberof Popper.Utils
  811. * @param {*} input to check
  812. * @return {Boolean}
  813. */
  814. function isNumeric(n) {
  815. return n !== '' && !isNaN(parseFloat(n)) && isFinite(n);
  816. }
  817. /**
  818. * Get the window associated with the element
  819. * @argument {Element} element
  820. * @returns {Window}
  821. */
  822. function getWindow(element) {
  823. var ownerDocument = element.ownerDocument;
  824. return ownerDocument ? ownerDocument.defaultView : window;
  825. }
  826. /**
  827. * Remove event listeners used to update the popper position
  828. * @method
  829. * @memberof Popper.Utils
  830. * @private
  831. */
  832. function removeEventListeners(reference, state) {
  833. // Remove resize event listener on window
  834. getWindow(reference).removeEventListener('resize', state.updateBound);
  835. // Remove scroll event listener on scroll parents
  836. state.scrollParents.forEach(function (target) {
  837. target.removeEventListener('scroll', state.updateBound);
  838. });
  839. // Reset state
  840. state.updateBound = null;
  841. state.scrollParents = [];
  842. state.scrollElement = null;
  843. state.eventsEnabled = false;
  844. return state;
  845. }
  846. /**
  847. * Loop trough the list of modifiers and run them in order,
  848. * each of them will then edit the data object.
  849. * @method
  850. * @memberof Popper.Utils
  851. * @param {dataObject} data
  852. * @param {Array} modifiers
  853. * @param {String} ends - Optional modifier name used as stopper
  854. * @returns {dataObject}
  855. */
  856. function runModifiers(modifiers, data, ends) {
  857. var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends));
  858. modifiersToRun.forEach(function (modifier) {
  859. if (modifier['function']) {
  860. // eslint-disable-line dot-notation
  861. console.warn('`modifier.function` is deprecated, use `modifier.fn`!');
  862. }
  863. var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation
  864. if (modifier.enabled && isFunction(fn)) {
  865. // Add properties to offsets to make them a complete clientRect object
  866. // we do this before each modifier to make sure the previous one doesn't
  867. // mess with these values
  868. data.offsets.popper = getClientRect(data.offsets.popper);
  869. data.offsets.reference = getClientRect(data.offsets.reference);
  870. data = fn(data, modifier);
  871. }
  872. });
  873. return data;
  874. }
  875. /**
  876. * Set the attributes to the given popper
  877. * @method
  878. * @memberof Popper.Utils
  879. * @argument {Element} element - Element to apply the attributes to
  880. * @argument {Object} styles
  881. * Object with a list of properties and values which will be applied to the element
  882. */
  883. function setAttributes(element, attributes) {
  884. Object.keys(attributes).forEach(function (prop) {
  885. var value = attributes[prop];
  886. if (value !== false) {
  887. element.setAttribute(prop, attributes[prop]);
  888. } else {
  889. element.removeAttribute(prop);
  890. }
  891. });
  892. }
  893. /**
  894. * Set the style to the given popper
  895. * @method
  896. * @memberof Popper.Utils
  897. * @argument {Element} element - Element to apply the style to
  898. * @argument {Object} styles
  899. * Object with a list of properties and values which will be applied to the element
  900. */
  901. function setStyles(element, styles) {
  902. Object.keys(styles).forEach(function (prop) {
  903. var unit = '';
  904. // add unit if the value is numeric and is one of the following
  905. if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) {
  906. unit = 'px';
  907. }
  908. element.style[prop] = styles[prop] + unit;
  909. });
  910. }
  911. function attachToScrollParents(scrollParent, event, callback, scrollParents) {
  912. var isBody = scrollParent.nodeName === 'BODY';
  913. var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent;
  914. target.addEventListener(event, callback, { passive: true });
  915. if (!isBody) {
  916. attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents);
  917. }
  918. scrollParents.push(target);
  919. }
  920. /**
  921. * Setup needed event listeners used to update the popper position
  922. * @method
  923. * @memberof Popper.Utils
  924. * @private
  925. */
  926. function setupEventListeners(reference, options, state, updateBound) {
  927. // Resize event listener on window
  928. state.updateBound = updateBound;
  929. getWindow(reference).addEventListener('resize', state.updateBound, { passive: true });
  930. // Scroll event listener on scroll parents
  931. var scrollElement = getScrollParent(reference);
  932. attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents);
  933. state.scrollElement = scrollElement;
  934. state.eventsEnabled = true;
  935. return state;
  936. }
  937. // This is here just for backward compatibility with versions lower than v1.10.3
  938. // you should import the utilities using named exports, if you want them all use:
  939. // ```
  940. // import * as PopperUtils from 'popper-utils';
  941. // ```
  942. // The default export will be removed in the next major version.
  943. var index = {
  944. computeAutoPlacement: computeAutoPlacement,
  945. debounce: debounce,
  946. findIndex: findIndex,
  947. getBordersSize: getBordersSize,
  948. getBoundaries: getBoundaries,
  949. getBoundingClientRect: getBoundingClientRect,
  950. getClientRect: getClientRect,
  951. getOffsetParent: getOffsetParent,
  952. getOffsetRect: getOffsetRect,
  953. getOffsetRectRelativeToArbitraryNode: getOffsetRectRelativeToArbitraryNode,
  954. getOuterSizes: getOuterSizes,
  955. getParentNode: getParentNode,
  956. getPopperOffsets: getPopperOffsets,
  957. getReferenceOffsets: getReferenceOffsets,
  958. getScroll: getScroll,
  959. getScrollParent: getScrollParent,
  960. getStyleComputedProperty: getStyleComputedProperty,
  961. getSupportedPropertyName: getSupportedPropertyName,
  962. getWindowSizes: getWindowSizes,
  963. isFixed: isFixed,
  964. isFunction: isFunction,
  965. isModifierEnabled: isModifierEnabled,
  966. isModifierRequired: isModifierRequired,
  967. isNumeric: isNumeric,
  968. removeEventListeners: removeEventListeners,
  969. runModifiers: runModifiers,
  970. setAttributes: setAttributes,
  971. setStyles: setStyles,
  972. setupEventListeners: setupEventListeners
  973. };
  974. export { computeAutoPlacement, debounce, findIndex, getBordersSize, getBoundaries, getBoundingClientRect, getClientRect, getOffsetParent, getOffsetRect, getOffsetRectRelativeToArbitraryNode, getOuterSizes, getParentNode, getPopperOffsets, getReferenceOffsets, getScroll, getScrollParent, getStyleComputedProperty, getSupportedPropertyName, getWindowSizes, isFixed, isFunction, isModifierEnabled, isModifierRequired, isNumeric, removeEventListeners, runModifiers, setAttributes, setStyles, setupEventListeners };
  975. export default index;