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

feat: new function getContainingDocument

parent 911ecbed
No related branches found
No related tags found
No related merge requests found
lockfileVersion: '6.0'
...@@ -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, findElementWithIdUpwards }; export { getDocument, getWindow, getDocumentFragmentFromString, findElementWithIdUpwards,getContainingDocument };
/** /**
* This method fetches the document object * This method fetches the document object
...@@ -199,3 +199,48 @@ function findElementWithIdUpwards(element, targetId) { ...@@ -199,3 +199,48 @@ function findElementWithIdUpwards(element, targetId) {
// Otherwise, search the current element's parent // Otherwise, search the current element's parent
return findElementWithIdUpwards(element.parentElement, targetId); return findElementWithIdUpwards(element.parentElement, targetId);
} }
/**
* @private
* @param {HTMLElement} element
* @returns {HTMLElement|null}
*/
function traverseShadowRoots(element) {
let currentRoot = element.shadowRoot;
let currentParent = element.parentNode;
while (currentParent && currentParent.nodeType !== Node.DOCUMENT_NODE && currentParent.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
if (currentRoot && currentRoot.parentNode) {
currentParent = currentRoot.parentNode;
currentRoot = currentParent.shadowRoot;
} else if (currentParent.parentNode) {
currentParent = currentParent.parentNode;
currentRoot = null;
} else if (currentRoot && currentRoot.host && currentRoot.host.nodeType === Node.DOCUMENT_NODE) {
currentParent = currentRoot.host;
currentRoot = null;
} else {
currentParent = null;
currentRoot = null;
}
}
return currentParent;
}
/**
* Recursively searches upwards from a given element to find an ancestor element
*
* @param {HTMLElement} element
* @returns {*}
* @throws {Error} Invalid argument. Expected an HTMLElement.
* @memberOf Monster.DOM
* @since 3.36.0
*/
function getContainingDocument(element) {
if (!element || !(element instanceof HTMLElement || element instanceof element.ownerDocument.defaultView.HTMLElement)) {
throw new Error('Invalid argument. Expected an HTMLElement.');
}
return traverseShadowRoots(element) || null;
}
This diff is collapsed.
...@@ -2,6 +2,7 @@ import { ...@@ -2,6 +2,7 @@ import {
getDocument, getWindow, getDocumentFragmentFromString getDocument, getWindow, getDocumentFragmentFromString
} from "../../../../application/source/dom/util.mjs"; } from "../../../../application/source/dom/util.mjs";
import {getContainingDocument} from "../../../../application/source/dom/util.mjs";
import {initJSDOM} from "../../util/jsdom.mjs"; import {initJSDOM} from "../../util/jsdom.mjs";
...@@ -52,4 +53,63 @@ describe('DOM', function () { ...@@ -52,4 +53,63 @@ describe('DOM', function () {
}); });
}); });
describe('getContainingDocument', () => {
let jsDomDocument;
beforeEach(() => {
jsDomDocument = getDocument();
});
//
// afterEach(() => {
// dom.window.close();
// });
it('should throw an error when called with an invalid argument', () => {
expect(() => getContainingDocument(null)).to.throw('Invalid argument. Expected an HTMLElement.');
});
it('should return the correct containing document for an element in the main document', () => {
const element = jsDomDocument.createElement('div');
const containingDocument = getContainingDocument(element);
expect(containingDocument).to.null;
});
it('should return the correct containing document for an element inside a shadow root', () => {
const host = jsDomDocument.createElement('div');
const shadowRoot = host.attachShadow({ mode: 'open' });
const element = jsDomDocument.createElement('span');
shadowRoot.appendChild(element);
const containingDocument = getContainingDocument(element);
expect(containingDocument).to.not.null;
});
it('should return the correct containing document for an element inside a nested shadow root', () => {
const outerHost = jsDomDocument.createElement('div');
const outerShadowRoot = outerHost.attachShadow({ mode: 'open' });
const innerHost = jsDomDocument.createElement('div');
outerShadowRoot.appendChild(innerHost);
const innerShadowRoot = innerHost.attachShadow({ mode: 'open' });
const element = jsDomDocument.createElement('span');
innerShadowRoot.appendChild(element);
const containingDocument = getContainingDocument(element);
expect(containingDocument).to.not.null;
});
it('should return null when the element is not attached to any document', () => {
const detachedElement = jsDomDocument.createElement('div');
detachedElement.remove();
const containingDocument = getContainingDocument(detachedElement);
expect(containingDocument).to.be.null;
});
});
}); });
\ No newline at end of file
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
</head> </head>
<body> <body>
<div id="headline" style="display: flex;align-items: center;justify-content: center;flex-direction: column;"> <div id="headline" style="display: flex;align-items: center;justify-content: center;flex-direction: column;">
<h1 style='margin-bottom: 0.1em;'>Monster 3.33.0</h1> <h1 style='margin-bottom: 0.1em;'>Monster 3.35.4</h1>
<div id="lastupdate" style='font-size:0.7em'>last update Mo 27. Mär 18:10:51 CEST 2023</div> <div id="lastupdate" style='font-size:0.7em'>last update Sa 1. Apr 17:29:43 CEST 2023</div>
</div> </div>
<div id="mocks"></div> <div id="mocks"></div>
<div id="mocha"></div> <div id="mocha"></div>
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment