2019-08-09 19:13:18 +03:00
|
|
|
///
|
|
|
|
|
/// 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<Event> {
|
|
|
|
|
const scrollSubject = new Subject<Event>();
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-20 20:42:48 +03:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-03 19:31:16 +03:00
|
|
|
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';
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-09 19:13:18 +03:00
|
|
|
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;
|
|
|
|
|
}
|
2019-09-03 19:31:16 +03:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
);
|
|
|
|
|
}
|