import cloneNode from './cloneNode.js';
/**
* Clones an element and its ancestor chain up to and including the first ancestor that matches the given selector. Optionally includes siblings of each cloned ancestor.
*
* @param {Element} element - An Element to start cloning from
* @param {string} selector - A String CSS selector that determines where to stop cloning ancestors
* @param {Object} [options={}] - An Object with optional configuration:
* - `siblings.exclude`: A CSS selector string to exclude matching sibling elements from being cloned
* @returns {Element} The cloned element with its ancestor chain
*/
export default function cloneUp (el, selector, options={}) {
const clone = cloneNode(el)
if (el.matches(selector)) {
return clone
}
if (!el.parentElement) {
return clone
}
const parentClone = cloneUp(el.parentElement, selector)
const shouldExclude = (node) =>
options.siblings?.exclude &&
node instanceof Element &&
node.matches(options.siblings.exclude)
// Clone previous siblings
let cursor = el.previousSibling
while (cursor) {
if (!shouldExclude(cursor)) {
parentClone.prepend(cloneNode(cursor, true))
}
cursor = cursor.previousSibling
}
// Add current element clone
parentClone.append(clone)
// Clone next siblings
cursor = el.nextSibling
while (cursor) {
if (!shouldExclude(cursor)) {
parentClone.append(cloneNode(cursor, true))
}
cursor = cursor.nextSibling
}
return clone
}