Skip to content

Instantly share code, notes, and snippets.

@anechunaev
Created September 25, 2018 19:13
Show Gist options
  • Save anechunaev/800c6bc5e29ccc17118b55c971f9bb0c to your computer and use it in GitHub Desktop.
Save anechunaev/800c6bc5e29ccc17118b55c971f9bb0c to your computer and use it in GitHub Desktop.
Get element path in DOM (including correct shadow DOM path resolving).
/**
* Return string that represent element position in DOM (usually valid CSS selector). Position is relative to document.body.
*
* ATTENTION!
* If you use shadow DOM on the page, this function will not return valid CSS selector.
*/
export function getPath(element: Element) {
const stack = [];
let el = element;
while (!!el.parentNode) {
let sibCount = 0;
let sibIndex = 0;
for (let i = 0; i < el.parentNode.childNodes.length; i++) {
const sib = el.parentNode.childNodes[i];
if (sib.nodeName === el.nodeName) {
if (sib === el) {
sibIndex = sibCount;
}
sibCount++;
}
}
if (el.hasAttribute('id') && el.id !== '') {
stack.unshift(el.nodeName.toLowerCase() + '#' + el.id);
} else if (sibCount > 1) {
stack.unshift(el.nodeName.toLowerCase() + ':nth-of-type(' + (sibIndex + 1) + ')');
} else {
stack.unshift(el.nodeName.toLowerCase());
}
el = el.parentNode as Element;
if (!el.parentNode) {
if (typeof (el as any).host !== 'undefined') {
stack.unshift(':shadow');
el = (el as any).host;
} else {
el = { parentNode: null } as Element;
}
}
}
return stack.slice(2, stack.length).join(' ');
}
/**
* Return element by path string that is generated by function above.
*/
export function getElementByPath(path: string, source: any = document.body) {
const parts = path.split(':shadow');
let parent = source;
let result;
for (let i = 0; i < parts.length; i++) {
const fragment = parent.querySelector(parts[i]);
if (i + 1 < parts.length) {
parent = fragment.shadowRoot;
} else {
result = fragment;
}
}
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment