import browser from "./browser.js"; import domObjects from "./domObjects.js"; import * as is from "./is.js"; import win, { getWindow } from "./window.js"; export function nodeContains(parent, 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.parentNode : el.host; // Test for the element that's "above" all other qualifiers export function indexOfDeepestElement(elements) { let deepestZoneParents = []; let deepestZone = elements[0]; let index = deepestZone ? 0 : -1; let i; let n; for (i = 1; i < elements.length; i++) { const dropzone = elements[i]; // an element might belong to multiple selector dropzones if (!dropzone || dropzone === deepestZone) { continue; } if (!deepestZone) { deepestZone = dropzone; index = i; continue; } // check if the deepest or current are document.documentElement or document.rootElement // - if the current dropzone is, do nothing and continue if (dropzone.parentNode === dropzone.ownerDocument) { continue; } // - if deepest is, update with the current dropzone and continue to next else if (deepestZone.parentNode === dropzone.ownerDocument) { deepestZone = dropzone; index = i; continue; } // compare zIndex of siblings if (dropzone.parentNode === deepestZone.parentNode) { const deepestZIndex = parseInt(getWindow(deepestZone).getComputedStyle(deepestZone).zIndex, 10) || 0; const dropzoneZIndex = parseInt(getWindow(dropzone).getComputedStyle(dropzone).zIndex, 10) || 0; if (dropzoneZIndex >= deepestZIndex) { deepestZone = dropzone; index = i; } continue; } // populate the ancestry array for the latest deepest dropzone if (!deepestZoneParents.length) { let parent = deepestZone; let parentParent; while ((parentParent = getParent(parent)) && parentParent !== parent.ownerDocument) { deepestZoneParents.unshift(parent); parent = parentParent; } } let parent; // if this element is an svg element and the current deepest is an // HTMLElement if (deepestZone instanceof domObjects.HTMLElement && dropzone instanceof domObjects.SVGElement && !(dropzone instanceof domObjects.SVGSVGElement)) { if (dropzone === deepestZone.parentNode) { continue; } parent = dropzone.ownerSVGElement; } else { parent = dropzone; } const dropzoneParents = []; while (parent.parentNode !== parent.ownerDocument) { dropzoneParents.unshift(parent); parent = getParent(parent); } n = 0; // get (position of last common ancestor) + 1 while (dropzoneParents[n] && dropzoneParents[n] === deepestZoneParents[n]) { n++; } const parents = [dropzoneParents[n - 1], dropzoneParents[n], deepestZoneParents[n]]; let child = parents[0].lastChild; while (child) { if (child === parents[1]) { deepestZone = dropzone; index = i; deepestZoneParents = dropzoneParents; break; } else if (child === parents[2]) { break; } child = child.previousSibling; } } return index; } 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 instanceof domObjects.SVGElementInstance ? 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