@schukai/monster 3.29.0 → 3.30.0

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schukai/monster",
3
- "version": "3.29.0",
3
+ "version": "3.30.0",
4
4
  "description": "Monster is a simple library for creating fast, robust and lightweight websites.",
5
5
  "keywords": [
6
6
  "framework",
@@ -8,7 +8,7 @@
8
8
  import { getGlobal } from "../types/global.mjs";
9
9
  import { validateString } from "../types/validate.mjs";
10
10
 
11
- export { getDocument, getWindow, getDocumentFragmentFromString };
11
+ export { getDocument, getWindow, getDocumentFragmentFromString, findElementWithIdUpwards };
12
12
 
13
13
  /**
14
14
  * This method fetches the document object
@@ -151,3 +151,52 @@ function getDocumentFragmentFromString(html) {
151
151
 
152
152
  return template.content;
153
153
  }
154
+
155
+
156
+ /**
157
+ * Recursively searches upwards from a given element to find an ancestor element
158
+ * with a specified ID, considering both normal DOM and shadow DOM.
159
+ *
160
+ * @param {HTMLElement|ShadowRoot} element - The starting element or shadow root to search from.
161
+ * @param {string} targetId - The ID of the target element to find.
162
+ * @returns {HTMLElement|null} - The ancestor element with the specified ID, or null if not found.
163
+ * @memberOf Monster.DOM
164
+ * @since 3.29.0
165
+ * @license AGPLv3
166
+ * @copyright schukai GmbH
167
+ */
168
+ function findElementWithIdUpwards(element, targetId) {
169
+ if (!element) {
170
+ return null;
171
+ }
172
+
173
+ // Check if the current element has the target ID
174
+ if (element.id === targetId) {
175
+ return element;
176
+ }
177
+
178
+ // Search within the current element's shadow root, if it exists
179
+ if (element.shadowRoot) {
180
+ const target = element.shadowRoot.getElementById(targetId);
181
+ if (target) {
182
+ return target;
183
+ }
184
+ }
185
+
186
+ // If the current element is the document.documentElement, search within the main document
187
+ if (element === document.documentElement) {
188
+ const target = document.getElementById(targetId);
189
+ if (target) {
190
+ return target;
191
+ }
192
+ }
193
+
194
+ // If the current element is inside a shadow root, search its host's ancestors
195
+ const rootNode = element.getRootNode();
196
+ if (rootNode && rootNode instanceof ShadowRoot) {
197
+ return findElementWithIdUpwards(rootNode.host, targetId);
198
+ }
199
+
200
+ // Otherwise, search the current element's parent
201
+ return findElementWithIdUpwards(element.parentElement, targetId);
202
+ }
@@ -142,7 +142,7 @@ function getMonsterVersion() {
142
142
  }
143
143
 
144
144
  /** don't touch, replaced by make with package.json version */
145
- monsterVersion = new Version("3.29.0");
145
+ monsterVersion = new Version("3.30.0");
146
146
 
147
147
  return monsterVersion;
148
148
  }
@@ -0,0 +1,85 @@
1
+ import {
2
+ findElementWithIdUpwards
3
+ } from "../../../../application/source/dom/util.mjs";
4
+
5
+ import { expect } from 'chai';
6
+ import { JSDOM } from 'jsdom';
7
+
8
+ let originalEnvironment;
9
+
10
+ function setupTestEnvironment() {
11
+ const { window } = new JSDOM('<!DOCTYPE html>', { pretendToBeVisual: true });
12
+
13
+ const { document, customElements, HTMLElement } = window;
14
+ originalEnvironment = {
15
+ document: globalThis.document,
16
+ customElements: globalThis.customElements,
17
+ HTMLElement: globalThis.HTMLElement,
18
+ ShadowRoot: globalThis.ShadowRoot,
19
+ };
20
+ globalThis.document = document;
21
+ globalThis.customElements = customElements;
22
+ globalThis.HTMLElement = HTMLElement;
23
+ globalThis.ShadowRoot = window.ShadowRoot || class ShadowRoot {}; // Fallback for JSDOM
24
+
25
+ class TestComponent extends HTMLElement {
26
+ constructor() {
27
+ super();
28
+ this.attachShadow({ mode: 'open' });
29
+ }
30
+ }
31
+
32
+ if (!customElements.get('test-component')) {
33
+ customElements.define('test-component', TestComponent);
34
+ }
35
+ }
36
+
37
+ function cleanupTestEnvironment() {
38
+ Object.assign(globalThis, originalEnvironment);
39
+ }
40
+
41
+ describe('findElementWithIdUpwards', () => {
42
+ before(() => {
43
+ setupTestEnvironment();
44
+ });
45
+
46
+ after(() => {
47
+ cleanupTestEnvironment();
48
+ });
49
+
50
+ beforeEach(() => {
51
+ // Set up the DOM
52
+ document.body.innerHTML = `
53
+ <div id="container">
54
+ <div id="parent">
55
+ <div id="child"></div>
56
+ </div>
57
+ </div>
58
+ `;
59
+
60
+ const shadowHost = document.createElement('div');
61
+ document.body.appendChild(shadowHost);
62
+ const shadowRoot = shadowHost.attachShadow({ mode: 'open' });
63
+ const innerElement = document.createElement('div');
64
+ innerElement.id = 'inner';
65
+ shadowRoot.appendChild(innerElement);
66
+ });
67
+
68
+ it('should find the element with the target ID in the normal DOM', () => {
69
+ const child = document.getElementById('child');
70
+ const result = findElementWithIdUpwards(child, 'parent');
71
+ expect(result).to.equal(document.getElementById('parent'));
72
+ });
73
+
74
+ it('should find the element with the target ID in the shadow DOM', () => {
75
+ const innerElement = document.querySelector('div[shadowroot] > div');
76
+ const result = findElementWithIdUpwards(innerElement, 'inner');
77
+ expect(result).to.equal(innerElement);
78
+ });
79
+
80
+ it('should return null if the element with the target ID is not found', () => {
81
+ const child = document.getElementById('child');
82
+ const result = findElementWithIdUpwards(child, 'nonexistent');
83
+ expect(result).to.be.null;
84
+ });
85
+ });
@@ -1,5 +1,3 @@
1
- 'use strict';
2
-
3
1
  import {
4
2
  getDocument, getWindow, getDocumentFragmentFromString
5
3
  } from "../../../../application/source/dom/util.mjs";
@@ -7,7 +7,7 @@ describe('Monster', function () {
7
7
  let monsterVersion
8
8
 
9
9
  /** don´t touch, replaced by make with package.json version */
10
- monsterVersion = new Version("3.29.0")
10
+ monsterVersion = new Version("3.30.0")
11
11
 
12
12
  let m = getMonsterVersion();
13
13