@dooboostore/dom-parser 1.0.0 → 1.0.2

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.
Files changed (49) hide show
  1. package/README.MD +47 -94
  2. package/dist/cjs/DomParser.js +33 -12
  3. package/dist/cjs/DomParser.js.map +2 -2
  4. package/dist/cjs/node/DocumentBase.js +4 -0
  5. package/dist/cjs/node/DocumentBase.js.map +2 -2
  6. package/dist/cjs/node/elements/Element.js.map +1 -1
  7. package/dist/cjs/node/elements/ElementBase.js +12 -2
  8. package/dist/cjs/node/elements/ElementBase.js.map +2 -2
  9. package/dist/cjs/node/elements/HTMLElement.js.map +1 -1
  10. package/dist/cjs/node/elements/HTMLElementBase.js +154 -2
  11. package/dist/cjs/node/elements/HTMLElementBase.js.map +2 -2
  12. package/dist/cjs/window/WindowBase.js +128 -7
  13. package/dist/cjs/window/WindowBase.js.map +2 -2
  14. package/dist/esm/DomParser.js +33 -12
  15. package/dist/esm/DomParser.js.map +2 -2
  16. package/dist/esm/node/DocumentBase.js +4 -0
  17. package/dist/esm/node/DocumentBase.js.map +2 -2
  18. package/dist/esm/node/elements/ElementBase.js +12 -2
  19. package/dist/esm/node/elements/ElementBase.js.map +2 -2
  20. package/dist/esm/node/elements/HTMLElementBase.js +154 -2
  21. package/dist/esm/node/elements/HTMLElementBase.js.map +2 -2
  22. package/dist/esm/window/WindowBase.js +128 -7
  23. package/dist/esm/window/WindowBase.js.map +2 -2
  24. package/dist/esm-bundle/dooboostore-dom-parser.esm.js +504 -195
  25. package/dist/esm-bundle/dooboostore-dom-parser.esm.js.map +3 -3
  26. package/dist/types/DomParser.d.ts +4 -0
  27. package/dist/types/DomParser.d.ts.map +1 -1
  28. package/dist/types/node/DocumentBase.d.ts +2 -0
  29. package/dist/types/node/DocumentBase.d.ts.map +1 -1
  30. package/dist/types/node/elements/Element.d.ts +1 -0
  31. package/dist/types/node/elements/Element.d.ts.map +1 -1
  32. package/dist/types/node/elements/ElementBase.d.ts +2 -2
  33. package/dist/types/node/elements/ElementBase.d.ts.map +1 -1
  34. package/dist/types/node/elements/HTMLElement.d.ts +32 -1
  35. package/dist/types/node/elements/HTMLElement.d.ts.map +1 -1
  36. package/dist/types/node/elements/HTMLElementBase.d.ts +11 -2
  37. package/dist/types/node/elements/HTMLElementBase.d.ts.map +1 -1
  38. package/dist/types/window/WindowBase.d.ts +12 -2
  39. package/dist/types/window/WindowBase.d.ts.map +1 -1
  40. package/dist/umd-bundle/dooboostore-dom-parser.umd.js +504 -195
  41. package/dist/umd-bundle/dooboostore-dom-parser.umd.js.map +3 -3
  42. package/package.json +3 -10
  43. package/src/DomParser.ts +457 -436
  44. package/src/node/DocumentBase.ts +7 -2
  45. package/src/node/elements/Element.ts +24 -23
  46. package/src/node/elements/ElementBase.ts +50 -41
  47. package/src/node/elements/HTMLElement.ts +36 -1
  48. package/src/node/elements/HTMLElementBase.ts +191 -5
  49. package/src/window/WindowBase.ts +1128 -919
