@remote-dom/polyfill 1.5.0 → 1.6.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 (304) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/README.md +51 -3
  3. package/build/cjs/Attr.cjs +33 -4
  4. package/build/cjs/CharacterData.cjs +10 -0
  5. package/build/cjs/ChildNode.cjs +79 -13
  6. package/build/cjs/Comment.cjs +1 -1
  7. package/build/cjs/CustomElementRegistry.cjs +27 -2
  8. package/build/cjs/CustomEvent.cjs +2 -2
  9. package/build/cjs/Document.cjs +56 -32
  10. package/build/cjs/DocumentFragment.cjs +6 -2
  11. package/build/cjs/Element.cjs +68 -8
  12. package/build/cjs/Event.cjs +29 -27
  13. package/build/cjs/EventTarget.cjs +128 -58
  14. package/build/cjs/HTMLTemplateElement.cjs +1 -0
  15. package/build/cjs/MutationObserver.cjs +167 -1
  16. package/build/cjs/NamedNodeMap.cjs +82 -45
  17. package/build/cjs/Node.cjs +47 -11
  18. package/build/cjs/NodeList.cjs +9 -1
  19. package/build/cjs/ParentNode.cjs +319 -77
  20. package/build/cjs/SVGElement.cjs +1 -1
  21. package/build/cjs/Text.cjs +1 -1
  22. package/build/cjs/Window.cjs +131 -38
  23. package/build/cjs/attribute-reactions.cjs +20 -0
  24. package/build/cjs/constants.cjs +48 -24
  25. package/build/cjs/custom-element-reactions.cjs +52 -0
  26. package/build/cjs/dom-exception.cjs +15 -0
  27. package/build/cjs/hook-effects.cjs +51 -0
  28. package/build/cjs/names.cjs +61 -0
  29. package/build/cjs/selectors.cjs +213 -122
  30. package/build/cjs/serialization.cjs +168 -65
  31. package/build/cjs/shared.cjs +177 -28
  32. package/build/esm/Attr.mjs +34 -5
  33. package/build/esm/CharacterData.mjs +10 -0
  34. package/build/esm/ChildNode.mjs +76 -15
  35. package/build/esm/Comment.mjs +2 -2
  36. package/build/esm/CustomElementRegistry.mjs +27 -2
  37. package/build/esm/CustomEvent.mjs +2 -2
  38. package/build/esm/Document.mjs +60 -35
  39. package/build/esm/DocumentFragment.mjs +7 -3
  40. package/build/esm/Element.mjs +69 -9
  41. package/build/esm/Event.mjs +27 -27
  42. package/build/esm/EventTarget.mjs +130 -60
  43. package/build/esm/HTMLTemplateElement.mjs +2 -1
  44. package/build/esm/MutationObserver.mjs +166 -2
  45. package/build/esm/NamedNodeMap.mjs +83 -46
  46. package/build/esm/Node.mjs +48 -12
  47. package/build/esm/NodeList.mjs +9 -1
  48. package/build/esm/ParentNode.mjs +322 -81
  49. package/build/esm/SVGElement.mjs +2 -2
  50. package/build/esm/Text.mjs +2 -2
  51. package/build/esm/Window.mjs +132 -39
  52. package/build/esm/attribute-reactions.mjs +16 -0
  53. package/build/esm/constants.mjs +28 -23
  54. package/build/esm/custom-element-reactions.mjs +47 -0
  55. package/build/esm/dom-exception.mjs +11 -0
  56. package/build/esm/hook-effects.mjs +46 -0
  57. package/build/esm/names.mjs +54 -0
  58. package/build/esm/selectors.mjs +202 -124
  59. package/build/esm/serialization.mjs +169 -66
  60. package/build/esm/shared.mjs +173 -30
  61. package/build/esnext/Attr.esnext +45 -5
  62. package/build/esnext/CharacterData.esnext +10 -0
  63. package/build/esnext/ChildNode.esnext +84 -15
  64. package/build/esnext/Comment.esnext +2 -2
  65. package/build/esnext/CustomElementRegistry.esnext +42 -0
  66. package/build/esnext/CustomEvent.esnext +2 -2
  67. package/build/esnext/Document.esnext +69 -32
  68. package/build/esnext/DocumentFragment.esnext +7 -3
  69. package/build/esnext/Element.esnext +78 -9
  70. package/build/esnext/Event.esnext +36 -37
  71. package/build/esnext/EventTarget.esnext +133 -61
  72. package/build/esnext/HTMLTemplateElement.esnext +3 -1
  73. package/build/esnext/MutationObserver.esnext +163 -2
  74. package/build/esnext/NamedNodeMap.esnext +110 -42
  75. package/build/esnext/Node.esnext +50 -12
  76. package/build/esnext/NodeList.esnext +1 -1
  77. package/build/esnext/ParentNode.esnext +352 -79
  78. package/build/esnext/SVGElement.esnext +2 -2
  79. package/build/esnext/Text.esnext +2 -2
  80. package/build/esnext/Window.esnext +120 -16
  81. package/build/esnext/attribute-reactions.esnext +21 -0
  82. package/build/esnext/constants.esnext +34 -21
  83. package/build/esnext/custom-element-reactions.esnext +49 -0
  84. package/build/esnext/dom-exception.esnext +11 -0
  85. package/build/esnext/hook-effects.esnext +46 -0
  86. package/build/esnext/names.esnext +61 -0
  87. package/build/esnext/selectors.esnext +202 -100
  88. package/build/esnext/serialization.esnext +171 -48
  89. package/build/esnext/shared.esnext +181 -34
  90. package/build/tsconfig.tsbuildinfo +1 -1
  91. package/build/typescript/Attr.d.ts +6 -4
  92. package/build/typescript/Attr.d.ts.map +1 -1
  93. package/build/typescript/CharacterData.d.ts.map +1 -1
  94. package/build/typescript/ChildNode.d.ts +5 -0
  95. package/build/typescript/ChildNode.d.ts.map +1 -1
  96. package/build/typescript/ClipboardEvent.d.ts.map +1 -1
  97. package/build/typescript/Comment.d.ts +2 -2
  98. package/build/typescript/Comment.d.ts.map +1 -1
  99. package/build/typescript/CustomElementRegistry.d.ts +1 -0
  100. package/build/typescript/CustomElementRegistry.d.ts.map +1 -1
  101. package/build/typescript/CustomEvent.d.ts.map +1 -1
  102. package/build/typescript/Document.d.ts +10 -5
  103. package/build/typescript/Document.d.ts.map +1 -1
  104. package/build/typescript/DocumentFragment.d.ts +2 -1
  105. package/build/typescript/DocumentFragment.d.ts.map +1 -1
  106. package/build/typescript/Element.d.ts +16 -7
  107. package/build/typescript/Element.d.ts.map +1 -1
  108. package/build/typescript/ErrorEvent.d.ts.map +1 -1
  109. package/build/typescript/Event.d.ts +9 -10
  110. package/build/typescript/Event.d.ts.map +1 -1
  111. package/build/typescript/EventTarget.d.ts +20 -3
  112. package/build/typescript/EventTarget.d.ts.map +1 -1
  113. package/build/typescript/FocusEvent.d.ts.map +1 -1
  114. package/build/typescript/HTMLTemplateElement.d.ts.map +1 -1
  115. package/build/typescript/MutationObserver.d.ts +42 -0
  116. package/build/typescript/MutationObserver.d.ts.map +1 -1
  117. package/build/typescript/NamedNodeMap.d.ts +5 -3
  118. package/build/typescript/NamedNodeMap.d.ts.map +1 -1
  119. package/build/typescript/Node.d.ts +4 -3
  120. package/build/typescript/Node.d.ts.map +1 -1
  121. package/build/typescript/NodeList.d.ts +3 -2
  122. package/build/typescript/NodeList.d.ts.map +1 -1
  123. package/build/typescript/ParentNode.d.ts +29 -10
  124. package/build/typescript/ParentNode.d.ts.map +1 -1
  125. package/build/typescript/PromiseRejectionEvent.d.ts.map +1 -1
  126. package/build/typescript/SVGElement.d.ts +1 -1
  127. package/build/typescript/SVGElement.d.ts.map +1 -1
  128. package/build/typescript/Text.d.ts +1 -1
  129. package/build/typescript/Text.d.ts.map +1 -1
  130. package/build/typescript/ToggleEvent.d.ts.map +1 -1
  131. package/build/typescript/Window.d.ts +5 -1
  132. package/build/typescript/Window.d.ts.map +1 -1
  133. package/build/typescript/attribute-reactions.d.ts +4 -0
  134. package/build/typescript/attribute-reactions.d.ts.map +1 -0
  135. package/build/typescript/constants.d.ts +27 -18
  136. package/build/typescript/constants.d.ts.map +1 -1
  137. package/build/typescript/custom-element-reactions.d.ts +6 -0
  138. package/build/typescript/custom-element-reactions.d.ts.map +1 -0
  139. package/build/typescript/dom-exception.d.ts +2 -0
  140. package/build/typescript/dom-exception.d.ts.map +1 -0
  141. package/build/typescript/extensions.d.ts +4 -0
  142. package/build/typescript/extensions.d.ts.map +1 -0
  143. package/build/typescript/hook-effects.d.ts +6 -0
  144. package/build/typescript/hook-effects.d.ts.map +1 -0
  145. package/build/typescript/hooks.d.ts +3 -3
  146. package/build/typescript/hooks.d.ts.map +1 -1
  147. package/build/typescript/index.d.ts +1 -0
  148. package/build/typescript/index.d.ts.map +1 -1
  149. package/build/typescript/names.d.ts +11 -0
  150. package/build/typescript/names.d.ts.map +1 -0
  151. package/build/typescript/selectors.d.ts +21 -22
  152. package/build/typescript/selectors.d.ts.map +1 -1
  153. package/build/typescript/serialization.d.ts.map +1 -1
  154. package/build/typescript/shared.d.ts +10 -0
  155. package/build/typescript/shared.d.ts.map +1 -1
  156. package/build/typescript/tests/ChildNode.test.d.ts +2 -0
  157. package/build/typescript/tests/ChildNode.test.d.ts.map +1 -0
  158. package/build/typescript/tests/MutationObserver.test.d.ts +2 -0
  159. package/build/typescript/tests/MutationObserver.test.d.ts.map +1 -0
  160. package/build/typescript/tests/adopt-inserted-subtrees.test.d.ts +2 -0
  161. package/build/typescript/tests/adopt-inserted-subtrees.test.d.ts.map +1 -0
  162. package/build/typescript/tests/attr-mutation.test.d.ts +2 -0
  163. package/build/typescript/tests/attr-mutation.test.d.ts.map +1 -0
  164. package/build/typescript/tests/child-node-before-after.test.d.ts +2 -0
  165. package/build/typescript/tests/child-node-before-after.test.d.ts.map +1 -0
  166. package/build/typescript/tests/child-node-replace-with.test.d.ts +2 -0
  167. package/build/typescript/tests/child-node-replace-with.test.d.ts.map +1 -0
  168. package/build/typescript/tests/clone-import-namespaces.test.d.ts +2 -0
  169. package/build/typescript/tests/clone-import-namespaces.test.d.ts.map +1 -0
  170. package/build/typescript/tests/constants.test.d.ts +2 -0
  171. package/build/typescript/tests/constants.test.d.ts.map +1 -0
  172. package/build/typescript/tests/create-element-namespaces.test.d.ts +2 -0
  173. package/build/typescript/tests/create-element-namespaces.test.d.ts.map +1 -0
  174. package/build/typescript/tests/create-text-node.test.d.ts +2 -0
  175. package/build/typescript/tests/create-text-node.test.d.ts.map +1 -0
  176. package/build/typescript/tests/custom-element-reactions.test.d.ts +2 -0
  177. package/build/typescript/tests/custom-element-reactions.test.d.ts.map +1 -0
  178. package/build/typescript/tests/custom-element-registry.test.d.ts +2 -0
  179. package/build/typescript/tests/custom-element-registry.test.d.ts.map +1 -0
  180. package/build/typescript/tests/custom-event.test.d.ts +2 -0
  181. package/build/typescript/tests/custom-event.test.d.ts.map +1 -0
  182. package/build/typescript/tests/document-clone-import-contract.test.d.ts +2 -0
  183. package/build/typescript/tests/document-clone-import-contract.test.d.ts.map +1 -0
  184. package/build/typescript/tests/document.test.d.ts +2 -0
  185. package/build/typescript/tests/document.test.d.ts.map +1 -0
  186. package/build/typescript/tests/dom-mutation-selector-errors.test.d.ts +2 -0
  187. package/build/typescript/tests/dom-mutation-selector-errors.test.d.ts.map +1 -0
  188. package/build/typescript/tests/event-dispatch.test.d.ts +2 -0
  189. package/build/typescript/tests/event-dispatch.test.d.ts.map +1 -0
  190. package/build/typescript/tests/event-target.test.d.ts +2 -0
  191. package/build/typescript/tests/event-target.test.d.ts.map +1 -0
  192. package/build/typescript/tests/event.test.d.ts +2 -0
  193. package/build/typescript/tests/event.test.d.ts.map +1 -0
  194. package/build/typescript/tests/extensions.test.d.ts +2 -0
  195. package/build/typescript/tests/extensions.test.d.ts.map +1 -0
  196. package/build/typescript/tests/get-elements-by-tag-name.test.d.ts +2 -0
  197. package/build/typescript/tests/get-elements-by-tag-name.test.d.ts.map +1 -0
  198. package/build/typescript/tests/getElementsByClassName.test.d.ts +2 -0
  199. package/build/typescript/tests/getElementsByClassName.test.d.ts.map +1 -0
  200. package/build/typescript/tests/hooks.test.d.ts +2 -0
  201. package/build/typescript/tests/hooks.test.d.ts.map +1 -0
  202. package/build/typescript/tests/inner-html-parsing.test.d.ts +2 -0
  203. package/build/typescript/tests/inner-html-parsing.test.d.ts.map +1 -0
  204. package/build/typescript/tests/is-default-namespace.test.d.ts +2 -0
  205. package/build/typescript/tests/is-default-namespace.test.d.ts.map +1 -0
  206. package/build/typescript/tests/name-and-namespace-normalization.test.d.ts +2 -0
  207. package/build/typescript/tests/name-and-namespace-normalization.test.d.ts.map +1 -0
  208. package/build/typescript/tests/named-node-map.test.d.ts +2 -0
  209. package/build/typescript/tests/named-node-map.test.d.ts.map +1 -0
  210. package/build/typescript/tests/namespaced-attribute-reactions.test.d.ts +2 -0
  211. package/build/typescript/tests/namespaced-attribute-reactions.test.d.ts.map +1 -0
  212. package/build/typescript/tests/node.test.d.ts +2 -0
  213. package/build/typescript/tests/node.test.d.ts.map +1 -0
  214. package/build/typescript/tests/parent-node-mutation-return-values.test.d.ts +2 -0
  215. package/build/typescript/tests/parent-node-mutation-return-values.test.d.ts.map +1 -0
  216. package/build/typescript/tests/parent-node-mutation-validation.test.d.ts +2 -0
  217. package/build/typescript/tests/parent-node-mutation-validation.test.d.ts.map +1 -0
  218. package/build/typescript/tests/parent-node.test.d.ts +2 -0
  219. package/build/typescript/tests/parent-node.test.d.ts.map +1 -0
  220. package/build/typescript/tests/serialization-template.test.d.ts +2 -0
  221. package/build/typescript/tests/serialization-template.test.d.ts.map +1 -0
  222. package/build/typescript/tests/slot-attribute.test.d.ts +2 -0
  223. package/build/typescript/tests/slot-attribute.test.d.ts.map +1 -0
  224. package/build/typescript/tests/text-content.test.d.ts +2 -0
  225. package/build/typescript/tests/text-content.test.d.ts.map +1 -0
  226. package/build/typescript/tests/toggle-attribute.test.d.ts +2 -0
  227. package/build/typescript/tests/toggle-attribute.test.d.ts.map +1 -0
  228. package/build/typescript/tests/wide-tree-traversal.test.d.ts +2 -0
  229. package/build/typescript/tests/wide-tree-traversal.test.d.ts.map +1 -0
  230. package/build/typescript/tests/window-set-global.test.d.ts +2 -0
  231. package/build/typescript/tests/window-set-global.test.d.ts.map +1 -0
  232. package/package.json +1 -1
  233. package/source/Attr.ts +60 -8
  234. package/source/CharacterData.ts +13 -0
  235. package/source/ChildNode.ts +107 -14
  236. package/source/Comment.ts +2 -2
  237. package/source/CustomElementRegistry.ts +56 -0
  238. package/source/CustomEvent.ts +2 -2
  239. package/source/Document.ts +104 -38
  240. package/source/DocumentFragment.ts +15 -3
  241. package/source/Element.ts +129 -14
  242. package/source/Event.ts +34 -32
  243. package/source/EventTarget.ts +203 -79
  244. package/source/HTMLTemplateElement.ts +2 -1
  245. package/source/MutationObserver.ts +279 -1
  246. package/source/NamedNodeMap.ts +141 -60
  247. package/source/Node.ts +70 -14
  248. package/source/NodeList.ts +13 -3
  249. package/source/ParentNode.ts +500 -88
  250. package/source/SVGElement.ts +2 -2
  251. package/source/Text.ts +2 -2
  252. package/source/Window.ts +156 -17
  253. package/source/attribute-reactions.ts +32 -0
  254. package/source/constants.ts +40 -17
  255. package/source/custom-element-reactions.ts +64 -0
  256. package/source/dom-exception.ts +14 -0
  257. package/source/extensions.ts +4 -0
  258. package/source/hook-effects.ts +56 -0
  259. package/source/hooks.ts +11 -3
  260. package/source/index.ts +1 -0
  261. package/source/names.ts +94 -0
  262. package/source/selectors.ts +301 -138
  263. package/source/serialization.ts +224 -66
  264. package/source/shared.ts +269 -40
  265. package/source/tests/ChildNode.test.ts +178 -0
  266. package/source/tests/MutationObserver.test.ts +303 -0
  267. package/source/tests/adopt-inserted-subtrees.test.ts +584 -0
  268. package/source/tests/attr-mutation.test.ts +112 -0
  269. package/source/tests/child-node-before-after.test.ts +421 -0
  270. package/source/tests/child-node-replace-with.test.ts +251 -0
  271. package/source/tests/clone-import-namespaces.test.ts +365 -0
  272. package/source/tests/constants.test.ts +46 -0
  273. package/source/tests/create-element-namespaces.test.ts +142 -0
  274. package/source/tests/create-text-node.test.ts +38 -0
  275. package/source/tests/custom-element-reactions.test.ts +600 -0
  276. package/source/tests/custom-element-registry.test.ts +137 -0
  277. package/source/tests/custom-event.test.ts +26 -0
  278. package/source/tests/document-clone-import-contract.test.ts +77 -0
  279. package/source/tests/document.test.ts +122 -0
  280. package/source/tests/dom-mutation-selector-errors.test.ts +484 -0
  281. package/source/tests/event-dispatch.test.ts +270 -0
  282. package/source/tests/event-target.test.ts +208 -0
  283. package/source/tests/event.test.ts +98 -0
  284. package/source/tests/extensions.test.ts +159 -0
  285. package/source/tests/get-elements-by-tag-name.test.ts +79 -0
  286. package/source/tests/getElementsByClassName.test.ts +109 -0
  287. package/source/tests/hooks.test.ts +43 -0
  288. package/source/tests/inner-html-parsing.test.ts +461 -0
  289. package/source/tests/is-default-namespace.test.ts +111 -0
  290. package/source/tests/name-and-namespace-normalization.test.ts +319 -0
  291. package/source/tests/named-node-map.test.ts +122 -0
  292. package/source/tests/namespaced-attribute-reactions.test.ts +141 -0
  293. package/source/tests/node.test.ts +56 -0
  294. package/source/tests/parent-node-mutation-return-values.test.ts +63 -0
  295. package/source/tests/parent-node-mutation-validation.test.ts +362 -0
  296. package/source/tests/parent-node.test.ts +169 -0
  297. package/source/tests/selectors.test.ts +533 -22
  298. package/source/tests/serialization-template.test.ts +232 -0
  299. package/source/tests/slot-attribute.test.ts +133 -0
  300. package/source/tests/text-content.test.ts +440 -0
  301. package/source/tests/toggle-attribute.test.ts +113 -0
  302. package/source/tests/wide-tree-traversal.test.ts +699 -0
  303. package/source/tests/window-set-global.test.ts +321 -0
  304. package/tsconfig.json +1 -1
