/// /// Copyright © 2016-2019 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { finalize, share } from 'rxjs/operators'; export function onParentScrollOrWindowResize(el: Node): Observable { const scrollSubject = new Subject(); const scrollParentNodes = scrollParents(el); const eventListenerObject: EventListenerObject = { handleEvent(evt: Event) { scrollSubject.next(evt); } }; scrollParentNodes.forEach((scrollParentNode) => { scrollParentNode.addEventListener('scroll', eventListenerObject); }); window.addEventListener('resize', eventListenerObject); const shared = scrollSubject.pipe( finalize(() => { scrollParentNodes.forEach((scrollParentNode) => { scrollParentNode.removeEventListener('scroll', eventListenerObject); }); window.removeEventListener('resize', eventListenerObject); }), share() ); return shared; } export function isLocalUrl(url: string): boolean { const parser = document.createElement('a'); parser.href = url; const host = parser.hostname; if (host === 'localhost' || host === '127.0.0.1') { return true; } else { return false; } } export function animatedScroll(element: HTMLElement, scrollTop: number, delay?: number) { let currentTime = 0; const increment = 20; const start = element.scrollTop; const to = scrollTop; const duration = delay ? delay : 0; const remaining = to - start; const animateScroll = () => { currentTime += increment; const val = easeInOut(currentTime, start, remaining, duration); element.scrollTop = val; if (currentTime < duration) { setTimeout(animateScroll, increment); } }; animateScroll(); } export function isUndefined(value: any): boolean { return typeof value === 'undefined'; } export function isDefined(value: any): boolean { return typeof value !== 'undefined'; } const scrollRegex = /(auto|scroll)/; function parentNodes(node: Node, nodes: Node[]): Node[] { if (node.parentNode === null) { return nodes; } return parentNodes(node.parentNode, nodes.concat([node])); } function style(el: Element, prop: string): string { return getComputedStyle(el, null).getPropertyValue(prop); } function overflow(el: Element): string { return style(el, 'overflow') + style(el, 'overflow-y') + style(el, 'overflow-x'); } function isScrollNode(node: Node): boolean { if (node instanceof Element) { return scrollRegex.test(overflow(node)); } else { return false; } } function scrollParents(node: Node): Node[] { if (!(node instanceof HTMLElement || node instanceof SVGElement)) { return []; } const scrollParentNodes = []; const nodeParents = parentNodes(node, []); nodeParents.forEach((nodeParent) => { if (isScrollNode(nodeParent)) { scrollParentNodes.push(nodeParent); } }); if (document.scrollingElement) { scrollParentNodes.push(document.scrollingElement); } else if (document.documentElement) { scrollParentNodes.push(document.documentElement); } return scrollParentNodes; } function easeInOut( currentTime: number, startTime: number, remainingTime: number, duration: number) { currentTime /= duration / 2; if (currentTime < 1) { return (remainingTime / 2) * currentTime * currentTime + startTime; } currentTime--; return ( (-remainingTime / 2) * (currentTime * (currentTime - 2) - 1) + startTime ); }