@@ -11,6 +11,10 @@ class HTMLElementBase extends ElementBase {
11
11
  this._contentEditable = "inherit";
12
12
  this._innerText = "";
13
13
  this._outerText = "";
14
+ // New implementations for style, dataset, nonce
15
+ this._style = null;
16
+ this._dataset = null;
17
+ this._attributeStyleMap = null;
14
18
  }
15
19
  // HTMLElement interface implementation
16
20
  get title() {
@@ -93,8 +97,6 @@ class HTMLElementBase extends ElementBase {
93
97
  console.log(`Clicked on ${this.tagName} element`);
94
98
  }
95
99
  focus(options) {
96
- this.setAttribute("data-focused", "true");
97
- console.log(`Focused on ${this.tagName} element`);
98
100
  }
99
101
  blur() {
100
102
  this.removeAttribute("data-focused");
@@ -156,6 +158,156 @@ class HTMLElementBase extends ElementBase {
156
158
  break;
157
159
  }
158
160
  }
161
+ get style() {
162
+ if (!this._style) {
163
+ this._style = new Proxy(new CSSStyleDeclarationImpl(this), {
164
+ get: (target, prop) => {
165
+ if (typeof prop === "string" && !(prop in target)) {
166
+ const cssProp = prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
167
+ return target.getPropertyValue(cssProp);
168
+ }
169
+ return target[prop];
170
+ },
171
+ set: (target, prop, value) => {
172
+ if (typeof prop === "string" && !(prop in target)) {
173
+ const cssProp = prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
174
+ target.setProperty(cssProp, String(value));
175
+ return true;
176
+ }
177
+ target[prop] = value;
178
+ return true;
179
+ }
180
+ });
181
+ }
182
+ return this._style;
183
+ }
184
+ set style(value) {
185
+ if (typeof value === "string") {
186
+ this.style.cssText = value;
187
+ }
188
+ }
189
+ get attributeStyleMap() {
190
+ if (!this._attributeStyleMap) {
191
+ this._attributeStyleMap = new StylePropertyMapImpl(this);
192
+ }
193
+ return this._attributeStyleMap;
194
+ }
195
+ get dataset() {
196
+ if (!this._dataset) {
197
+ this._dataset = new Proxy({}, {
198
+ get: (target, prop) => {
199
+ if (typeof prop === "string") {
200
+ const attrName = "data-" + prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
201
+ return this.getAttribute(attrName);
202
+ }
203
+ return void 0;
204
+ },
205
+ set: (target, prop, value) => {
206
+ if (typeof prop === "string") {
207
+ const attrName = "data-" + prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
208
+ this.setAttribute(attrName, String(value));
209
+ return true;
210
+ }
211
+ return false;
212
+ },
213
+ deleteProperty: (target, prop) => {
214
+ if (typeof prop === "string") {
215
+ const attrName = "data-" + prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
216
+ this.removeAttribute(attrName);
217
+ return true;
218
+ }
219
+ return false;
220
+ }
221
+ });
222
+ }
223
+ return this._dataset;
224
+ }
225
+ get nonce() {
226
+ return this.getAttribute("nonce") || "";
227
+ }
228
+ set nonce(value) {
229
+ this.setAttribute("nonce", value);
230
+ }
231
+ }
232
+ class CSSStyleDeclarationImpl {
233
+ constructor(element) {
234
+ this.element = element;
235
+ this.parentRule = null;
236
+ }
237
+ getPropertyPriority(property) {
238
+ return "";
239
+ }
240
+ get cssText() {
241
+ return this.element.getAttribute("style") || "";
242
+ }
243
+ set cssText(value) {
244
+ this.element.setAttribute("style", value);
245
+ }
246
+ get length() {
247
+ return this.parseStyle(this.cssText).size;
248
+ }
249
+ getPropertyValue(property) {
250
+ const style = this.parseStyle(this.cssText);
251
+ return style.get(property) || "";
252
+ }
253
+ setProperty(property, value, priority = "") {
254
+ const style = this.parseStyle(this.cssText);
255
+ if (value === null || value === "") {
256
+ style.delete(property);
257
+ } else {
258
+ style.set(property, value);
259
+ }
260
+ this.cssText = this.serializeStyle(style);
261
+ }
262
+ removeProperty(property) {
263
+ const style = this.parseStyle(this.cssText);
264
+ const value = style.get(property) || "";
265
+ style.delete(property);
266
+ this.cssText = this.serializeStyle(style);
267
+ return value;
268
+ }
269
+ item(index) {
270
+ const style = this.parseStyle(this.cssText);
271
+ return Array.from(style.keys())[index] || "";
272
+ }
273
+ parseStyle(cssText) {
274
+ const style = /* @__PURE__ */ new Map();
275
+ if (!cssText) return style;
276
+ cssText.split(";").forEach((declaration) => {
277
+ const part = declaration.trim();
278
+ if (!part) return;
279
+ const colonIndex = part.indexOf(":");
280
+ if (colonIndex !== -1) {
281
+ const property = part.substring(0, colonIndex).trim();
282
+ const value = part.substring(colonIndex + 1).trim();
283
+ if (property && value) {
284
+ style.set(property, value);
285
+ }
286
+ }
287
+ });
288
+ return style;
289
+ }
290
+ serializeStyle(style) {
291
+ return Array.from(style.entries()).map(([property, value]) => `${property}: ${value}`).join("; ");
292
+ }
293
+ }
294
+ class StylePropertyMapImpl {
295
+ constructor(element) {
296
+ this.element = element;
297
+ }
298
+ set(property, ...values) {
299
+ const value = values[0];
300
+ this.element.style.setProperty(property, String(value));
301
+ }
302
+ append(property, ...values) {
303
+ this.set(property, ...values);
304
+ }
305
+ delete(property) {
306
+ this.element.style.removeProperty(property);
307
+ }
308
+ clear() {
309
+ this.element.style.cssText = "";
310
+ }
159
311
  }
