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