Skip to content
Snippets Groups Projects
Verified Commit 12dc7d7b authored by Volker Schukai's avatar Volker Schukai :alien:
Browse files

feat: add util.findElementWithIdUpwards

parent 7c422694
Branches
Tags
No related merge requests found
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
import { getGlobal } from "../types/global.mjs"; import { getGlobal } from "../types/global.mjs";
import { validateString } from "../types/validate.mjs"; import { validateString } from "../types/validate.mjs";
export { getDocument, getWindow, getDocumentFragmentFromString }; export { getDocument, getWindow, getDocumentFragmentFromString, findElementWithIdUpwards };
/** /**
* This method fetches the document object * This method fetches the document object
...@@ -151,3 +151,52 @@ function getDocumentFragmentFromString(html) { ...@@ -151,3 +151,52 @@ function getDocumentFragmentFromString(html) {
return template.content; return template.content;
} }
/**
* Recursively searches upwards from a given element to find an ancestor element
* with a specified ID, considering both normal DOM and shadow DOM.
*
* @param {HTMLElement|ShadowRoot} element - The starting element or shadow root to search from.
* @param {string} targetId - The ID of the target element to find.
* @returns {HTMLElement|null} - The ancestor element with the specified ID, or null if not found.
* @memberOf Monster.DOM
* @since 3.29.0
* @license AGPLv3
* @copyright schukai GmbH
*/
function findElementWithIdUpwards(element, targetId) {
if (!element) {
return null;
}
// Check if the current element has the target ID
if (element.id === targetId) {
return element;
}
// Search within the current element's shadow root, if it exists
if (element.shadowRoot) {
const target = element.shadowRoot.getElementById(targetId);
if (target) {
return target;
}
}
// If the current element is the document.documentElement, search within the main document
if (element === document.documentElement) {
const target = document.getElementById(targetId);
if (target) {
return target;
}
}
// If the current element is inside a shadow root, search its host's ancestors
const rootNode = element.getRootNode();
if (rootNode && rootNode instanceof ShadowRoot) {
return findElementWithIdUpwards(rootNode.host, targetId);
}
// Otherwise, search the current element's parent
return findElementWithIdUpwards(element.parentElement, targetId);
}
\ No newline at end of file
import {
findElementWithIdUpwards
} from "../../../../application/source/dom/util.mjs";
import { expect } from 'chai';
import { JSDOM } from 'jsdom';
let originalEnvironment;
function setupTestEnvironment() {
const { window } = new JSDOM('<!DOCTYPE html>', { pretendToBeVisual: true });
const { document, customElements, HTMLElement } = window;
originalEnvironment = {
document: globalThis.document,
customElements: globalThis.customElements,
HTMLElement: globalThis.HTMLElement,
ShadowRoot: globalThis.ShadowRoot,
};
globalThis.document = document;
globalThis.customElements = customElements;
globalThis.HTMLElement = HTMLElement;
globalThis.ShadowRoot = window.ShadowRoot || class ShadowRoot {}; // Fallback for JSDOM
class TestComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
}
if (!customElements.get('test-component')) {
customElements.define('test-component', TestComponent);
}
}
function cleanupTestEnvironment() {
Object.assign(globalThis, originalEnvironment);
}
describe('findElementWithIdUpwards', () => {
before(() => {
setupTestEnvironment();
});
after(() => {
cleanupTestEnvironment();
});
beforeEach(() => {
// Set up the DOM
document.body.innerHTML = `
<div id="container">
<div id="parent">
<div id="child"></div>
</div>
</div>
`;
const shadowHost = document.createElement('div');
document.body.appendChild(shadowHost);
const shadowRoot = shadowHost.attachShadow({ mode: 'open' });
const innerElement = document.createElement('div');
innerElement.id = 'inner';
shadowRoot.appendChild(innerElement);
});
it('should find the element with the target ID in the normal DOM', () => {
const child = document.getElementById('child');
const result = findElementWithIdUpwards(child, 'parent');
expect(result).to.equal(document.getElementById('parent'));
});
it('should find the element with the target ID in the shadow DOM', () => {
const innerElement = document.querySelector('div[shadowroot] > div');
const result = findElementWithIdUpwards(innerElement, 'inner');
expect(result).to.equal(innerElement);
});
it('should return null if the element with the target ID is not found', () => {
const child = document.getElementById('child');
const result = findElementWithIdUpwards(child, 'nonexistent');
expect(result).to.be.null;
});
});
'use strict';
import { import {
getDocument, getWindow, getDocumentFragmentFromString getDocument, getWindow, getDocumentFragmentFromString
} from "../../../../application/source/dom/util.mjs"; } from "../../../../application/source/dom/util.mjs";
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment