@gjsify/dom-elements 0.1.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.
Files changed (84) hide show
  1. package/README.md +31 -0
  2. package/lib/esm/attr.js +31 -0
  3. package/lib/esm/character-data.js +56 -0
  4. package/lib/esm/comment.js +21 -0
  5. package/lib/esm/document-fragment.js +112 -0
  6. package/lib/esm/document.js +83 -0
  7. package/lib/esm/dom-token-list.js +109 -0
  8. package/lib/esm/element.js +237 -0
  9. package/lib/esm/html-canvas-element.js +65 -0
  10. package/lib/esm/html-element.js +346 -0
  11. package/lib/esm/html-image-element.js +184 -0
  12. package/lib/esm/image.js +23 -0
  13. package/lib/esm/index.js +112 -0
  14. package/lib/esm/intersection-observer.js +19 -0
  15. package/lib/esm/mutation-observer.js +14 -0
  16. package/lib/esm/named-node-map.js +124 -0
  17. package/lib/esm/namespace-uri.js +10 -0
  18. package/lib/esm/node-list.js +34 -0
  19. package/lib/esm/node-type.js +14 -0
  20. package/lib/esm/node.js +227 -0
  21. package/lib/esm/property-symbol.js +30 -0
  22. package/lib/esm/resize-observer.js +13 -0
  23. package/lib/esm/text.js +51 -0
  24. package/lib/esm/types/i-html-image-element.js +0 -0
  25. package/lib/esm/types/image-data.js +0 -0
  26. package/lib/esm/types/index.js +3 -0
  27. package/lib/esm/types/predefined-color-space.js +0 -0
  28. package/lib/types/attr.d.ts +22 -0
  29. package/lib/types/character-data.d.ts +24 -0
  30. package/lib/types/comment.d.ts +12 -0
  31. package/lib/types/document-fragment.d.ts +37 -0
  32. package/lib/types/document.d.ts +39 -0
  33. package/lib/types/dom-token-list.d.ts +30 -0
  34. package/lib/types/element.d.ts +58 -0
  35. package/lib/types/html-canvas-element.d.ts +40 -0
  36. package/lib/types/html-element.d.ts +119 -0
  37. package/lib/types/html-image-element.d.ts +65 -0
  38. package/lib/types/image.d.ts +17 -0
  39. package/lib/types/index.d.ts +21 -0
  40. package/lib/types/intersection-observer.d.ts +21 -0
  41. package/lib/types/mutation-observer.d.ts +24 -0
  42. package/lib/types/named-node-map.d.ts +31 -0
  43. package/lib/types/namespace-uri.d.ts +7 -0
  44. package/lib/types/node-list.d.ts +18 -0
  45. package/lib/types/node-type.d.ts +11 -0
  46. package/lib/types/node.d.ts +63 -0
  47. package/lib/types/property-symbol.d.ts +14 -0
  48. package/lib/types/resize-observer.d.ts +13 -0
  49. package/lib/types/text.d.ts +21 -0
  50. package/lib/types/types/i-html-image-element.d.ts +41 -0
  51. package/lib/types/types/image-data.d.ts +11 -0
  52. package/lib/types/types/index.d.ts +3 -0
  53. package/lib/types/types/predefined-color-space.d.ts +1 -0
  54. package/package.json +43 -0
  55. package/src/attr.ts +61 -0
  56. package/src/character-data.ts +79 -0
  57. package/src/comment.ts +31 -0
  58. package/src/document-fragment.ts +137 -0
  59. package/src/document.ts +93 -0
  60. package/src/dom-token-list.ts +140 -0
  61. package/src/element.ts +299 -0
  62. package/src/html-canvas-element.ts +81 -0
  63. package/src/html-element.ts +422 -0
  64. package/src/html-image-element.ts +242 -0
  65. package/src/image.ts +31 -0
  66. package/src/index.spec.ts +897 -0
  67. package/src/index.ts +95 -0
  68. package/src/intersection-observer.ts +42 -0
  69. package/src/mutation-observer.ts +39 -0
  70. package/src/named-node-map.ts +159 -0
  71. package/src/namespace-uri.ts +11 -0
  72. package/src/node-list.ts +52 -0
  73. package/src/node-type.ts +14 -0
  74. package/src/node.ts +250 -0
  75. package/src/property-symbol.ts +23 -0
  76. package/src/resize-observer.ts +28 -0
  77. package/src/test.mts +6 -0
  78. package/src/text.ts +67 -0
  79. package/src/types/i-html-image-element.ts +44 -0
  80. package/src/types/image-data.ts +12 -0
  81. package/src/types/index.ts +3 -0
  82. package/src/types/predefined-color-space.ts +1 -0
  83. package/tsconfig.json +37 -0
  84. package/tsconfig.tsbuildinfo +1 -0