@@ -1,53 +1,86 @@
1
- import { LISTENERS, OWNER_DOCUMENT, HOOKS, PATH } from './constants.mjs';
2
- import { fireEvent, CAPTURE_MARKER, EventPhase } from './Event.mjs';
1
+ import { LISTENERS, OWNER_DOCUMENT, HOOKS_DISPATCH, DISPATCHING, PATH, STOP_IMMEDIATE_PROPAGATION } from './constants.mjs';
2
+ import { createDOMException } from './dom-exception.mjs';
3
+ import { fireEvent, EVENT_PHASE_CAPTURING, EVENT_PHASE_BUBBLING, EVENT_PHASE_NONE } from './Event.mjs';
3
4
 
4
- const ONCE_LISTENERS = Symbol('onceListeners');
5
+ const LISTENER_REGISTRATIONS = Symbol('listenerRegistrations');
5
6
  class EventTarget {
6
- [LISTENERS] = (() => undefined)();
7
- [ONCE_LISTENERS] = (() => undefined)();
7
+ [LISTENERS] = undefined;
8
+ [LISTENER_REGISTRATIONS] = undefined;
8
9
 
9
10
  /**
10
11
  * Property set by entities that extend this class that are part of the DOM tree.
11
12
  * @internal
12
13
  */
13
- [OWNER_DOCUMENT] = (() => undefined)();
14
+ [OWNER_DOCUMENT] = undefined;
14
15
  addEventListener(type, listener, options) {
15
16
  if (listener == null) return;
16
- const capture = options === true || options && options.capture === true;
17
+ const capture = options === true || typeof options === 'object' && options.capture === true;
17
18
  const once = typeof options === 'object' && options.once === true;
18
19
  const signal = typeof options === 'object' ? options.signal : undefined;
19
- const key = `${type}${capture ? CAPTURE_MARKER : ''}`;
20
- let normalizedListener = listener;
21
- if (once) {
22
- normalizedListener = function normalizedListener(...args) {
23
- this.removeEventListener(type, listener, options);
24
- return typeof listener === 'object' ? listener.handleEvent(...args) : listener.call(this, ...args);
20
+ if (signal?.aborted) return;
21
+ const phase = listenerPhase(capture);
22
+ let registrations = this[LISTENER_REGISTRATIONS];
23
+ if (!registrations) {
24
+ registrations = new Map();
25
+ this[LISTENER_REGISTRATIONS] = registrations;
26
+ }
27
+ let registrationsForType = registrations.get(type);
28
+ if (!registrationsForType) {
29
+ registrationsForType = {};
30
+ registrations.set(type, registrationsForType);
31
+ }
32
+ let registrationsForPhase = registrationsForType[phase];
33
+ if (!registrationsForPhase) {
34
+ registrationsForPhase = new Map();
35
+ registrationsForType[phase] = registrationsForPhase;
36
+ }
37
+ if (registrationsForPhase.has(listener)) return;
38
+ const target = this;
39
+ const registration = {
40
+ type,
41
+ listener,
42
+ capture,
43
+ once,
44
+ normalizedListener: listener,
45
+ signal
46
+ };
47
+ if (once || signal) {
48
+ registration.normalizedListener = function normalizedListener(...args) {
49
+ if (registration.signal?.aborted) {
50
+ removeListenerRegistration(target, registration);
51
+ return;
52
+ }
53
+ if (registration.once) removeListenerRegistration(target, registration);
54
+ return typeof registration.listener === 'object' ? registration.listener.handleEvent(...args) : registration.listener.call(this, ...args);
25
55
  };
26
- let onceListeners = this[ONCE_LISTENERS];
27
- if (!onceListeners) {
28
- onceListeners = new WeakMap();
29
- this[ONCE_LISTENERS] = onceListeners;
30
- }
31
- onceListeners.set(listener, normalizedListener);
32
56
  }
33
57
  let listeners = this[LISTENERS];
34
58
  if (!listeners) {
35
59
  listeners = new Map();
36
60
  this[LISTENERS] = listeners;
37
61
  }
38
- let list = listeners.get(key);
62
+ let listenersForType = listeners.get(type);
63
+ if (!listenersForType) {
64
+ listenersForType = {};
65
+ listeners.set(type, listenersForType);
66
+ }
67
+ let list = listenersForType[phase];
39
68
  if (!list) {
40
69
  list = new Set();
41
- listeners.set(key, list);
70
+ listenersForType[phase] = list;
42
71
  }
43
- if (list.has(normalizedListener)) return;
44
- signal?.addEventListener('abort', () => {
45
- removeEventListener.call(this, type, listener, options);
46
- }, {
47
- once: true
48
- });
49
- list.add(normalizedListener);
50
- this[OWNER_DOCUMENT]?.defaultView[HOOKS].addEventListener?.(this, type, listener, options);
72
+ registrationsForPhase.set(listener, registration);
73
+ list.add(registration);
74
+ if (signal) {
75
+ const abortListener = () => {
76
+ removeListenerRegistration(target, registration);
77
+ };
78
+ registration.abortListener = abortListener;
79
+ signal.addEventListener('abort', abortListener, {
80
+ once: true
81
+ });
82
+ }
83
+ this[OWNER_DOCUMENT]?.defaultView[HOOKS_DISPATCH].addEventListener?.(this, type, listener, options);
51
84
  }
52
85
  removeEventListener(type, listener, options) {
53
86
  return removeEventListener.call(this, type, listener, options);
@@ -58,45 +91,82 @@ class EventTarget {
58
91
  // }
59
92
 
60
93
  dispatchEvent(event) {
61
- const path = [];
62
- // instanceof here is just to keep TypeScript happy
63
- let target = this;
64
- while (target != null) {
65
- path.push(target);
66
- target = target.parentNode;
94
+ if (event[DISPATCHING]) {
95
+ throw createDOMException(`Failed to execute 'dispatchEvent' on 'EventTarget': The event is already being dispatched.`, 'InvalidStateError');
67
96
  }
68
- // while (target instanceof Node && (target = target.parentNode)) {
69
- // path.push(target);
70
- // }
71
- event.target = this;
72
- event.srcElement = this;
73
- event[PATH] = path;
74
- for (let i = path.length; i--;) {
75
- fireEvent(event, path[i], EventPhase.CAPTURING_PHASE);
76
- if (event.cancelBubble) return event.defaultPrevented;
77
- }
78
- const bubblePath = event.bubbles ? path : path.slice(0, 1);
79
- for (let i = 0; i < bubblePath.length; i++) {
80
- fireEvent(event, bubblePath[i], EventPhase.BUBBLING_PHASE);
81
- if (event.cancelBubble) return event.defaultPrevented;
97
+ event[DISPATCHING] = true;
98
+ try {
99
+ const path = [];
100
+ // instanceof here is just to keep TypeScript happy
101
+ let target = this;
102
+ while (target != null) {
103
+ path.push(target);
104
+ target = target.parentNode;
105
+ }
106
+ // while (target instanceof Node && (target = target.parentNode)) {
107
+ // path.push(target);
108
+ // }
109
+ event.target = this;
110
+ event.srcElement = this;
111
+ event[PATH] = path;
112
+ for (let i = path.length; i--;) {
113
+ fireEvent(event, path[i], EVENT_PHASE_CAPTURING);
114
+ if (event.cancelBubble) return !event.defaultPrevented;
115
+ }
116
+ const bubblePath = event.bubbles ? path : path.slice(0, 1);
117
+ for (let i = 0; i < bubblePath.length; i++) {
118
+ fireEvent(event, bubblePath[i], EVENT_PHASE_BUBBLING);
119
+ if (event.cancelBubble) return !event.defaultPrevented;
120
+ }
121
+ return !event.defaultPrevented;
122
+ } finally {
123
+ event[DISPATCHING] = false;
124
+ event.cancelBubble = false;
125
+ event[STOP_IMMEDIATE_PROPAGATION] = false;
126
+ event.eventPhase = EVENT_PHASE_NONE;
127
+ event.currentTarget = null;
128
+ event[PATH] = [];
82
129
  }
83
- return event.defaultPrevented;
84
130
  }
85
131
  }
86
132
  function removeEventListener(type, listener, options) {
87
133
  if (listener == null) return;
88
- const onceListeners = this[ONCE_LISTENERS];
89
- const normalizedListener = onceListeners?.get(listener) ?? listener;
90
- onceListeners?.delete(listener);
91
134
  const capture = options === true || options && options.capture === true;
92
- const key = `${type}${capture ? CAPTURE_MARKER : ''}`;
93
- const list = this[LISTENERS]?.get(key);
94
- if (list) {
95
- const deleted = list.delete(normalizedListener);
96
- if (deleted) {
97
- this[OWNER_DOCUMENT]?.defaultView[HOOKS].removeEventListener?.(this, type, listener, options);
98
- }
135
+ const phase = listenerPhase(Boolean(capture));
136
+ const registration = this[LISTENER_REGISTRATIONS]?.get(type)?.[phase]?.get(listener);
137
+ if (!registration) return;
138
+ removeListenerRegistration(this, registration);
139
+ }
140
+ function listenerPhase(capture) {
141
+ return capture ? 'capture' : 'bubble';
142
+ }
143
+ function removeListenerRegistration(target, registration) {
144
+ const phase = listenerPhase(registration.capture);
145
+ const registrations = target[LISTENER_REGISTRATIONS];
146
+ const registrationsForType = registrations?.get(registration.type);
147
+ if (!registrationsForType) return;
148
+ const registrationsForPhase = registrationsForType[phase];
149
+ if (!registrationsForPhase || registrationsForPhase.get(registration.listener) !== registration) {
150
+ return;
151
+ }
152
+ registrationsForPhase.delete(registration.listener);
153
+ if (registrationsForPhase.size === 0) delete registrationsForType[phase];
154
+ if (!registrationsForType.bubble && !registrationsForType.capture) {
155
+ registrations?.delete(registration.type);
156
+ }
157
+ if (registration.signal && registration.abortListener) {
158
+ registration.signal.removeEventListener('abort', registration.abortListener);
159
+ }
160
+ const listeners = target[LISTENERS];
161
+ const listenersForType = listeners?.get(registration.type);
162
+ if (!listenersForType) return;
163
+ const list = listenersForType[phase];
164
+ if (!list?.delete(registration)) return;
165
+ if (list.size === 0) delete listenersForType[phase];
166
+ if (!listenersForType.bubble && !listenersForType.capture) {
167
+ listeners?.delete(registration.type);
99
168
  }
169
+ target[OWNER_DOCUMENT]?.defaultView[HOOKS_DISPATCH].removeEventListener?.(target, registration.type, registration.listener, registration.capture);
100
170
  }
101
171
 
102
172
  export { EventTarget };
@@ -1,4 +1,4 @@
1
- import { CONTENT } from './constants.mjs';
1
+ import { CONTENT, HOST } from './constants.mjs';
2
2
  import { Element } from './Element.mjs';
3
3
  import { parseHtml, serializeChildren } from './serialization.mjs';
4
4
 
@@ -7,6 +7,7 @@ class HTMLTemplateElement extends Element {
7
7
  let content = this[CONTENT];
8
8
  if (!content) {
9
9
  content = this.ownerDocument.createDocumentFragment();
10
+ content[HOST] = this;
10
11
  this[CONTENT] = content;
11
12
  }
12
13
  return content;
@@ -1,5 +1,169 @@
1
+ import { NodeList } from './NodeList.mjs';
2
+
3
+ let registrations;
4
+ let registrationCount = 0;
5
+ let attributeRegistrationCount = 0;
6
+ let characterDataRegistrationCount = 0;
7
+ let childListRegistrationCount = 0;
8
+
9
+ // Mutation sites read these live bindings before capturing old values or
10
+ // allocating record data. Keep them split so observing one mutation type does
11
+ // not add work to unrelated mutations.
12
+ /** @internal */
13
+ let attributeObserversActive = false;
14
+ /** @internal */
15
+ let characterDataObserversActive = false;
16
+ /** @internal */
17
+ let childListObserversActive = false;
1
18
  class MutationObserver {
2
- // stub implementation
19
+ #callback;
20
+ #records = [];
21
+ #targets = new Set();
22
+ #scheduled = false;
23
+ constructor(callback) {
24
+ if (typeof callback !== 'function') {
25
+ throw new TypeError('MutationObserver callback must be a function');
26
+ }
27
+ this.#callback = callback;
28
+ }
29
+ observe(target, options = {}) {
30
+ const normalizedOptions = normalizeOptions(options);
31
+ const currentRegistrations = registrations ??= new WeakMap();
32
+ let targetRegistrations = currentRegistrations.get(target);
33
+ if (targetRegistrations == null) {
34
+ targetRegistrations = new Map();
35
+ currentRegistrations.set(target, targetRegistrations);
36
+ }
37
+ const previousOptions = targetRegistrations.get(this);
38
+ if (previousOptions == null) {
39
+ registrationCount++;
40
+ } else {
41
+ updateRegistrationCounts(previousOptions, -1);
42
+ }
43
+ targetRegistrations.set(this, normalizedOptions);
44
+ updateRegistrationCounts(normalizedOptions, 1);
45
+ this.#targets.add(target);
46
+ }
47
+ disconnect() {
48
+ const currentRegistrations = registrations;
49
+ if (currentRegistrations == null) return;
50
+ for (const target of this.#targets) {
51
+ const targetRegistrations = currentRegistrations.get(target);
52
+ const options = targetRegistrations?.get(this);
53
+ if (options != null) {
54
+ targetRegistrations.delete(this);
55
+ registrationCount--;
56
+ updateRegistrationCounts(options, -1);
57
+ }
58
+ if (targetRegistrations?.size === 0) {
59
+ currentRegistrations.delete(target);
60
+ }
61
+ }
62
+ this.#targets.clear();
63
+ this.#records.length = 0;
64
+ if (registrationCount === 0) {
65
+ registrations = undefined;
66
+ }
67
+ }
68
+ takeRecords() {
69
+ return this.#records.splice(0);
70
+ }
71
+
72
+ /** @internal */
73
+ enqueue(record) {
74
+ this.#records.push(record);
75
+ if (this.#scheduled) return;
76
+ this.#scheduled = true;
77
+ queueMicrotask(() => {
78
+ this.#scheduled = false;
79
+ const records = this.takeRecords();
80
+ if (records.length > 0) {
81
+ this.#callback.call(this, records, this);
82
+ }
83
+ });
84
+ }
85
+ }
86
+
87
+ /** @internal */
88
+ function queueMutationRecord(init) {
89
+ const currentRegistrations = registrations;
90
+ if (currentRegistrations == null) return;
91
+ const interestedObservers = new Map();
92
+ let node = init.target;
93
+ while (node) {
94
+ const targetRegistrations = currentRegistrations.get(node);
95
+ if (targetRegistrations) {
96
+ for (const [observer, options] of targetRegistrations) {
97
+ if (node !== init.target && !options.subtree) continue;
98
+ let includeOldValue = false;
99
+ if (init.type === 'attributes') {
100
+ if (!options.attributes) continue;
101
+ if (options.attributeFilter && !options.attributeFilter.has(init.attributeName ?? '')) {
102
+ continue;
103
+ }
104
+ includeOldValue = options.attributeOldValue;
105
+ } else if (init.type === 'characterData') {
106
+ if (!options.characterData) continue;
107
+ includeOldValue = options.characterDataOldValue;
108
+ } else if (!options.childList) {
109
+ continue;
110
+ }
111
+ interestedObservers.set(observer, interestedObservers.get(observer) === true || includeOldValue);
112
+ }
113
+ }
114
+ node = node.parentNode;
115
+ }
116
+ for (const [observer, includeOldValue] of interestedObservers) {
117
+ observer.enqueue({
118
+ addedNodes: init.addedNodes ?? new NodeList(),
119
+ attributeName: init.attributeName ?? null,
120
+ attributeNamespace: init.attributeNamespace ?? null,
121
+ nextSibling: init.nextSibling ?? null,
122
+ oldValue: includeOldValue ? init.oldValue ?? null : null,
123
+ previousSibling: init.previousSibling ?? null,
124
+ removedNodes: init.removedNodes ?? new NodeList(),
125
+ target: init.target,
126
+ type: init.type
127
+ });
128
+ }
129
+ }
130
+
131
+ /** @internal */
132
+ function mutationNodeList(...nodes) {
133
+ const list = new NodeList();
134
+ list.push(...nodes);
135
+ return list;
136
+ }
137
+ function normalizeOptions(options) {
138
+ if (options.attributes === false && (options.attributeOldValue || options.attributeFilter != null)) {
139
+ throw new TypeError('attributeOldValue and attributeFilter require attributes to be enabled');
140
+ }
141
+ if (options.characterData === false && options.characterDataOldValue) {
142
+ throw new TypeError('characterDataOldValue requires characterData to be enabled');
143
+ }
144
+ const attributes = options.attributes ?? (options.attributeOldValue === true || options.attributeFilter != null);
145
+ const characterData = options.characterData ?? options.characterDataOldValue === true;
146
+ const childList = options.childList === true;
147
+ if (!attributes && !characterData && !childList) {
148
+ throw new TypeError('MutationObserver options must enable childList, attributes, or characterData');
149
+ }
150
+ return {
151
+ attributes,
152
+ attributeFilter: options.attributeFilter == null ? undefined : new Set(options.attributeFilter.map(String)),
153
+ attributeOldValue: options.attributeOldValue === true,
154
+ characterData,
155
+ characterDataOldValue: options.characterDataOldValue === true,
156
+ childList,
157
+ subtree: options.subtree === true
158
+ };
159
+ }
160
+ function updateRegistrationCounts(options, delta) {
161
+ if (options.attributes) attributeRegistrationCount += delta;
162
+ if (options.characterData) characterDataRegistrationCount += delta;
163
+ if (options.childList) childListRegistrationCount += delta;
164
+ attributeObserversActive = attributeRegistrationCount > 0;
165
+ characterDataObserversActive = characterDataRegistrationCount > 0;
166
+ childListObserversActive = childListRegistrationCount > 0;
3
167
  }
4
168
 
5
- export { MutationObserver };
169
+ export { MutationObserver, attributeObserversActive, characterDataObserversActive, childListObserversActive, mutationNodeList, queueMutationRecord };
@@ -1,4 +1,9 @@
1
- import { CHILD, OWNER_ELEMENT, NS, NEXT, HOOKS } from './constants.mjs';
1
+ import { CHILD, OWNER_ELEMENT, NS, HTML_NAMESPACE, asciiLowercase, NEXT, HOOKS, OWNER_DOCUMENT } from './constants.mjs';
2
+ import { normalizeNamespace } from './names.mjs';
3
+ import { attributeObserversActive, queueMutationRecord } from './MutationObserver.mjs';
4
+ import { performWithCustomElementReactions } from './custom-element-reactions.mjs';
5
+ import { enqueueAttributeReaction } from './attribute-reactions.mjs';
6
+ import { createDOMException } from './dom-exception.mjs';
2
7
 
3
8
  class NamedNodeMap {
4
9
  [CHILD] = null;
@@ -6,12 +11,21 @@ class NamedNodeMap {
6
11
  this[OWNER_ELEMENT] = ownerElement;
7
12
  }
8
13
  getNamedItem(name) {
9
- return this.getNamedItemNS(null, name);
14
+ const qualifiedName = String(name);
15
+ const normalizedName = this[OWNER_ELEMENT][NS] === HTML_NAMESPACE ? asciiLowercase(qualifiedName) : qualifiedName;
16
+ let attr = this[CHILD];
17
+ while (attr) {
18
+ if (attr.name === normalizedName) return attr;
19
+ attr = attr[NEXT];
20
+ }
21
+ return null;
10
22
  }
11
- getNamedItemNS(namespaceURI, name) {
23
+ getNamedItemNS(namespaceURI, localName) {
24
+ const namespace = normalizeNamespace(namespaceURI);
25
+ const normalizedLocalName = String(localName);
12
26
  let attr = this[CHILD];
13
27
  while (attr) {
14
- if (attr.name === name && attr[NS] == namespaceURI) {
28
+ if (attr.localName === normalizedLocalName && attr[NS] === namespace) {
15
29
  return attr;
16
30
  }
17
31
  attr = attr[NEXT];
@@ -37,18 +51,37 @@ class NamedNodeMap {
37
51
  return index;
38
52
  }
39
53
  removeNamedItem(name) {
40
- return this.removeNamedItemNS(null, name);
54
+ const qualifiedName = String(name);
55
+ const normalizedName = this[OWNER_ELEMENT][NS] === HTML_NAMESPACE ? asciiLowercase(qualifiedName) : qualifiedName;
56
+ return performWithCustomElementReactions(() => this.removeNamedItemImmediately(attr => attr.name === normalizedName));
57
+ }
58
+ removeNamedItemNS(namespaceURI, localName) {
59
+ const namespace = normalizeNamespace(namespaceURI);
60
+ const normalizedLocalName = String(localName);
61
+ return performWithCustomElementReactions(() => this.removeNamedItemImmediately(attr => attr.localName === normalizedLocalName && attr[NS] === namespace));
41
62
  }
42
- removeNamedItemNS(namespaceURI, name) {
63
+ removeNamedItemImmediately(matches) {
43
64
  const ownerElement = this[OWNER_ELEMENT];
44
65
  let attr = this[CHILD];
45
66
  let prev = null;
46
67
  while (attr != null) {
47
- if (attr.name === name && attr[NS] == namespaceURI) {
68
+ if (matches(attr)) {
48
69
  if (prev) prev[NEXT] = attr[NEXT];
49
70
  if (this[CHILD] === attr) this[CHILD] = attr[NEXT];
50
- updateElementAttribute(ownerElement, attr.name, attr.value, null);
51
- ownerElement[HOOKS].removeAttribute?.(ownerElement, name, namespaceURI);
71
+ const oldValue = attr.value;
72
+ attr[NEXT] = null;
73
+ attr[OWNER_ELEMENT] = null;
74
+ if (attributeObserversActive) {
75
+ queueMutationRecord({
76
+ type: 'attributes',
77
+ target: ownerElement,
78
+ attributeName: attr.name,
79
+ attributeNamespace: attr[NS],
80
+ oldValue
81
+ });
82
+ }
83
+ ownerElement[HOOKS].removeAttribute?.(ownerElement, attr.name, attr[NS]);
84
+ enqueueAttributeReaction(ownerElement, attr.localName, oldValue, null, attr[NS]);
52
85
  return attr;
53
86
  }
54
87
  prev = attr;
@@ -57,36 +90,55 @@ class NamedNodeMap {
57
90
  return null;
58
91
  }
59
92
  setNamedItem(attr) {
93
+ return performWithCustomElementReactions(() => this.setNamedItemImmediately(attr));
94
+ }
95
+ setNamedItemImmediately(attr) {
60
96
  const ownerElement = this[OWNER_ELEMENT];
97
+ const currentOwner = attr[OWNER_ELEMENT];
98
+ if (currentOwner != null && currentOwner !== ownerElement) {
99
+ throw createDOMException('The attribute is already in use by another element.', 'InUseAttributeError');
100
+ }
61
101
  let old = null;
62
102
  let child = this[CHILD];
63
- attr[OWNER_ELEMENT] = ownerElement;
64
- if (child == null) {
65
- this[CHILD] = attr;
66
- // return null;
67
- } else {
68
- let prev;
69
- while (child) {
70
- if (child.name === attr.name && child[NS] == attr[NS]) {
71
- if (prev) prev[NEXT] = attr;else this[CHILD] = attr;
72
- attr[NEXT] = child[NEXT];
73
- child[NEXT] = null;
74
- old = child;
75
- break;
76
- // return child;
77
- }
78
- prev = child;
79
- child = child[NEXT];
103
+ let prev = null;
104
+ while (child) {
105
+ if (child.localName === attr.localName && child[NS] === attr[NS]) {
106
+ if (child === attr) return child;
107
+ if (prev) prev[NEXT] = attr;else this[CHILD] = attr;
108
+ attr[NEXT] = child[NEXT];
109
+ child[NEXT] = null;
110
+ old = child;
111
+ break;
80
112
  }
113
+ prev = child;
114
+ child = child[NEXT];
115
+ }
116
+ if (old == null) {
81
117
  if (prev) prev[NEXT] = attr;else this[CHILD] = attr;
82
- // return null;
83
118
  }
84
-
85
- // only invoke the protocol if the value changed
86
- if (!old || old.value !== attr.value) {
87
- updateElementAttribute(ownerElement, attr.name, old?.value ?? null, attr.value);
119
+ attr[OWNER_ELEMENT] = ownerElement;
120
+ attr[OWNER_DOCUMENT] = ownerElement[OWNER_DOCUMENT];
121
+ if (old) old[OWNER_ELEMENT] = null;
122
+ const valueChanged = old == null || old.value !== attr.value;
123
+ const qualifiedNameChanged = old != null && old.name !== attr.name;
124
+ if (valueChanged && attributeObserversActive) {
125
+ queueMutationRecord({
126
+ type: 'attributes',
127
+ target: ownerElement,
128
+ attributeName: attr.name,
129
+ attributeNamespace: attr[NS],
130
+ oldValue: old?.value ?? null
131
+ });
132
+ }
133
+ if (qualifiedNameChanged) {
134
+ ownerElement[HOOKS].removeAttribute?.(ownerElement, old.name, old[NS]);
135
+ }
136
+ if (valueChanged || qualifiedNameChanged) {
88
137
  ownerElement[HOOKS].setAttribute?.(ownerElement, attr.name, attr.value, attr[NS]);
89
138
  }
139
+ if (valueChanged) {
140
+ enqueueAttributeReaction(ownerElement, attr.localName, old?.value ?? null, attr.value, attr[NS]);
141
+ }
90
142
  return old;
91
143
  }
92
144
  setNamedItemNS(attr) {
@@ -100,20 +152,5 @@ class NamedNodeMap {
100
152
  }
101
153
  }
102
154
  }
103
- function updateElementAttribute(element, name, oldValue, newValue) {
104
- const {
105
- observedAttributes
106
- } = element.constructor;
107
- const {
108
- attributeChangedCallback
109
- } = element;
110
- if (name === 'slot') {
111
- element.slot = newValue ?? '';
112
- }
113
- if (attributeChangedCallback == null || observedAttributes == null || !observedAttributes.includes(name)) {
114
- return;
115
- }
116
- return attributeChangedCallback.call(element, name, oldValue, newValue);
117
- }
118
155
 
119
156
  export { NamedNodeMap };