1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | class DomHandler {
|
11 | static addClass(element, className) {
|
12 | if (element.classList)
|
13 | element.classList.add(className);
|
14 | else
|
15 | element.className += ' ' + className;
|
16 | }
|
17 | static addMultipleClasses(element, className) {
|
18 | if (element.classList) {
|
19 | let styles = className.split(' ');
|
20 | for (let i = 0; i < styles.length; i++) {
|
21 | element.classList.add(styles[i]);
|
22 | }
|
23 | }
|
24 | else {
|
25 | let styles = className.split(' ');
|
26 | for (let i = 0; i < styles.length; i++) {
|
27 | element.className += ' ' + styles[i];
|
28 | }
|
29 | }
|
30 | }
|
31 | static removeClass(element, className) {
|
32 | if (element.classList)
|
33 | element.classList.remove(className);
|
34 | else
|
35 | element.className = element.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
|
36 | }
|
37 | static hasClass(element, className) {
|
38 | if (element.classList)
|
39 | return element.classList.contains(className);
|
40 | else
|
41 | return new RegExp('(^| )' + className + '( |$)', 'gi').test(element.className);
|
42 | }
|
43 | static siblings(element) {
|
44 | return Array.prototype.filter.call(element.parentNode.children, function (child) {
|
45 | return child !== element;
|
46 | });
|
47 | }
|
48 | static find(element, selector) {
|
49 | return Array.from(element.querySelectorAll(selector));
|
50 | }
|
51 | static findSingle(element, selector) {
|
52 | if (element) {
|
53 | return element.querySelector(selector);
|
54 | }
|
55 | return null;
|
56 | }
|
57 | static index(element) {
|
58 | let children = element.parentNode.childNodes;
|
59 | let num = 0;
|
60 | for (var i = 0; i < children.length; i++) {
|
61 | if (children[i] == element)
|
62 | return num;
|
63 | if (children[i].nodeType == 1)
|
64 | num++;
|
65 | }
|
66 | return -1;
|
67 | }
|
68 | static indexWithinGroup(element, attributeName) {
|
69 | let children = element.parentNode ? element.parentNode.childNodes : [];
|
70 | let num = 0;
|
71 | for (var i = 0; i < children.length; i++) {
|
72 | if (children[i] == element)
|
73 | return num;
|
74 | if (children[i].attributes && children[i].attributes[attributeName] && children[i].nodeType == 1)
|
75 | num++;
|
76 | }
|
77 | return -1;
|
78 | }
|
79 | static relativePosition(element, target) {
|
80 | let elementDimensions = element.offsetParent ? { width: element.offsetWidth, height: element.offsetHeight } : this.getHiddenElementDimensions(element);
|
81 | const targetHeight = target.offsetHeight;
|
82 | const targetOffset = target.getBoundingClientRect();
|
83 | const viewport = this.getViewport();
|
84 | let top, left;
|
85 | if ((targetOffset.top + targetHeight + elementDimensions.height) > viewport.height) {
|
86 | top = -1 * (elementDimensions.height);
|
87 | element.style.transformOrigin = 'bottom';
|
88 | if (targetOffset.top + top < 0) {
|
89 | top = -1 * targetOffset.top;
|
90 | }
|
91 | }
|
92 | else {
|
93 | top = targetHeight;
|
94 | element.style.transformOrigin = 'top';
|
95 | }
|
96 | if (elementDimensions.width > viewport.width) {
|
97 |
|
98 | left = targetOffset.left * -1;
|
99 | }
|
100 | else if ((targetOffset.left + elementDimensions.width) > viewport.width) {
|
101 |
|
102 | left = (targetOffset.left + elementDimensions.width - viewport.width) * -1;
|
103 | }
|
104 | else {
|
105 |
|
106 | left = 0;
|
107 | }
|
108 | element.style.top = top + 'px';
|
109 | element.style.left = left + 'px';
|
110 | }
|
111 | static absolutePosition(element, target) {
|
112 | let elementDimensions = element.offsetParent ? { width: element.offsetWidth, height: element.offsetHeight } : this.getHiddenElementDimensions(element);
|
113 | let elementOuterHeight = elementDimensions.height;
|
114 | let elementOuterWidth = elementDimensions.width;
|
115 | let targetOuterHeight = target.offsetHeight;
|
116 | let targetOuterWidth = target.offsetWidth;
|
117 | let targetOffset = target.getBoundingClientRect();
|
118 | let windowScrollTop = this.getWindowScrollTop();
|
119 | let windowScrollLeft = this.getWindowScrollLeft();
|
120 | let viewport = this.getViewport();
|
121 | let top, left;
|
122 | if (targetOffset.top + targetOuterHeight + elementOuterHeight > viewport.height) {
|
123 | top = targetOffset.top + windowScrollTop - elementOuterHeight;
|
124 | element.style.transformOrigin = 'bottom';
|
125 | if (top < 0) {
|
126 | top = windowScrollTop;
|
127 | }
|
128 | }
|
129 | else {
|
130 | top = targetOuterHeight + targetOffset.top + windowScrollTop;
|
131 | element.style.transformOrigin = 'top';
|
132 | }
|
133 | if (targetOffset.left + elementOuterWidth > viewport.width)
|
134 | left = Math.max(0, targetOffset.left + windowScrollLeft + targetOuterWidth - elementOuterWidth);
|
135 | else
|
136 | left = targetOffset.left + windowScrollLeft;
|
137 | element.style.top = top + 'px';
|
138 | element.style.left = left + 'px';
|
139 | }
|
140 | static getParents(element, parents = []) {
|
141 | return element['parentNode'] === null ? parents : this.getParents(element.parentNode, parents.concat([element.parentNode]));
|
142 | }
|
143 | static getScrollableParents(element) {
|
144 | let scrollableParents = [];
|
145 | if (element) {
|
146 | let parents = this.getParents(element);
|
147 | const overflowRegex = /(auto|scroll)/;
|
148 | const overflowCheck = (node) => {
|
149 | let styleDeclaration = window['getComputedStyle'](node, null);
|
150 | return overflowRegex.test(styleDeclaration.getPropertyValue('overflow')) || overflowRegex.test(styleDeclaration.getPropertyValue('overflowX')) || overflowRegex.test(styleDeclaration.getPropertyValue('overflowY'));
|
151 | };
|
152 | for (let parent of parents) {
|
153 | let scrollSelectors = parent.nodeType === 1 && parent.dataset['scrollselectors'];
|
154 | if (scrollSelectors) {
|
155 | let selectors = scrollSelectors.split(',');
|
156 | for (let selector of selectors) {
|
157 | let el = this.findSingle(parent, selector);
|
158 | if (el && overflowCheck(el)) {
|
159 | scrollableParents.push(el);
|
160 | }
|
161 | }
|
162 | }
|
163 | if (parent.nodeType === 9 || overflowCheck(parent)) {
|
164 | scrollableParents.push(parent);
|
165 | }
|
166 | }
|
167 | }
|
168 | return scrollableParents;
|
169 | }
|
170 | static getHiddenElementOuterHeight(element) {
|
171 | element.style.visibility = 'hidden';
|
172 | element.style.display = 'block';
|
173 | let elementHeight = element.offsetHeight;
|
174 | element.style.display = 'none';
|
175 | element.style.visibility = 'visible';
|
176 | return elementHeight;
|
177 | }
|
178 | static getHiddenElementOuterWidth(element) {
|
179 | element.style.visibility = 'hidden';
|
180 | element.style.display = 'block';
|
181 | let elementWidth = element.offsetWidth;
|
182 | element.style.display = 'none';
|
183 | element.style.visibility = 'visible';
|
184 | return elementWidth;
|
185 | }
|
186 | static getHiddenElementDimensions(element) {
|
187 | let dimensions = {};
|
188 | element.style.visibility = 'hidden';
|
189 | element.style.display = 'block';
|
190 | dimensions.width = element.offsetWidth;
|
191 | dimensions.height = element.offsetHeight;
|
192 | element.style.display = 'none';
|
193 | element.style.visibility = 'visible';
|
194 | return dimensions;
|
195 | }
|
196 | static scrollInView(container, item) {
|
197 | let borderTopValue = getComputedStyle(container).getPropertyValue('borderTopWidth');
|
198 | let borderTop = borderTopValue ? parseFloat(borderTopValue) : 0;
|
199 | let paddingTopValue = getComputedStyle(container).getPropertyValue('paddingTop');
|
200 | let paddingTop = paddingTopValue ? parseFloat(paddingTopValue) : 0;
|
201 | let containerRect = container.getBoundingClientRect();
|
202 | let itemRect = item.getBoundingClientRect();
|
203 | let offset = (itemRect.top + document.body.scrollTop) - (containerRect.top + document.body.scrollTop) - borderTop - paddingTop;
|
204 | let scroll = container.scrollTop;
|
205 | let elementHeight = container.clientHeight;
|
206 | let itemHeight = this.getOuterHeight(item);
|
207 | if (offset < 0) {
|
208 | container.scrollTop = scroll + offset;
|
209 | }
|
210 | else if ((offset + itemHeight) > elementHeight) {
|
211 | container.scrollTop = scroll + offset - elementHeight + itemHeight;
|
212 | }
|
213 | }
|
214 | static fadeIn(element, duration) {
|
215 | element.style.opacity = 0;
|
216 | let last = +new Date();
|
217 | let opacity = 0;
|
218 | let tick = function () {
|
219 | opacity = +element.style.opacity.replace(",", ".") + (new Date().getTime() - last) / duration;
|
220 | element.style.opacity = opacity;
|
221 | last = +new Date();
|
222 | if (+opacity < 1) {
|
223 | (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
|
224 | }
|
225 | };
|
226 | tick();
|
227 | }
|
228 | static fadeOut(element, ms) {
|
229 | var opacity = 1, interval = 50, duration = ms, gap = interval / duration;
|
230 | let fading = setInterval(() => {
|
231 | opacity = opacity - gap;
|
232 | if (opacity <= 0) {
|
233 | opacity = 0;
|
234 | clearInterval(fading);
|
235 | }
|
236 | element.style.opacity = opacity;
|
237 | }, interval);
|
238 | }
|
239 | static getWindowScrollTop() {
|
240 | let doc = document.documentElement;
|
241 | return (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
|
242 | }
|
243 | static getWindowScrollLeft() {
|
244 | let doc = document.documentElement;
|
245 | return (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
|
246 | }
|
247 | static matches(element, selector) {
|
248 | var p = Element.prototype;
|
249 | var f = p['matches'] || p.webkitMatchesSelector || p['mozMatchesSelector'] || p['msMatchesSelector'] || function (s) {
|
250 | return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
|
251 | };
|
252 | return f.call(element, selector);
|
253 | }
|
254 | static getOuterWidth(el, margin) {
|
255 | let width = el.offsetWidth;
|
256 | if (margin) {
|
257 | let style = getComputedStyle(el);
|
258 | width += parseFloat(style.marginLeft) + parseFloat(style.marginRight);
|
259 | }
|
260 | return width;
|
261 | }
|
262 | static getHorizontalPadding(el) {
|
263 | let style = getComputedStyle(el);
|
264 | return parseFloat(style.paddingLeft) + parseFloat(style.paddingRight);
|
265 | }
|
266 | static getHorizontalMargin(el) {
|
267 | let style = getComputedStyle(el);
|
268 | return parseFloat(style.marginLeft) + parseFloat(style.marginRight);
|
269 | }
|
270 | static innerWidth(el) {
|
271 | let width = el.offsetWidth;
|
272 | let style = getComputedStyle(el);
|
273 | width += parseFloat(style.paddingLeft) + parseFloat(style.paddingRight);
|
274 | return width;
|
275 | }
|
276 | static width(el) {
|
277 | let width = el.offsetWidth;
|
278 | let style = getComputedStyle(el);
|
279 | width -= parseFloat(style.paddingLeft) + parseFloat(style.paddingRight);
|
280 | return width;
|
281 | }
|
282 | static getInnerHeight(el) {
|
283 | let height = el.offsetHeight;
|
284 | let style = getComputedStyle(el);
|
285 | height += parseFloat(style.paddingTop) + parseFloat(style.paddingBottom);
|
286 | return height;
|
287 | }
|
288 | static getOuterHeight(el, margin) {
|
289 | let height = el.offsetHeight;
|
290 | if (margin) {
|
291 | let style = getComputedStyle(el);
|
292 | height += parseFloat(style.marginTop) + parseFloat(style.marginBottom);
|
293 | }
|
294 | return height;
|
295 | }
|
296 | static getHeight(el) {
|
297 | let height = el.offsetHeight;
|
298 | let style = getComputedStyle(el);
|
299 | height -= parseFloat(style.paddingTop) + parseFloat(style.paddingBottom) + parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);
|
300 | return height;
|
301 | }
|
302 | static getWidth(el) {
|
303 | let width = el.offsetWidth;
|
304 | let style = getComputedStyle(el);
|
305 | width -= parseFloat(style.paddingLeft) + parseFloat(style.paddingRight) + parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth);
|
306 | return width;
|
307 | }
|
308 | static getViewport() {
|
309 | let win = window, d = document, e = d.documentElement, g = d.getElementsByTagName('body')[0], w = win.innerWidth || e.clientWidth || g.clientWidth, h = win.innerHeight || e.clientHeight || g.clientHeight;
|
310 | return { width: w, height: h };
|
311 | }
|
312 | static getOffset(el) {
|
313 | var rect = el.getBoundingClientRect();
|
314 | return {
|
315 | top: rect.top + (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0),
|
316 | left: rect.left + (window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0),
|
317 | };
|
318 | }
|
319 | static replaceElementWith(element, replacementElement) {
|
320 | let parentNode = element.parentNode;
|
321 | if (!parentNode)
|
322 | throw `Can't replace element`;
|
323 | return parentNode.replaceChild(replacementElement, element);
|
324 | }
|
325 | static getUserAgent() {
|
326 | return navigator.userAgent;
|
327 | }
|
328 | static isIE() {
|
329 | var ua = window.navigator.userAgent;
|
330 | var msie = ua.indexOf('MSIE ');
|
331 | if (msie > 0) {
|
332 |
|
333 | return true;
|
334 | }
|
335 | var trident = ua.indexOf('Trident/');
|
336 | if (trident > 0) {
|
337 |
|
338 | var rv = ua.indexOf('rv:');
|
339 | return true;
|
340 | }
|
341 | var edge = ua.indexOf('Edge/');
|
342 | if (edge > 0) {
|
343 |
|
344 | return true;
|
345 | }
|
346 |
|
347 | return false;
|
348 | }
|
349 | static isIOS() {
|
350 | return /iPad|iPhone|iPod/.test(navigator.userAgent) && !window['MSStream'];
|
351 | }
|
352 | static isAndroid() {
|
353 | return /(android)/i.test(navigator.userAgent);
|
354 | }
|
355 | static appendChild(element, target) {
|
356 | if (this.isElement(target))
|
357 | target.appendChild(element);
|
358 | else if (target.el && target.el.nativeElement)
|
359 | target.el.nativeElement.appendChild(element);
|
360 | else
|
361 | throw 'Cannot append ' + target + ' to ' + element;
|
362 | }
|
363 | static removeChild(element, target) {
|
364 | if (this.isElement(target))
|
365 | target.removeChild(element);
|
366 | else if (target.el && target.el.nativeElement)
|
367 | target.el.nativeElement.removeChild(element);
|
368 | else
|
369 | throw 'Cannot remove ' + element + ' from ' + target;
|
370 | }
|
371 | static removeElement(element) {
|
372 | if (!('remove' in Element.prototype))
|
373 | element.parentNode.removeChild(element);
|
374 | else
|
375 | element.remove();
|
376 | }
|
377 | static isElement(obj) {
|
378 | return (typeof HTMLElement === "object" ? obj instanceof HTMLElement :
|
379 | obj && typeof obj === "object" && obj !== null && obj.nodeType === 1 && typeof obj.nodeName === "string");
|
380 | }
|
381 | static calculateScrollbarWidth(el) {
|
382 | if (el) {
|
383 | let style = getComputedStyle(el);
|
384 | return (el.offsetWidth - el.clientWidth - parseFloat(style.borderLeftWidth) - parseFloat(style.borderRightWidth));
|
385 | }
|
386 | else {
|
387 | if (this.calculatedScrollbarWidth !== null)
|
388 | return this.calculatedScrollbarWidth;
|
389 | let scrollDiv = document.createElement("div");
|
390 | scrollDiv.className = "p-scrollbar-measure";
|
391 | document.body.appendChild(scrollDiv);
|
392 | let scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
|
393 | document.body.removeChild(scrollDiv);
|
394 | this.calculatedScrollbarWidth = scrollbarWidth;
|
395 | return scrollbarWidth;
|
396 | }
|
397 | }
|
398 | static calculateScrollbarHeight() {
|
399 | if (this.calculatedScrollbarHeight !== null)
|
400 | return this.calculatedScrollbarHeight;
|
401 | let scrollDiv = document.createElement("div");
|
402 | scrollDiv.className = "p-scrollbar-measure";
|
403 | document.body.appendChild(scrollDiv);
|
404 | let scrollbarHeight = scrollDiv.offsetHeight - scrollDiv.clientHeight;
|
405 | document.body.removeChild(scrollDiv);
|
406 | this.calculatedScrollbarWidth = scrollbarHeight;
|
407 | return scrollbarHeight;
|
408 | }
|
409 | static invokeElementMethod(element, methodName, args) {
|
410 | element[methodName].apply(element, args);
|
411 | }
|
412 | static clearSelection() {
|
413 | if (window.getSelection) {
|
414 | if (window.getSelection().empty) {
|
415 | window.getSelection().empty();
|
416 | }
|
417 | else if (window.getSelection().removeAllRanges && window.getSelection().rangeCount > 0 && window.getSelection().getRangeAt(0).getClientRects().length > 0) {
|
418 | window.getSelection().removeAllRanges();
|
419 | }
|
420 | }
|
421 | else if (document['selection'] && document['selection'].empty) {
|
422 | try {
|
423 | document['selection'].empty();
|
424 | }
|
425 | catch (error) {
|
426 |
|
427 | }
|
428 | }
|
429 | }
|
430 | static getBrowser() {
|
431 | if (!this.browser) {
|
432 | let matched = this.resolveUserAgent();
|
433 | this.browser = {};
|
434 | if (matched.browser) {
|
435 | this.browser[matched.browser] = true;
|
436 | this.browser['version'] = matched.version;
|
437 | }
|
438 | if (this.browser['chrome']) {
|
439 | this.browser['webkit'] = true;
|
440 | }
|
441 | else if (this.browser['webkit']) {
|
442 | this.browser['safari'] = true;
|
443 | }
|
444 | }
|
445 | return this.browser;
|
446 | }
|
447 | static resolveUserAgent() {
|
448 | let ua = navigator.userAgent.toLowerCase();
|
449 | let match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
|
450 | /(webkit)[ \/]([\w.]+)/.exec(ua) ||
|
451 | /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
|
452 | /(msie) ([\w.]+)/.exec(ua) ||
|
453 | ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
|
454 | [];
|
455 | return {
|
456 | browser: match[1] || "",
|
457 | version: match[2] || "0"
|
458 | };
|
459 | }
|
460 | static isInteger(value) {
|
461 | if (Number.isInteger) {
|
462 | return Number.isInteger(value);
|
463 | }
|
464 | else {
|
465 | return typeof value === "number" && isFinite(value) && Math.floor(value) === value;
|
466 | }
|
467 | }
|
468 | static isHidden(element) {
|
469 | return element.offsetParent === null;
|
470 | }
|
471 | static getFocusableElements(element) {
|
472 | let focusableElements = DomHandler.find(element, `button:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden]),
|
473 | [href][clientHeight][clientWidth]:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden]),
|
474 | input:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden]), select:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden]),
|
475 | textarea:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden]), [tabIndex]:not([tabIndex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden]),
|
476 | [contenteditable]:not([tabIndex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])`);
|
477 | let visibleFocusableElements = [];
|
478 | for (let focusableElement of focusableElements) {
|
479 | if (getComputedStyle(focusableElement).display != "none" && getComputedStyle(focusableElement).visibility != "hidden")
|
480 | visibleFocusableElements.push(focusableElement);
|
481 | }
|
482 | return visibleFocusableElements;
|
483 | }
|
484 | static generateZIndex() {
|
485 | this.zindex = this.zindex || 999;
|
486 | return ++this.zindex;
|
487 | }
|
488 | }
|
489 | DomHandler.zindex = 1000;
|
490 | DomHandler.calculatedScrollbarWidth = null;
|
491 | DomHandler.calculatedScrollbarHeight = null;
|
492 |
|
493 | class ConnectedOverlayScrollHandler {
|
494 | constructor(element, listener = () => { }) {
|
495 | this.element = element;
|
496 | this.listener = listener;
|
497 | }
|
498 | bindScrollListener() {
|
499 | this.scrollableParents = DomHandler.getScrollableParents(this.element);
|
500 | for (let i = 0; i < this.scrollableParents.length; i++) {
|
501 | this.scrollableParents[i].addEventListener('scroll', this.listener);
|
502 | }
|
503 | }
|
504 | unbindScrollListener() {
|
505 | if (this.scrollableParents) {
|
506 | for (let i = 0; i < this.scrollableParents.length; i++) {
|
507 | this.scrollableParents[i].removeEventListener('scroll', this.listener);
|
508 | }
|
509 | }
|
510 | }
|
511 | destroy() {
|
512 | this.unbindScrollListener();
|
513 | this.element = null;
|
514 | this.listener = null;
|
515 | this.scrollableParents = null;
|
516 | }
|
517 | }
|
518 |
|
519 |
|
520 |
|
521 |
|
522 |
|
523 | export { ConnectedOverlayScrollHandler, DomHandler };
|
524 |
|