Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

| Ultima modificación | Ver Log |

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