@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
@@ -33,6 +33,10 @@ class HTMLElementBase extends import_ElementBase.ElementBase {
33
33
  this._contentEditable = "inherit";
34
34
  this._innerText = "";
35
35
  this._outerText = "";
36
+ // New implementations for style, dataset, nonce
37
+ this._style = null;
38
+ this._dataset = null;
39
+ this._attributeStyleMap = null;
36
40
  }
37
41
  // HTMLElement interface implementation
38
42
  get title() {
@@ -115,8 +119,6 @@ class HTMLElementBase extends import_ElementBase.ElementBase {
115
119
  console.log(`Clicked on ${this.tagName} element`);
116
120
  }
117
121
  focus(options) {
118
- this.setAttribute("data-focused", "true");
119
- console.log(`Focused on ${this.tagName} element`);
120
122
  }
121
123
  blur() {
122
124
  this.removeAttribute("data-focused");
@@ -178,5 +180,155 @@ class HTMLElementBase extends import_ElementBase.ElementBase {
178
180
  break;
179
181
  }
180
182
  }
183
+ get style() {
184
+ if (!this._style) {
185
+ this._style = new Proxy(new CSSStyleDeclarationImpl(this), {
186
+ get: (target, prop) => {
187
+ if (typeof prop === "string" && !(prop in target)) {
188
+ const cssProp = prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
189
+ return target.getPropertyValue(cssProp);
190
+ }
191
+ return target[prop];
192
+ },
193
+ set: (target, prop, value) => {
194
+ if (typeof prop === "string" && !(prop in target)) {
195
+ const cssProp = prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
196
+ target.setProperty(cssProp, String(value));
197
+ return true;
198
+ }
199
+ target[prop] = value;
200
+ return true;
201
+ }
202
+ });
203
+ }
204
+ return this._style;
205
+ }
206
+ set style(value) {
207
+ if (typeof value === "string") {
208
+ this.style.cssText = value;
209
+ }
210
+ }
211
+ get attributeStyleMap() {
212
+ if (!this._attributeStyleMap) {
213
+ this._attributeStyleMap = new StylePropertyMapImpl(this);
214
+ }
215
+ return this._attributeStyleMap;
216
+ }
217
+ get dataset() {
218
+ if (!this._dataset) {
219
+ this._dataset = new Proxy({}, {
220
+ get: (target, prop) => {
221
+ if (typeof prop === "string") {
222
+ const attrName = "data-" + prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
223
+ return this.getAttribute(attrName);
224
+ }
225
+ return void 0;
226
+ },
227
+ set: (target, prop, value) => {
228
+ if (typeof prop === "string") {
229
+ const attrName = "data-" + prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
230
+ this.setAttribute(attrName, String(value));
231
+ return true;
232
+ }
233
+ return false;
234
+ },
235
+ deleteProperty: (target, prop) => {
236
+ if (typeof prop === "string") {
237
+ const attrName = "data-" + prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
238
+ this.removeAttribute(attrName);
239
+ return true;
240
+ }
241
+ return false;
242
+ }
243
+ });
244
+ }
245
+ return this._dataset;
246
+ }
247
+ get nonce() {
248
+ return this.getAttribute("nonce") || "";
249
+ }
250
+ set nonce(value) {
251
+ this.setAttribute("nonce", value);
252
+ }
253
+ }
254
+ class CSSStyleDeclarationImpl {
255
+ constructor(element) {
256
+ this.element = element;
257
+ this.parentRule = null;
258
+ }
259
+ getPropertyPriority(property) {
260
+ return "";
261
+ }
262
+ get cssText() {
263
+ return this.element.getAttribute("style") || "";
264
+ }
265
+ set cssText(value) {
266
+ this.element.setAttribute("style", value);
267
+ }
268
+ get length() {
269
+ return this.parseStyle(this.cssText).size;
270
+ }
271
+ getPropertyValue(property) {
272
+ const style = this.parseStyle(this.cssText);
273
+ return style.get(property) || "";
274
+ }
275
+ setProperty(property, value, priority = "") {
276
+ const style = this.parseStyle(this.cssText);
277
+ if (value === null || value === "") {
278
+ style.delete(property);
279
+ } else {
280
+ style.set(property, value);
281
+ }
282
+ this.cssText = this.serializeStyle(style);
283
+ }
284
+ removeProperty(property) {
285
+ const style = this.parseStyle(this.cssText);
286
+ const value = style.get(property) || "";
287
+ style.delete(property);
288
+ this.cssText = this.serializeStyle(style);
289
+ return value;
290
+ }
291
+ item(index) {
292
+ const style = this.parseStyle(this.cssText);
293
+ return Array.from(style.keys())[index] || "";
294
+ }
295
+ parseStyle(cssText) {
296
+ const style = /* @__PURE__ */ new Map();
297
+ if (!cssText) return style;
298
+ cssText.split(";").forEach((declaration) => {
299
+ const part = declaration.trim();
300
+ if (!part) return;
301
+ const colonIndex = part.indexOf(":");
302
+ if (colonIndex !== -1) {
303
+ const property = part.substring(0, colonIndex).trim();
304
+ const value = part.substring(colonIndex + 1).trim();
305
+ if (property && value) {
306
+ style.set(property, value);
307
+ }
308
+ }
309
+ });
310
+ return style;
311
+ }
312
+ serializeStyle(style) {
313
+ return Array.from(style.entries()).map(([property, value]) => `${property}: ${value}`).join("; ");
314
+ }
315
+ }
316
+ class StylePropertyMapImpl {
317
+ constructor(element) {
318
+ this.element = element;
319
+ }
320
+ set(property, ...values) {
321
+ const value = values[0];
322
+ this.element.style.setProperty(property, String(value));
323
+ }
324
+ append(property, ...values) {
325
+ this.set(property, ...values);
326
+ }
327
+ delete(property) {
328
+ this.element.style.removeProperty(property);
329
+ }
330
+ clear() {
331
+ this.element.style.cssText = "";
332
+ }
181
333
  }
