@schukai/monster 3.29.0 → 3.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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