package/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # @gjsify/dom-elements
2
+
3
+ GJS implementation of DOM elements including Node, Element, HTMLElement, HTMLCanvasElement, HTMLImageElement, Document, and more. Backed by GdkPixbuf.
4
+
5
+ Part of the [gjsify](https://github.com/gjsify/gjsify) project — Node.js and Web APIs for GJS (GNOME JavaScript).
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @gjsify/dom-elements
11
+ # or
12
+ yarn add @gjsify/dom-elements
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```typescript
18
+ import '@gjsify/dom-elements';
19
+
20
+ // Registers globalThis.document, globalThis.Image, globalThis.HTMLCanvasElement
21
+ const img = new Image();
22
+ img.src = 'path/to/image.png';
23
+
24
+ const canvas = document.createElement('canvas');
25
+ canvas.width = 800;
26
+ canvas.height = 600;
27
+ ```
28
+
29
+ ## License
30
+
31
+ MIT
@@ -0,0 +1,31 @@
1
+ import * as PS from "./property-symbol.js";
2
+ class Attr {
3
+ constructor(name, value, namespaceURI = null, prefix = null, ownerElement = null) {
4
+ this.specified = true;
5
+ this[PS.name] = name;
6
+ this[PS.value] = value;
7
+ this[PS.ownerElement] = ownerElement;
8
+ this.namespaceURI = namespaceURI;
9
+ this.prefix = prefix;
10
+ const colonIndex = name.indexOf(":");
11
+ this.localName = colonIndex !== -1 ? name.slice(colonIndex + 1) : name;
12
+ }
13
+ get name() {
14
+ return this[PS.name];
15
+ }
16
+ get value() {
17
+ return this[PS.value];
18
+ }
19
+ set value(value) {
20
+ this[PS.value] = value;
21
+ }
22
+ get ownerElement() {
23
+ return this[PS.ownerElement];
24
+ }
25
+ get [(PS.name, PS.value, PS.ownerElement, Symbol.toStringTag)]() {
26
+ return "Attr";
27
+ }
28
+ }
29
+ export {
30
+ Attr
31
+ };
@@ -0,0 +1,56 @@
1
+ import { Node } from "./node.js";
2
+ import { NodeType } from "./node-type.js";
3
+ import * as PS from "./property-symbol.js";
4
+ class CharacterData extends Node {
5
+ constructor(data = "") {
6
+ super();
7
+ this[PS.nodeType] = NodeType.TEXT_NODE;
8
+ this._data = data;
9
+ }
10
+ get data() {
11
+ return this._data;
12
+ }
13
+ set data(value) {
14
+ this._data = value;
15
+ }
16
+ get textContent() {
17
+ return this._data;
18
+ }
19
+ set textContent(value) {
20
+ this._data = value;
21
+ }
22
+ get nodeValue() {
23
+ return this._data;
24
+ }
25
+ set nodeValue(value) {
26
+ this._data = value;
27
+ }
28
+ get length() {
29
+ return this._data.length;
30
+ }
31
+ appendData(data) {
32
+ this._data += data;
33
+ }
34
+ deleteData(offset, count) {
35
+ this._data = this._data.substring(0, offset) + this._data.substring(offset + count);
36
+ }
37
+ insertData(offset, data) {
38
+ this._data = this._data.substring(0, offset) + data + this._data.substring(offset);
39
+ }
40
+ replaceData(offset, count, data) {
41
+ this._data = this._data.substring(0, offset) + data + this._data.substring(offset + count);
42
+ }
43
+ substringData(offset, count) {
44
+ return this._data.substring(offset, offset + count);
45
+ }
46
+ cloneNode(_deep = false) {
47
+ const clone = new this.constructor(this._data);
48
+ return clone;
49
+ }
50
+ get [Symbol.toStringTag]() {
51
+ return "CharacterData";
52
+ }
53
+ }
54
+ export {
55
+ CharacterData
56
+ };
@@ -0,0 +1,21 @@
1
+ import { CharacterData } from "./character-data.js";
2
+ import { NodeType } from "./node-type.js";
3
+ import * as PS from "./property-symbol.js";
4
+ class Comment extends CharacterData {
5
+ constructor(data = "") {
6
+ super(data);
7
+ this[PS.nodeType] = NodeType.COMMENT_NODE;
8
+ }
9
+ get nodeName() {
10
+ return "#comment";
11
+ }
12
+ cloneNode(_deep = false) {
13
+ return new Comment(this.data);
14
+ }
15
+ get [Symbol.toStringTag]() {
16
+ return "Comment";
17
+ }
18
+ }
19
+ export {
20
+ Comment
21
+ };
@@ -0,0 +1,112 @@
1
+ import { Node } from "./node.js";
2
+ import { Text } from "./text.js";
3
+ import { NodeType } from "./node-type.js";
4
+ import * as PS from "./property-symbol.js";
5
+ class DocumentFragment extends Node {
6
+ constructor() {
7
+ super();
8
+ this[PS.nodeType] = NodeType.DOCUMENT_FRAGMENT_NODE;
9
+ }
10
+ get nodeName() {
11
+ return "#document-fragment";
12
+ }
13
+ /** Element children only (excludes text/comment nodes) */
14
+ get children() {
15
+ return this[PS.elementChildren];
16
+ }
17
+ get childElementCount() {
18
+ return this[PS.elementChildren].length;
19
+ }
20
+ get firstElementChild() {
21
+ return this[PS.elementChildren][0] ?? null;
22
+ }
23
+ get lastElementChild() {
24
+ const children = this[PS.elementChildren];
25
+ return children[children.length - 1] ?? null;
26
+ }
27
+ get textContent() {
28
+ let text = "";
29
+ for (const child of this.childNodes) {
30
+ if (child.textContent !== null) {
31
+ text += child.textContent;
32
+ }
33
+ }
34
+ return text;
35
+ }
36
+ set textContent(value) {
37
+ while (this.firstChild) {
38
+ this.removeChild(this.firstChild);
39
+ }
40
+ if (value) {
41
+ this.appendChild(new Text(value));
42
+ }
43
+ }
44
+ /**
45
+ * Append nodes or strings to this fragment.
46
+ */
47
+ append(...nodes) {
48
+ for (const node of nodes) {
49
+ if (typeof node === "string") {
50
+ this.appendChild(new Text(node));
51
+ } else {
52
+ this.appendChild(node);
53
+ }
54
+ }
55
+ }
56
+ /**
57
+ * Prepend nodes or strings to this fragment.
58
+ */
59
+ prepend(...nodes) {
60
+ const firstChild = this.firstChild;
61
+ for (const node of nodes) {
62
+ if (typeof node === "string") {
63
+ this.insertBefore(new Text(node), firstChild);
64
+ } else {
65
+ this.insertBefore(node, firstChild);
66
+ }
67
+ }
68
+ }
69
+ /**
70
+ * Replace all children with the given nodes.
71
+ */
72
+ replaceChildren(...nodes) {
73
+ while (this.firstChild) {
74
+ this.removeChild(this.firstChild);
75
+ }
76
+ this.append(...nodes);
77
+ }
78
+ /**
79
+ * Find an element by ID in this fragment's children.
80
+ */
81
+ getElementById(id) {
82
+ for (const child of this.children) {
83
+ if (child.id === id) return child;
84
+ const found = this._findById(child, id);
85
+ if (found) return found;
86
+ }
87
+ return null;
88
+ }
89
+ _findById(element, id) {
90
+ for (const child of element.children) {
91
+ if (child.id === id) return child;
92
+ const found = this._findById(child, id);
93
+ if (found) return found;
94
+ }
95
+ return null;
96
+ }
97
+ cloneNode(deep = false) {
98
+ const clone = new DocumentFragment();
99
+ if (deep) {
100
+ for (const child of this.childNodes) {
101
+ clone.appendChild(child.cloneNode(true));
102
+ }
103
+ }
104
+ return clone;
105
+ }
106
+ get [Symbol.toStringTag]() {
107
+ return "DocumentFragment";
108
+ }
109
+ }
110
+ export {
111
+ DocumentFragment
112
+ };
@@ -0,0 +1,83 @@
1
+ import { Node } from "./node.js";
2
+ import { HTMLElement } from "./html-element.js";
3
+ import { HTMLImageElement } from "./html-image-element.js";
4
+ import { HTMLCanvasElement } from "./html-canvas-element.js";
5
+ import { Text } from "./text.js";
6
+ import { Comment } from "./comment.js";
7
+ import { DocumentFragment } from "./document-fragment.js";
8
+ import { Event } from "@gjsify/dom-events";
9
+ class Document extends Node {
10
+ constructor() {
11
+ super(...arguments);
12
+ /** Stub body element */
13
+ this.body = new HTMLElement();
14
+ /** Stub head element */
15
+ this.head = new HTMLElement();
16
+ /** Stub documentElement */
17
+ this.documentElement = new HTMLElement();
18
+ }
19
+ static {
20
+ /** External packages register element factories here (e.g. @gjsify/iframe registers 'iframe') */
21
+ this._elementFactories = /* @__PURE__ */ new Map();
22
+ }
23
+ /**
24
+ * Register a factory for a custom element tag name.
25
+ * Called as a side-effect by DOM packages to avoid circular dependencies.
26
+ *
27
+ * Example: `Document.registerElementFactory('iframe', () => new HTMLIFrameElement())`
28
+ */
29
+ static registerElementFactory(tagName, factory) {
30
+ Document._elementFactories.set(tagName.toLowerCase(), factory);
31
+ }
32
+ createElementNS(_namespace, tagName) {
33
+ const tag = tagName.toLowerCase();
34
+ switch (tag) {
35
+ case "img":
36
+ return new HTMLImageElement();
37
+ case "canvas":
38
+ return new HTMLCanvasElement();
39
+ default: {
40
+ const factory = Document._elementFactories.get(tag);
41
+ if (factory) return factory();
42
+ return new HTMLElement();
43
+ }
44
+ }
45
+ }
46
+ createElement(tagName) {
47
+ return this.createElementNS("http://www.w3.org/1999/xhtml", tagName);
48
+ }
49
+ createTextNode(data) {
50
+ return new Text(data);
51
+ }
52
+ createComment(data) {
53
+ return new Comment(data);
54
+ }
55
+ createDocumentFragment() {
56
+ return new DocumentFragment();
57
+ }
58
+ createEvent(type) {
59
+ return new Event(type);
60
+ }
61
+ /**
62
+ * Find an element by ID. Searches body's descendants.
63
+ */
64
+ getElementById(id) {
65
+ return this._findById(this.body, id);
66
+ }
67
+ _findById(element, id) {
68
+ if (element.id === id) return element;
69
+ for (const child of element.children) {
70
+ const found = this._findById(child, id);
71
+ if (found) return found;
72
+ }
73
+ return null;
74
+ }
75
+ get [Symbol.toStringTag]() {
76
+ return "Document";
77
+ }
78
+ }
79
+ const document = new Document();
80
+ export {
81
+ Document,
82
+ document
83
+ };
@@ -0,0 +1,109 @@
1
+ class DOMTokenList {
2
+ constructor(ownerElement, attributeName) {
3
+ this._ownerElement = ownerElement;
4
+ this._attributeName = attributeName;
5
+ }
6
+ _getTokens() {
7
+ const value = this._ownerElement.getAttribute(this._attributeName);
8
+ if (!value) return [];
9
+ return value.split(/\s+/).filter((t) => t.length > 0);
10
+ }
11
+ _setTokens(tokens) {
12
+ const value = tokens.join(" ");
13
+ if (value) {
14
+ this._ownerElement.setAttribute(this._attributeName, value);
15
+ } else {
16
+ this._ownerElement.removeAttribute(this._attributeName);
17
+ }
18
+ }
19
+ get length() {
20
+ return this._getTokens().length;
21
+ }
22
+ get value() {
23
+ return this._ownerElement.getAttribute(this._attributeName) ?? "";
24
+ }
25
+ set value(val) {
26
+ if (val) {
27
+ this._ownerElement.setAttribute(this._attributeName, val);
28
+ } else {
29
+ this._ownerElement.removeAttribute(this._attributeName);
30
+ }
31
+ }
32
+ item(index) {
33
+ const tokens = this._getTokens();
34
+ return index >= 0 && index < tokens.length ? tokens[index] : null;
35
+ }
36
+ contains(token) {
37
+ return this._getTokens().includes(token);
38
+ }
39
+ add(...tokens) {
40
+ const current = this._getTokens();
41
+ for (const token of tokens) {
42
+ if (token && !current.includes(token)) {
43
+ current.push(token);
44
+ }
45
+ }
46
+ this._setTokens(current);
47
+ }
48
+ remove(...tokens) {
49
+ const current = this._getTokens().filter((t) => !tokens.includes(t));
50
+ this._setTokens(current);
51
+ }
52
+ toggle(token, force) {
53
+ const has = this.contains(token);
54
+ if (force !== void 0) {
55
+ if (force) {
56
+ this.add(token);
57
+ return true;
58
+ } else {
59
+ this.remove(token);
60
+ return false;
61
+ }
62
+ }
63
+ if (has) {
64
+ this.remove(token);
65
+ return false;
66
+ } else {
67
+ this.add(token);
68
+ return true;
69
+ }
70
+ }
71
+ replace(token, newToken) {
72
+ const tokens = this._getTokens();
73
+ const idx = tokens.indexOf(token);
74
+ if (idx === -1) return false;
75
+ tokens[idx] = newToken;
76
+ this._setTokens(tokens);
77
+ return true;
78
+ }
79
+ supports(_token) {
80
+ return true;
81
+ }
82
+ forEach(callback) {
83
+ const tokens = this._getTokens();
84
+ for (let i = 0; i < tokens.length; i++) {
85
+ callback(tokens[i], i, this);
86
+ }
87
+ }
88
+ keys() {
89
+ return this._getTokens().keys();
90
+ }
91
+ values() {
92
+ return this._getTokens().values();
93
+ }
94
+ entries() {
95
+ return this._getTokens().entries();
96
+ }
97
+ [Symbol.iterator]() {
98
+ return this._getTokens().values();
99
+ }
100
+ toString() {
101
+ return this.value;
102
+ }
103
+ get [Symbol.toStringTag]() {
104
+ return "DOMTokenList";
105
+ }
106
+ }
107
+ export {
108
+ DOMTokenList
109
+ };
@@ -0,0 +1,237 @@
1
+ var _a, _b, _c, _d, _e, _f;
2
+ import { Node } from "./node.js";
3
+ import { NodeType } from "./node-type.js";
4
+ import { NamedNodeMap } from "./named-node-map.js";
5
+ import { NamespaceURI } from "./namespace-uri.js";
6
+ import * as PS from "./property-symbol.js";
7
+ class Element extends Node {
8
+ constructor() {
9
+ super();
10
+ this[_f] = "";
11
+ this[_e] = "";
12
+ this[_d] = NamespaceURI.html;
13
+ this[_c] = null;
14
+ this[_b] = new NamedNodeMap(this);
15
+ this[_a] = /* @__PURE__ */ new Map();
16
+ this[PS.nodeType] = NodeType.ELEMENT_NODE;
17
+ }
18
+ get tagName() {
19
+ return this[PS.tagName];
20
+ }
21
+ get localName() {
22
+ return this[PS.localName];
23
+ }
24
+ get namespaceURI() {
25
+ return this[PS.namespaceURI];
26
+ }
27
+ get prefix() {
28
+ return this[PS.prefix];
29
+ }
30
+ get nodeName() {
31
+ return this[PS.tagName];
32
+ }
33
+ get attributes() {
34
+ return this[PS.attributes];
35
+ }
36
+ get id() {
37
+ return this.getAttribute("id") ?? "";
38
+ }
39
+ set id(value) {
40
+ this.setAttribute("id", value);
41
+ }
42
+ get className() {
43
+ return this.getAttribute("class") ?? "";
44
+ }
45
+ set className(value) {
46
+ this.setAttribute("class", value);
47
+ }
48
+ get children() {
49
+ return this[PS.elementChildren];
50
+ }
51
+ get childElementCount() {
52
+ return this[PS.elementChildren].length;
53
+ }
54
+ get firstElementChild() {
55
+ return this[PS.elementChildren][0] ?? null;
56
+ }
57
+ get lastElementChild() {
58
+ const children = this[PS.elementChildren];
59
+ return children[children.length - 1] ?? null;
60
+ }
61
+ get previousElementSibling() {
62
+ const parent = this[PS.parentNode];
63
+ if (!parent) return null;
64
+ const siblings = parent[PS.elementChildren];
65
+ const idx = siblings.indexOf(this);
66
+ return idx > 0 ? siblings[idx - 1] : null;
67
+ }
68
+ get nextElementSibling() {
69
+ const parent = this[PS.parentNode];
70
+ if (!parent) return null;
71
+ const siblings = parent[PS.elementChildren];
72
+ const idx = siblings.indexOf(this);
73
+ return idx !== -1 && idx < siblings.length - 1 ? siblings[idx + 1] : null;
74
+ }
75
+ get textContent() {
76
+ let text = "";
77
+ for (const child of this[PS.childNodesList]) {
78
+ if (child.textContent !== null) {
79
+ text += child.textContent;
80
+ }
81
+ }
82
+ return text;
83
+ }
84
+ set textContent(_value) {
85
+ const children = this[PS.childNodesList];
86
+ while (children.length > 0) {
87
+ this.removeChild(children[0]);
88
+ }
89
+ }
90
+ // -- Attribute methods --
91
+ getAttribute(qualifiedName) {
92
+ const attr = this[PS.attributes].getNamedItem(qualifiedName);
93
+ return attr ? attr.value : null;
94
+ }
95
+ getAttributeNS(namespace, localName) {
96
+ const attr = this[PS.attributes].getNamedItemNS(namespace, localName);
97
+ return attr ? attr.value : null;
98
+ }
99
+ setAttribute(qualifiedName, value) {
100
+ this[PS.attributes]._setNamedItem(qualifiedName, String(value));
101
+ }
102
+ setAttributeNS(namespace, qualifiedName, value) {
103
+ const ns = namespace === "" ? null : namespace;
104
+ const parts = qualifiedName.split(":");
105
+ const prefix = parts.length > 1 ? parts[0] : null;
106
+ this[PS.attributes]._setNamedItem(qualifiedName, String(value), ns, prefix);
107
+ }
108
+ removeAttribute(qualifiedName) {
109
+ this[PS.attributes]._removeNamedItem(qualifiedName);
110
+ }
111
+ removeAttributeNS(namespace, localName) {
112
+ const ns = namespace === "" ? null : namespace;
113
+ this[PS.attributes]._removeNamedItemNS(ns, localName);
114
+ }
115
+ hasAttribute(qualifiedName) {
116
+ return this[PS.attributes].getNamedItem(qualifiedName) !== null;
117
+ }
118
+ hasAttributeNS(namespace, localName) {
119
+ return this[PS.attributes].getNamedItemNS(namespace, localName) !== null;
120
+ }
121
+ getAttributeNode(qualifiedName) {
122
+ return this[PS.attributes].getNamedItem(qualifiedName);
123
+ }
124
+ setAttributeNode(attr) {
125
+ return this[PS.attributes].setNamedItem(attr);
126
+ }
127
+ removeAttributeNode(attr) {
128
+ const existing = this[PS.attributes].getNamedItem(attr.name);
129
+ if (!existing) {
130
+ throw new DOMException(
131
+ "Failed to execute 'removeAttributeNode' on 'Element': The attribute is not owned by this element.",
132
+ "NotFoundError"
133
+ );
134
+ }
135
+ this[PS.attributes].removeNamedItem(existing.name);
136
+ return existing;
137
+ }
138
+ toggleAttribute(qualifiedName, force) {
139
+ if (force !== void 0) {
140
+ if (force) {
141
+ this.setAttribute(qualifiedName, "");
142
+ return true;
143
+ }
144
+ this.removeAttribute(qualifiedName);
145
+ return false;
146
+ }
147
+ if (this.hasAttribute(qualifiedName)) {
148
+ this.removeAttribute(qualifiedName);
149
+ return false;
150
+ }
151
+ this.setAttribute(qualifiedName, "");
152
+ return true;
153
+ }
154
+ hasAttributes() {
155
+ return this[PS.attributes].length > 0;
156
+ }
157
+ // -- Override dispatchEvent to call on* property handlers --
158
+ dispatchEvent(event) {
159
+ const result = super.dispatchEvent(event);
160
+ const handler = this[PS.propertyEventListeners].get("on" + event.type);
161
+ if (typeof handler === "function") {
162
+ handler.call(this, event);
163
+ }
164
+ return result;
165
+ }
166
+ // -- Stubs for commonly expected methods --
167
+ querySelector(_selectors) {
168
+ return null;
169
+ }
170
+ querySelectorAll(_selectors) {
171
+ return [];
172
+ }
173
+ matches(_selectors) {
174
+ return false;
175
+ }
176
+ closest(_selectors) {
177
+ return null;
178
+ }
179
+ getElementsByTagName(tagName) {
180
+ const results = [];
181
+ const upperTag = tagName.toUpperCase();
182
+ const walk = (node) => {
183
+ for (const child of node[PS.childNodesList]) {
184
+ if (child[PS.nodeType] === NodeType.ELEMENT_NODE) {
185
+ const el = child;
186
+ if (tagName === "*" || el[PS.tagName] === upperTag) {
187
+ results.push(el);
188
+ }
189
+ walk(el);
190
+ }
191
+ }
192
+ };
193
+ walk(this);
194
+ return results;
195
+ }
196
+ getElementsByClassName(className) {
197
+ const results = [];
198
+ const targetClasses = className.split(/\s+/).filter(Boolean);
199
+ const walk = (node) => {
200
+ for (const child of node[PS.childNodesList]) {
201
+ if (child[PS.nodeType] === NodeType.ELEMENT_NODE) {
202
+ const el = child;
203
+ const elClasses = el.className.split(/\s+/);
204
+ if (targetClasses.every((c) => elClasses.includes(c))) {
205
+ results.push(el);
206
+ }
207
+ walk(el);
208
+ }
209
+ }
210
+ };
211
+ walk(this);
212
+ return results;
213
+ }
214
+ // -- Clone --
215
+ cloneNode(deep = false) {
216
+ const clone = super.cloneNode(false);
217
+ clone[PS.tagName] = this[PS.tagName];
218
+ clone[PS.localName] = this[PS.localName];
219
+ clone[PS.namespaceURI] = this[PS.namespaceURI];
220
+ clone[PS.prefix] = this[PS.prefix];
221
+ for (const attr of this[PS.attributes]) {
222
+ clone.setAttributeNS(attr.namespaceURI, attr.name, attr.value);
223
+ }
224
+ if (deep) {
225
+ for (const child of this[PS.childNodesList]) {
226
+ clone.appendChild(child.cloneNode(true));
227
+ }
228
+ }
229
+ return clone;
230
+ }
231
+ get [(_f = PS.tagName, _e = PS.localName, _d = PS.namespaceURI, _c = PS.prefix, _b = PS.attributes, _a = PS.propertyEventListeners, Symbol.toStringTag)]() {
232
+ return "Element";
233
+ }
234
+ }
235
+ export {
236
+ Element
237
+ };