182
334
  //# sourceMappingURL=HTMLElementBase.js.map
@@ -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
  }
@@ -298,10 +298,14 @@ class NavigatorBase {
298
298
  }
299
299
  }
300
300
  class WindowBase {
301
- constructor(document, initialUrl) {
301
+ constructor(config) {
302
302
  // Event system
303
303
  this._eventListeners = [];
304
- this.closed = false;
304
+ // Timers and intervals tracking
305
+ this._timers = /* @__PURE__ */ new Set();
306
+ this._intervals = /* @__PURE__ */ new Set();
307
+ this._animationFrames = /* @__PURE__ */ new Set();
308
+ this._closed = false;
305
309
  this.cookieStore = {};
306
310
  this.customElements = {};
307
311
  this.devicePixelRatio = 1;
@@ -526,11 +530,13 @@ class WindowBase {
526
530
  this.performance = {};
527
531
  // WindowSessionStorage
528
532
  this.sessionStorage = {};
529
- this.document = document || new import_DocumentBase.DocumentBase();
533
+ const documentBase = new import_DocumentBase.DocumentBase();
530
534
  if (this.document && this.document.setWindow) {
531
535
  this.document.setWindow(this);
532
536
  }
533
- this._location = new LocationBase(initialUrl);
537
+ this._location = new LocationBase(config?.initialUrl);
538
+ documentBase.setLocation(this._location);
539
+ this.document = documentBase;
534
540
  this.history = new HistoryBase(this);
535
541
  this.navigator = new NavigatorBase();
536
542
  this.clientInformation = this.navigator;
@@ -573,6 +579,9 @@ class WindowBase {
573
579
  }
574
580
  });
575
581
  }
582
+ get closed() {
583
+ return this._closed;
584
+ }
576
585
  get location() {
577
586
  return this._location;
578
587
  }
@@ -593,6 +602,103 @@ class WindowBase {
593
602
  captureEvents() {
594
603
  }
595
604
  close() {
605
+ if (this._closed) return;
606
+ this._closed = true;
607
+ this._timers.forEach((id) => clearTimeout(id));
608
+ this._timers.clear();
609
+ this._intervals.forEach((id) => clearInterval(id));
610
+ this._intervals.clear();
611
+ this._animationFrames.forEach((id) => clearTimeout(id));
612
+ this._animationFrames.clear();
613
+ this._eventListeners.forEach((listener) => {
614
+ listener.listener = null;
615
+ });
616
+ this._eventListeners.length = 0;
617
+ this.onload = null;
618
+ this.onunload = null;
619
+ this.onbeforeunload = null;
620
+ this.onpopstate = null;
621
+ this.onerror = null;
622
+ this.onmessage = null;
623
+ this.onhashchange = null;
624
+ if (this.document) {
625
+ const doc = this.document;
626
+ if (doc.body) {
627
+ this.clearNodeRecursively(doc.body);
628
+ }
629
+ if (doc.head) {
630
+ this.clearNodeRecursively(doc.head);
631
+ }
632
+ if (doc.documentElement) {
633
+ this.clearNodeRecursively(doc.documentElement);
634
+ }
635
+ if (doc.setWindow) {
636
+ doc.setWindow(null);
637
+ }
638
+ if (doc._eventListeners) {
639
+ doc._eventListeners.forEach((listener) => {
640
+ listener.listener = null;
641
+ });
642
+ doc._eventListeners.length = 0;
643
+ }
644
+ }
645
+ if (this.history) {
646
+ const hist = this.history;
647
+ if (hist.historyStack) {
648
+ hist.historyStack.forEach((entry) => {
649
+ entry.state = null;
650
+ });
651
+ hist.historyStack.length = 0;
652
+ }
653
+ hist.state = null;
654
+ hist.window = null;
655
+ }
656
+ if (this._location) {
657
+ this._location.urlChangeCallback = null;
658
+ }
659
+ }
660
+ /**
661
+ * Recursively clear a node and its children to prevent memory leaks
662
+ */
663
+ clearNodeRecursively(node) {
664
+ if (!node) return;
665
+ while (node.firstChild) {
666
+ const child = node.firstChild;
667
+ node.removeChild(child);
668
+ this.clearNodeRecursively(child);
669
+ }
670
+ if (node._eventListeners) {
671
+ node._eventListeners.forEach((listener) => {
672
+ listener.listener = null;
673
+ });
674
+ node._eventListeners.length = 0;
675
+ }
676
+ try {
677
+ if (node.parentNode) {
678
+ node.parentNode = null;
679
+ }
680
+ } catch (e) {
681
+ }
682
+ try {
683
+ if (node.ownerDocument) {
684
+ node.ownerDocument = null;
685
+ }
686
+ } catch (e) {
687
+ }
688
+ if (node._childNodes) {
689
+ if (Array.isArray(node._childNodes)) {
690
+ node._childNodes = [];
691
+ } else if (node._childNodes instanceof Map) {
692
+ node._childNodes.clear();
693
+ }
694
+ }
695
+ if (node._attributes) {
696
+ if (Array.isArray(node._attributes)) {
697
+ node._attributes = [];
698
+ } else if (node._attributes instanceof Map) {
699
+ node._attributes.clear();
700
+ }
701
+ }
596
702
  }
597
703
  confirm(message) {
598
704
  return false;
@@ -641,23 +747,38 @@ class WindowBase {
641
747
  }
642
748
  // Timer methods
643
749
  setTimeout(callback, delay, ...args) {
644
- return setTimeout(callback, delay, ...args);
750
+ if (this._closed) return 0;
751
+ const id = setTimeout(() => {
752
+ this._timers.delete(id);
753
+ callback(...args);
754
+ }, delay);
755
+ this._timers.add(id);
756
+ return id;
645
757
  }
646
758
  clearTimeout(id) {
647
759
  clearTimeout(id);
760
+ this._timers.delete(id);
648
761
  }
649
762
  setInterval(callback, delay, ...args) {
650
- return setInterval(callback, delay, ...args);
763
+ if (this._closed) return 0;
764
+ const id = setInterval(callback, delay, ...args);
765
+ this._intervals.add(id);
766
+ return id;
651
767
  }
652
768
  clearInterval(id) {
653
769
  clearInterval(id);
770
+ this._intervals.delete(id);
654
771
  }
655
772
  // Animation methods
656
773
  requestAnimationFrame(callback) {
657
- return this.setTimeout(callback, 16);
774
+ if (this._closed) return 0;
775
+ const id = this.setTimeout(callback, 16);
776
+ this._animationFrames.add(id);
777
+ return id;
658
778
  }
659
779
  cancelAnimationFrame(id) {
660
780
  this.clearTimeout(id);
781
+ this._animationFrames.delete(id);
661
782
  }
662
783
  addEventListener(type, listener, options) {
663
784
  if (type === "popstate" || type === "load" || type === "unload" || type === "beforeunload") {