160
312
  export {
161
313
  HTMLElementBase
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/node/elements/HTMLElementBase.ts"],
4
- "sourcesContent": ["import { ElementBase } from './ElementBase';\nimport { HTMLElement, FocusOptions } from './HTMLElement';\nimport { Text } from '../Text';\nimport { ElementFactory } from '../../factory';\n\n/**\n * Base implementation for all HTML elements\n */\nexport abstract class HTMLElementBase extends ElementBase implements HTMLElement {\n private _title: string = '';\n private _lang: string = '';\n private _dir: string = '';\n private _hidden: boolean = false;\n private _tabIndex: number = -1;\n private _accessKey: string = '';\n private _contentEditable: string = 'inherit';\n private _innerText: string = '';\n private _outerText: string = '';\n\n constructor(tagName: string, ownerDocument?: any) {\n super(tagName, ownerDocument);\n }\n\n // HTMLElement interface implementation\n get title(): string {\n return this._title;\n }\n\n set title(value: string) {\n this._title = value;\n this.setAttribute('title', value);\n }\n\n get lang(): string {\n return this._lang;\n }\n\n set lang(value: string) {\n this._lang = value;\n this.setAttribute('lang', value);\n }\n\n get dir(): string {\n return this._dir;\n }\n\n set dir(value: string) {\n this._dir = value;\n this.setAttribute('dir', value);\n }\n\n get hidden(): boolean {\n return this._hidden;\n }\n\n set hidden(value: boolean) {\n this._hidden = value;\n if (value) {\n this.setAttribute('hidden', '');\n } else {\n this.removeAttribute('hidden');\n }\n }\n\n get tabIndex(): number {\n return this._tabIndex;\n }\n\n set tabIndex(value: number) {\n this._tabIndex = value;\n this.setAttribute('tabindex', value.toString());\n }\n\n get accessKey(): string {\n return this._accessKey;\n }\n\n set accessKey(value: string) {\n this._accessKey = value;\n this.setAttribute('accesskey', value);\n }\n\n get contentEditable(): string {\n return this._contentEditable;\n }\n\n set contentEditable(value: string) {\n this._contentEditable = value;\n this.setAttribute('contenteditable', value);\n }\n\n get isContentEditable(): boolean {\n return this._contentEditable === 'true';\n }\n\n get innerText(): string {\n return this._innerText || this.textContent || '';\n }\n\n set innerText(value: string) {\n this._innerText = value;\n this.textContent = value;\n }\n\n get outerText(): string {\n return this._outerText || this.innerText;\n }\n\n set outerText(value: string) {\n this._outerText = value;\n if (this.parentNode) {\n const { TextBase } = require('../TextBase');\n const textNode = new TextBase(value, this._ownerDocument);\n this.parentNode.replaceChild(textNode, this);\n }\n }\n\n // innerHTML functionality is inherited from ElementBase\n\n // HTMLElement methods\n click(): void {\n // Simulate click event - in a real implementation, this would dispatch events\n console.log(`Clicked on ${this.tagName} element`);\n }\n\n focus(options?: FocusOptions): void {\n // Set focus state using data attribute\n this.setAttribute('data-focused', 'true');\n console.log(`Focused on ${this.tagName} element`);\n }\n\n blur(): void {\n // Remove focus state\n this.removeAttribute('data-focused');\n console.log(`Blurred ${this.tagName} element`);\n }\n\n // Override setAttribute to sync with properties\n setAttribute(qualifiedName: string, value: string): void {\n super.setAttribute(qualifiedName, value);\n\n // Sync with properties\n const name = qualifiedName.toLowerCase();\n switch (name) {\n case 'title':\n this._title = value;\n break;\n case 'lang':\n this._lang = value;\n break;\n case 'dir':\n this._dir = value;\n break;\n case 'hidden':\n this._hidden = true;\n break;\n case 'tabindex':\n this._tabIndex = parseInt(value, 10) || -1;\n break;\n case 'accesskey':\n this._accessKey = value;\n break;\n case 'contenteditable':\n this._contentEditable = value;\n break;\n }\n }\n\n // Override removeAttribute to sync with properties\n removeAttribute(qualifiedName: string): void {\n super.removeAttribute(qualifiedName);\n\n const name = qualifiedName.toLowerCase();\n switch (name) {\n case 'title':\n this._title = '';\n break;\n case 'lang':\n this._lang = '';\n break;\n case 'dir':\n this._dir = '';\n break;\n case 'hidden':\n this._hidden = false;\n break;\n case 'tabindex':\n this._tabIndex = -1;\n break;\n case 'accesskey':\n this._accessKey = '';\n break;\n case 'contenteditable':\n this._contentEditable = 'inherit';\n break;\n }\n }\n}"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { ElementBase } from './ElementBase';\nimport { HTMLElement, FocusOptions, CSSStyleDeclaration, DOMStringMap, ElementCSSInlineStyle, StylePropertyMap } from './HTMLElement';\nimport { Text } from '../Text';\nimport { ElementFactory } from '../../factory';\n\n/**\n * Base implementation for all HTML elements\n */\nexport abstract class HTMLElementBase extends ElementBase implements HTMLElement, ElementCSSInlineStyle {\n private _title: string = '';\n private _lang: string = '';\n private _dir: string = '';\n private _hidden: boolean = false;\n private _tabIndex: number = -1;\n private _accessKey: string = '';\n private _contentEditable: string = 'inherit';\n private _innerText: string = '';\n private _outerText: string = '';\n\n constructor(tagName: string, ownerDocument?: any) {\n super(tagName, ownerDocument);\n }\n\n // HTMLElement interface implementation\n get title(): string {\n return this._title;\n }\n\n set title(value: string) {\n this._title = value;\n this.setAttribute('title', value);\n }\n\n get lang(): string {\n return this._lang;\n }\n\n set lang(value: string) {\n this._lang = value;\n this.setAttribute('lang', value);\n }\n\n get dir(): string {\n return this._dir;\n }\n\n set dir(value: string) {\n this._dir = value;\n this.setAttribute('dir', value);\n }\n\n get hidden(): boolean {\n return this._hidden;\n }\n\n set hidden(value: boolean) {\n this._hidden = value;\n if (value) {\n this.setAttribute('hidden', '');\n } else {\n this.removeAttribute('hidden');\n }\n }\n\n get tabIndex(): number {\n return this._tabIndex;\n }\n\n set tabIndex(value: number) {\n this._tabIndex = value;\n this.setAttribute('tabindex', value.toString());\n }\n\n get accessKey(): string {\n return this._accessKey;\n }\n\n set accessKey(value: string) {\n this._accessKey = value;\n this.setAttribute('accesskey', value);\n }\n\n get contentEditable(): string {\n return this._contentEditable;\n }\n\n set contentEditable(value: string) {\n this._contentEditable = value;\n this.setAttribute('contenteditable', value);\n }\n\n get isContentEditable(): boolean {\n return this._contentEditable === 'true';\n }\n\n get innerText(): string {\n return this._innerText || this.textContent || '';\n }\n\n set innerText(value: string) {\n this._innerText = value;\n this.textContent = value;\n }\n\n get outerText(): string {\n return this._outerText || this.innerText;\n }\n\n set outerText(value: string) {\n this._outerText = value;\n if (this.parentNode) {\n const { TextBase } = require('../TextBase');\n const textNode = new TextBase(value, this._ownerDocument);\n this.parentNode.replaceChild(textNode, this);\n }\n }\n\n // innerHTML functionality is inherited from ElementBase\n\n // HTMLElement methods\n click(): void {\n // Simulate click event - in a real implementation, this would dispatch events\n console.log(`Clicked on ${this.tagName} element`);\n }\n\n focus(options?: FocusOptions): void {\n }\n\n blur(): void {\n // Remove focus state\n this.removeAttribute('data-focused');\n console.log(`Blurred ${this.tagName} element`);\n }\n\n // Override setAttribute to sync with properties\n setAttribute(qualifiedName: string, value: string): void {\n super.setAttribute(qualifiedName, value);\n\n // Sync with properties\n const name = qualifiedName.toLowerCase();\n switch (name) {\n case 'title':\n this._title = value;\n break;\n case 'lang':\n this._lang = value;\n break;\n case 'dir':\n this._dir = value;\n break;\n case 'hidden':\n this._hidden = true;\n break;\n case 'tabindex':\n this._tabIndex = parseInt(value, 10) || -1;\n break;\n case 'accesskey':\n this._accessKey = value;\n break;\n case 'contenteditable':\n this._contentEditable = value;\n break;\n }\n }\n\n // Override removeAttribute to sync with properties\n removeAttribute(qualifiedName: string): void {\n super.removeAttribute(qualifiedName);\n\n const name = qualifiedName.toLowerCase();\n switch (name) {\n case 'title':\n this._title = '';\n break;\n case 'lang':\n this._lang = '';\n break;\n case 'dir':\n this._dir = '';\n break;\n case 'hidden':\n this._hidden = false;\n break;\n case 'tabindex':\n this._tabIndex = -1;\n break;\n case 'accesskey':\n this._accessKey = '';\n break;\n case 'contenteditable':\n this._contentEditable = 'inherit';\n break;\n }\n }\n\n // New implementations for style, dataset, nonce\n private _style: CSSStyleDeclaration | null = null;\n private _dataset: DOMStringMap | null = null;\n\n get style(): CSSStyleDeclaration {\n if (!this._style) {\n this._style = new Proxy(new CSSStyleDeclarationImpl(this), {\n get: (target, prop: string | symbol) => {\n if (typeof prop === 'string' && !(prop in target)) {\n // Convert camelCase to kebab-case for CSS properties\n const cssProp = prop.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`);\n return target.getPropertyValue(cssProp);\n }\n return (target as any)[prop];\n },\n set: (target, prop: string | symbol, value: any) => {\n if (typeof prop === 'string' && !(prop in target)) {\n // Convert camelCase to kebab-case for CSS properties\n const cssProp = prop.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`);\n target.setProperty(cssProp, String(value));\n return true;\n }\n (target as any)[prop] = value;\n return true;\n }\n }) as unknown as CSSStyleDeclaration;\n }\n return this._style;\n }\n\n set style(value: string | CSSStyleDeclaration) {\n if (typeof value === 'string') {\n this.style.cssText = value;\n }\n }\n\n private _attributeStyleMap: StylePropertyMap | null = null;\n\n get attributeStyleMap(): StylePropertyMap {\n if (!this._attributeStyleMap) {\n this._attributeStyleMap = new StylePropertyMapImpl(this);\n }\n return this._attributeStyleMap;\n }\n\n get dataset(): DOMStringMap {\n if (!this._dataset) {\n this._dataset = new Proxy({}, {\n get: (target, prop: string | symbol) => {\n if (typeof prop === 'string') {\n // Convert camelCase to kebab-case: fooBar -> data-foo-bar\n const attrName = 'data-' + prop.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`);\n return this.getAttribute(attrName);\n }\n return undefined;\n },\n set: (target, prop: string | symbol, value: any) => {\n if (typeof prop === 'string') {\n // Convert camelCase to kebab-case: fooBar -> data-foo-bar\n const attrName = 'data-' + prop.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`);\n this.setAttribute(attrName, String(value));\n return true;\n }\n return false;\n },\n deleteProperty: (target, prop: string | symbol) => {\n if (typeof prop === 'string') {\n const attrName = 'data-' + prop.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`);\n this.removeAttribute(attrName);\n return true;\n }\n return false;\n }\n });\n }\n return this._dataset;\n }\n\n get nonce(): string {\n return this.getAttribute('nonce') || '';\n }\n\n set nonce(value: string) {\n this.setAttribute('nonce', value);\n }\n}\n\n// CSSStyleDeclaration implementation\nclass CSSStyleDeclarationImpl {\n [key: string]: any;\n\n constructor(private element: HTMLElementBase) { }\n\n parentRule: any = null;\n\n getPropertyPriority(property: string): string {\n return '';\n }\n\n get cssText(): string {\n return this.element.getAttribute('style') || '';\n }\n\n set cssText(value: string) {\n this.element.setAttribute('style', value);\n }\n\n get length(): number {\n return this.parseStyle(this.cssText).size;\n }\n\n getPropertyValue(property: string): string {\n const style = this.parseStyle(this.cssText);\n return style.get(property) || '';\n }\n\n setProperty(property: string, value: string | null, priority: string = ''): void {\n const style = this.parseStyle(this.cssText);\n if (value === null || value === '') {\n style.delete(property);\n } else {\n style.set(property, value); // TODO: handle priority\n }\n this.cssText = this.serializeStyle(style);\n }\n\n removeProperty(property: string): string {\n const style = this.parseStyle(this.cssText);\n const value = style.get(property) || '';\n style.delete(property);\n this.cssText = this.serializeStyle(style);\n return value;\n }\n\n item(index: number): string {\n const style = this.parseStyle(this.cssText);\n return Array.from(style.keys())[index] || '';\n }\n\n private parseStyle(cssText: string): Map<string, string> {\n const style = new Map<string, string>();\n if (!cssText) return style;\n\n cssText.split(';').forEach(declaration => {\n const part = declaration.trim();\n if (!part) return;\n\n const colonIndex = part.indexOf(':');\n if (colonIndex !== -1) {\n const property = part.substring(0, colonIndex).trim();\n const value = part.substring(colonIndex + 1).trim();\n if (property && value) {\n style.set(property, value);\n }\n }\n });\n return style;\n }\n\n private serializeStyle(style: Map<string, string>): string {\n return Array.from(style.entries())\n .map(([property, value]) => `${property}: ${value}`)\n .join('; ');\n }\n}\n\n// StylePropertyMap implementation\nclass StylePropertyMapImpl implements StylePropertyMap {\n [key: string]: any;\n\n constructor(private element: HTMLElementBase) { }\n\n set(property: string, ...values: (string | any)[]): void {\n const value = values[0];\n this.element.style.setProperty(property, String(value));\n }\n\n append(property: string, ...values: (string | any)[]): void {\n this.set(property, ...values);\n }\n\n delete(property: string): void {\n this.element.style.removeProperty(property);\n }\n\n clear(): void {\n this.element.style.cssText = '';\n }\n}"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -276,10 +276,14 @@ class NavigatorBase {
276
276
  }
277
277
  }
278
278
  class WindowBase {
279
- constructor(document, initialUrl) {
279
+ constructor(config) {
280
280
  // Event system
281
281
  this._eventListeners = [];
282
- this.closed = false;
282
+ // Timers and intervals tracking
283
+ this._timers = /* @__PURE__ */ new Set();
284
+ this._intervals = /* @__PURE__ */ new Set();
285
+ this._animationFrames = /* @__PURE__ */ new Set();
286
+ this._closed = false;
283
287
  this.cookieStore = {};
284
288
  this.customElements = {};
285
289
  this.devicePixelRatio = 1;
@@ -504,11 +508,13 @@ class WindowBase {
504
508
  this.performance = {};
505
509
  // WindowSessionStorage
506
510
  this.sessionStorage = {};
507
- this.document = document || new DocumentBase();
511
+ const documentBase = new DocumentBase();
508
512
  if (this.document && this.document.setWindow) {
509
513
  this.document.setWindow(this);
510
514
  }
511
- this._location = new LocationBase(initialUrl);
515
+ this._location = new LocationBase(config?.initialUrl);
516
+ documentBase.setLocation(this._location);
517
+ this.document = documentBase;
512
518
  this.history = new HistoryBase(this);
513
519
  this.navigator = new NavigatorBase();
514
520
  this.clientInformation = this.navigator;
@@ -551,6 +557,9 @@ class WindowBase {
551
557
  }
552
558
  });
553
559
  }
560
+ get closed() {
561
+ return this._closed;
562
+ }
554
563
  get location() {
555
564
  return this._location;
556
565
  }
@@ -571,6 +580,103 @@ class WindowBase {
571
580
  captureEvents() {
572
581
  }
573
582
  close() {
583
+ if (this._closed) return;
584
+ this._closed = true;
585
+ this._timers.forEach((id) => clearTimeout(id));
586
+ this._timers.clear();
587
+ this._intervals.forEach((id) => clearInterval(id));
588
+ this._intervals.clear();
589
+ this._animationFrames.forEach((id) => clearTimeout(id));
590
+ this._animationFrames.clear();
591
+ this._eventListeners.forEach((listener) => {
592
+ listener.listener = null;
593
+ });
594
+ this._eventListeners.length = 0;
595
+ this.onload = null;
596
+ this.onunload = null;
597
+ this.onbeforeunload = null;
598
+ this.onpopstate = null;
599
+ this.onerror = null;
600
+ this.onmessage = null;
601
+ this.onhashchange = null;
602
+ if (this.document) {
603
+ const doc = this.document;
604
+ if (doc.body) {
605
+ this.clearNodeRecursively(doc.body);
606
+ }
607
+ if (doc.head) {
608
+ this.clearNodeRecursively(doc.head);
609
+ }
610
+ if (doc.documentElement) {
611
+ this.clearNodeRecursively(doc.documentElement);
612
+ }
613
+ if (doc.setWindow) {
614
+ doc.setWindow(null);
615
+ }
616
+ if (doc._eventListeners) {
617
+ doc._eventListeners.forEach((listener) => {
618
+ listener.listener = null;
619
+ });
620
+ doc._eventListeners.length = 0;
621
+ }
622
+ }
623
+ if (this.history) {
624
+ const hist = this.history;
625
+ if (hist.historyStack) {
626
+ hist.historyStack.forEach((entry) => {
627
+ entry.state = null;
628
+ });
629
+ hist.historyStack.length = 0;
630
+ }
631
+ hist.state = null;
632
+ hist.window = null;
633
+ }
634
+ if (this._location) {
635
+ this._location.urlChangeCallback = null;
636
+ }
637
+ }
638
+ /**
639
+ * Recursively clear a node and its children to prevent memory leaks
640
+ */
641
+ clearNodeRecursively(node) {
642
+ if (!node) return;
643
+ while (node.firstChild) {
644
+ const child = node.firstChild;
645
+ node.removeChild(child);
646
+ this.clearNodeRecursively(child);
647
+ }
648
+ if (node._eventListeners) {
649
+ node._eventListeners.forEach((listener) => {
650
+ listener.listener = null;
651
+ });
652
+ node._eventListeners.length = 0;
653
+ }
654
+ try {
655
+ if (node.parentNode) {
656
+ node.parentNode = null;
657
+ }
658
+ } catch (e) {
659
+ }
660
+ try {
661
+ if (node.ownerDocument) {
662
+ node.ownerDocument = null;
663
+ }
664
+ } catch (e) {
665
+ }
666
+ if (node._childNodes) {
667
+ if (Array.isArray(node._childNodes)) {
668
+ node._childNodes = [];
669
+ } else if (node._childNodes instanceof Map) {
670
+ node._childNodes.clear();
671
+ }
672
+ }
673
+ if (node._attributes) {
674
+ if (Array.isArray(node._attributes)) {
675
+ node._attributes = [];
676
+ } else if (node._attributes instanceof Map) {
677
+ node._attributes.clear();
678
+ }
679
+ }
574
680
  }
575
681
  confirm(message) {
576
682
  return false;
@@ -619,23 +725,38 @@ class WindowBase {
619
725
  }
620
726
  // Timer methods
621
727
  setTimeout(callback, delay, ...args) {
622
- return setTimeout(callback, delay, ...args);
728
+ if (this._closed) return 0;
729
+ const id = setTimeout(() => {
730
+ this._timers.delete(id);
731
+ callback(...args);
732
+ }, delay);
733
+ this._timers.add(id);
734
+ return id;
623
735
  }
624
736
  clearTimeout(id) {
625
737
  clearTimeout(id);
738
+ this._timers.delete(id);
626
739
  }
627
740
  setInterval(callback, delay, ...args) {
628
- return setInterval(callback, delay, ...args);
741
+ if (this._closed) return 0;
742
+ const id = setInterval(callback, delay, ...args);
743
+ this._intervals.add(id);
744
+ return id;
629
745
  }
630
746
  clearInterval(id) {
631
747
  clearInterval(id);
748
+ this._intervals.delete(id);
632
749
  }
633
750
  // Animation methods
634
751
  requestAnimationFrame(callback) {
635
- return this.setTimeout(callback, 16);
752
+ if (this._closed) return 0;
753
+ const id = this.setTimeout(callback, 16);
754
+ this._animationFrames.add(id);
755
+ return id;
636
756
  }
637
757
  cancelAnimationFrame(id) {
638
758
  this.clearTimeout(id);
759
+ this._animationFrames.delete(id);
639
760
  }
640
761
  addEventListener(type, listener, options) {
641
762
  if (type === "popstate" || type === "load" || type === "unload" || type === "beforeunload") {