SafetyScreen-ui/node_modules/@interactjs/utils/domUtils.js

224 lines
6.2 KiB
JavaScript
Raw Normal View History

2025-03-29 19:33:58 +08:00
import browser from "./browser.js";
import domObjects from "./domObjects.js";
import is from "./is.js";
import * as win from "./window.js";
export function nodeContains(parent, child) {
if (parent.contains) {
return parent.contains(child);
}
while (child) {
if (child === parent) {
return true;
}
child = child.parentNode;
}
return false;
}
export function closest(element, selector) {
while (is.element(element)) {
if (matchesSelector(element, selector)) {
return element;
}
element = parentNode(element);
}
return null;
}
export function parentNode(node) {
let parent = node.parentNode;
if (is.docFrag(parent)) {
// skip past #shado-root fragments
// tslint:disable-next-line
while ((parent = parent.host) && is.docFrag(parent)) {
continue;
}
return parent;
}
return parent;
}
export function matchesSelector(element, selector) {
// remove /deep/ from selectors if shadowDOM polyfill is used
if (win.window !== win.realWindow) {
selector = selector.replace(/\/deep\//g, ' ');
}
return element[browser.prefixedMatchesSelector](selector);
}
const getParent = el => el.parentNode || el.host; // Test for the element that's "above" all other qualifiers
export function indexOfDeepestElement(elements) {
let deepestNodeParents = [];
let deepestNodeIndex;
for (let i = 0; i < elements.length; i++) {
const currentNode = elements[i];
const deepestNode = elements[deepestNodeIndex]; // node may appear in elements array multiple times
if (!currentNode || i === deepestNodeIndex) {
continue;
}
if (!deepestNode) {
deepestNodeIndex = i;
continue;
}
const currentNodeParent = getParent(currentNode);
const deepestNodeParent = getParent(deepestNode); // check if the deepest or current are document.documentElement/rootElement
// - if the current node is, do nothing and continue
if (currentNodeParent === currentNode.ownerDocument) {
continue;
} // - if deepest is, update with the current node and continue to next
else if (deepestNodeParent === currentNode.ownerDocument) {
deepestNodeIndex = i;
continue;
} // compare zIndex of siblings
if (currentNodeParent === deepestNodeParent) {
if (zIndexIsHigherThan(currentNode, deepestNode)) {
deepestNodeIndex = i;
}
continue;
} // populate the ancestry array for the latest deepest node
deepestNodeParents = deepestNodeParents.length ? deepestNodeParents : getNodeParents(deepestNode);
let ancestryStart; // if the deepest node is an HTMLElement and the current node is a non root svg element
if (deepestNode instanceof domObjects.HTMLElement && currentNode instanceof domObjects.SVGElement && !(currentNode instanceof domObjects.SVGSVGElement)) {
// TODO: is this check necessary? Was this for HTML elements embedded in SVG?
if (currentNode === deepestNodeParent) {
continue;
}
ancestryStart = currentNode.ownerSVGElement;
} else {
ancestryStart = currentNode;
}
const currentNodeParents = getNodeParents(ancestryStart, deepestNode.ownerDocument);
let commonIndex = 0; // get (position of closest common ancestor) + 1
while (currentNodeParents[commonIndex] && currentNodeParents[commonIndex] === deepestNodeParents[commonIndex]) {
commonIndex++;
}
const parents = [currentNodeParents[commonIndex - 1], currentNodeParents[commonIndex], deepestNodeParents[commonIndex]];
let child = parents[0].lastChild;
while (child) {
if (child === parents[1]) {
deepestNodeIndex = i;
deepestNodeParents = currentNodeParents;
break;
} else if (child === parents[2]) {
break;
}
child = child.previousSibling;
}
}
return deepestNodeIndex;
}
function getNodeParents(node, limit) {
const parents = [];
let parent = node;
let parentParent;
while ((parentParent = getParent(parent)) && parent !== limit && parentParent !== parent.ownerDocument) {
parents.unshift(parent);
parent = parentParent;
}
return parents;
}
function zIndexIsHigherThan(higherNode, lowerNode) {
const higherIndex = parseInt(win.getWindow(higherNode).getComputedStyle(higherNode).zIndex, 10) || 0;
const lowerIndex = parseInt(win.getWindow(lowerNode).getComputedStyle(lowerNode).zIndex, 10) || 0;
return higherIndex >= lowerIndex;
}
export function matchesUpTo(element, selector, limit) {
while (is.element(element)) {
if (matchesSelector(element, selector)) {
return true;
}
element = parentNode(element);
if (element === limit) {
return matchesSelector(element, selector);
}
}
return false;
}
export function getActualElement(element) {
return element.correspondingUseElement || element;
}
export function getScrollXY(relevantWindow) {
relevantWindow = relevantWindow || win.window;
return {
x: relevantWindow.scrollX || relevantWindow.document.documentElement.scrollLeft,
y: relevantWindow.scrollY || relevantWindow.document.documentElement.scrollTop
};
}
export function getElementClientRect(element) {
const clientRect = element instanceof domObjects.SVGElement ? element.getBoundingClientRect() : element.getClientRects()[0];
return clientRect && {
left: clientRect.left,
right: clientRect.right,
top: clientRect.top,
bottom: clientRect.bottom,
width: clientRect.width || clientRect.right - clientRect.left,
height: clientRect.height || clientRect.bottom - clientRect.top
};
}
export function getElementRect(element) {
const clientRect = getElementClientRect(element);
if (!browser.isIOS7 && clientRect) {
const scroll = getScrollXY(win.getWindow(element));
clientRect.left += scroll.x;
clientRect.right += scroll.x;
clientRect.top += scroll.y;
clientRect.bottom += scroll.y;
}
return clientRect;
}
export function getPath(node) {
const path = [];
while (node) {
path.push(node);
node = parentNode(node);
}
return path;
}
export function trySelector(value) {
if (!is.string(value)) {
return false;
} // an exception will be raised if it is invalid
domObjects.document.querySelector(value);
return true;
}
//# sourceMappingURL=domUtils.js.map