happy-dom 2.24.3 → 2.25.1
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.
Potentially problematic release.
This version of happy-dom might be problematic. Click here for more details.
- package/lib/css/CSSStyleSheet.d.ts +5 -1
- package/lib/css/CSSStyleSheet.js +21 -10
- package/lib/css/CSSStyleSheet.js.map +1 -1
- package/lib/event/EventTarget.d.ts +9 -0
- package/lib/event/EventTarget.js +11 -0
- package/lib/event/EventTarget.js.map +1 -1
- package/lib/event/NonImplementedEventTypes.js +0 -1
- package/lib/event/NonImplementedEventTypes.js.map +1 -1
- package/lib/event/events/IPointerEventInit.d.ts +13 -0
- package/lib/event/events/IPointerEventInit.js +3 -0
- package/lib/event/events/IPointerEventInit.js.map +1 -0
- package/lib/event/events/PointerEvent.d.ts +24 -0
- package/lib/event/events/PointerEvent.js +64 -0
- package/lib/event/events/PointerEvent.js.map +1 -0
- package/lib/exception/DOMExceptionNameEnum.d.ts +4 -1
- package/lib/exception/DOMExceptionNameEnum.js +3 -0
- package/lib/exception/DOMExceptionNameEnum.js.map +1 -1
- package/lib/nodes/document/Document.d.ts +8 -1
- package/lib/nodes/document/Document.js +14 -1
- package/lib/nodes/document/Document.js.map +1 -1
- package/lib/nodes/document/IDocument.d.ts +1 -0
- package/lib/nodes/document-fragment/DocumentFragment.d.ts +1 -0
- package/lib/nodes/document-fragment/DocumentFragment.js +1 -0
- package/lib/nodes/document-fragment/DocumentFragment.js.map +1 -1
- package/lib/nodes/element/Element.d.ts +7 -0
- package/lib/nodes/element/Element.js +39 -3
- package/lib/nodes/element/Element.js.map +1 -1
- package/lib/nodes/element/IElement.d.ts +7 -0
- package/lib/nodes/html-element/HTMLElement.js +16 -4
- package/lib/nodes/html-element/HTMLElement.js.map +1 -1
- package/lib/nodes/html-input-element/HTMLInputElement.d.ts +9 -6
- package/lib/nodes/html-input-element/HTMLInputElement.js +18 -8
- package/lib/nodes/html-input-element/HTMLInputElement.js.map +1 -1
- package/lib/nodes/html-input-element/IHTMLInputElement.d.ts +0 -1
- package/lib/nodes/html-link-element/HTMLLinkElement.d.ts +5 -12
- package/lib/nodes/html-link-element/HTMLLinkElement.js +39 -68
- package/lib/nodes/html-link-element/HTMLLinkElement.js.map +1 -1
- package/lib/nodes/html-script-element/HTMLScriptElement.d.ts +5 -12
- package/lib/nodes/html-script-element/HTMLScriptElement.js +21 -49
- package/lib/nodes/html-script-element/HTMLScriptElement.js.map +1 -1
- package/lib/nodes/html-style-element/HTMLStyleElement.js +1 -1
- package/lib/nodes/html-style-element/HTMLStyleElement.js.map +1 -1
- package/lib/nodes/node/INode.d.ts +1 -1
- package/lib/nodes/node/Node.d.ts +8 -13
- package/lib/nodes/node/Node.js +58 -64
- package/lib/nodes/node/Node.js.map +1 -1
- package/lib/nodes/shadow-root/ShadowRoot.d.ts +7 -0
- package/lib/nodes/shadow-root/ShadowRoot.js +16 -0
- package/lib/nodes/shadow-root/ShadowRoot.js.map +1 -1
- package/lib/query-selector/SelectorItem.d.ts +8 -0
- package/lib/query-selector/SelectorItem.js +29 -11
- package/lib/query-selector/SelectorItem.js.map +1 -1
- package/lib/window/Window.d.ts +2 -0
- package/lib/window/Window.js +2 -0
- package/lib/window/Window.js.map +1 -1
- package/package.json +2 -2
- package/src/css/CSSStyleSheet.ts +33 -4
- package/src/event/EventTarget.ts +12 -0
- package/src/event/NonImplementedEventTypes.ts +0 -1
- package/src/event/events/IPointerEventInit.ts +14 -0
- package/src/event/events/PointerEvent.ts +42 -0
- package/src/exception/DOMExceptionNameEnum.ts +4 -1
- package/src/nodes/document/Document.ts +11 -1
- package/src/nodes/document/IDocument.ts +1 -0
- package/src/nodes/document-fragment/DocumentFragment.ts +1 -0
- package/src/nodes/element/Element.ts +42 -3
- package/src/nodes/element/IElement.ts +8 -0
- package/src/nodes/html-element/HTMLElement.ts +21 -4
- package/src/nodes/html-input-element/HTMLInputElement.ts +21 -9
- package/src/nodes/html-input-element/IHTMLInputElement.ts +0 -1
- package/src/nodes/html-link-element/HTMLLinkElement.ts +46 -73
- package/src/nodes/html-script-element/HTMLScriptElement.ts +24 -49
- package/src/nodes/html-style-element/HTMLStyleElement.ts +1 -1
- package/src/nodes/node/INode.ts +1 -1
- package/src/nodes/node/Node.ts +61 -63
- package/src/nodes/shadow-root/ShadowRoot.ts +14 -0
- package/src/query-selector/SelectorItem.ts +38 -19
- package/src/window/Window.ts +2 -0
package/src/nodes/node/Node.ts
CHANGED
@@ -9,7 +9,6 @@ import IDocument from '../document/IDocument';
|
|
9
9
|
import IElement from '../element/IElement';
|
10
10
|
import INodeList from './INodeList';
|
11
11
|
import NodeListFactory from './NodeListFactory';
|
12
|
-
import { IShadowRoot } from '../..';
|
13
12
|
|
14
13
|
/**
|
15
14
|
* Node.
|
@@ -27,9 +26,8 @@ export default class Node extends EventTarget implements INode {
|
|
27
26
|
public readonly parentNode: INode = null;
|
28
27
|
public readonly nodeType: number;
|
29
28
|
public readonly childNodes: INodeList<INode> = NodeListFactory.create();
|
30
|
-
|
31
|
-
|
32
|
-
protected _isConnected = false;
|
29
|
+
public readonly isConnected: boolean = false;
|
30
|
+
public _rootNode: INode = null;
|
33
31
|
|
34
32
|
// Custom Properties (not part of HTML standard)
|
35
33
|
protected _observers: MutationObserverListener[] = [];
|
@@ -42,42 +40,6 @@ export default class Node extends EventTarget implements INode {
|
|
42
40
|
this.ownerDocument = (<typeof Node>this.constructor).ownerDocument;
|
43
41
|
}
|
44
42
|
|
45
|
-
/**
|
46
|
-
* Returns "true" if connected to DOM.
|
47
|
-
*
|
48
|
-
* @returns "true" if connected.
|
49
|
-
*/
|
50
|
-
public get isConnected(): boolean {
|
51
|
-
return this._isConnected;
|
52
|
-
}
|
53
|
-
|
54
|
-
/**
|
55
|
-
* Sets the connected state.
|
56
|
-
*
|
57
|
-
* @param isConnected "true" if connected.
|
58
|
-
*/
|
59
|
-
public set isConnected(isConnected) {
|
60
|
-
if (this._isConnected !== isConnected) {
|
61
|
-
this._isConnected = isConnected;
|
62
|
-
|
63
|
-
if (isConnected && this.connectedCallback) {
|
64
|
-
this.connectedCallback();
|
65
|
-
} else if (!isConnected && this.disconnectedCallback) {
|
66
|
-
this.disconnectedCallback();
|
67
|
-
}
|
68
|
-
|
69
|
-
for (const child of this.childNodes) {
|
70
|
-
child.isConnected = isConnected;
|
71
|
-
}
|
72
|
-
|
73
|
-
// eslint-disable-next-line
|
74
|
-
if ((<any>this).shadowRoot) {
|
75
|
-
// eslint-disable-next-line
|
76
|
-
(<any>this).shadowRoot.isConnected = isConnected;
|
77
|
-
}
|
78
|
-
}
|
79
|
-
}
|
80
|
-
|
81
43
|
/**
|
82
44
|
* Get text value of children.
|
83
45
|
*
|
@@ -176,7 +138,7 @@ export default class Node extends EventTarget implements INode {
|
|
176
138
|
public get parentElement(): IElement {
|
177
139
|
let parent = this.parentNode;
|
178
140
|
while (parent && parent.nodeType !== Node.ELEMENT_NODE) {
|
179
|
-
parent =
|
141
|
+
parent = parent.parentNode;
|
180
142
|
}
|
181
143
|
return <IElement>parent;
|
182
144
|
}
|
@@ -208,21 +170,15 @@ export default class Node extends EventTarget implements INode {
|
|
208
170
|
* @returns Node.
|
209
171
|
*/
|
210
172
|
public getRootNode(options?: { composed: boolean }): INode {
|
211
|
-
|
212
|
-
|
173
|
+
if (!this.isConnected) {
|
174
|
+
return this;
|
175
|
+
}
|
213
176
|
|
214
|
-
|
215
|
-
|
216
|
-
if (!options?.composed || !(<IShadowRoot>parent).host) {
|
217
|
-
return parent;
|
218
|
-
}
|
219
|
-
parent = (<IShadowRoot>parent).host;
|
220
|
-
} else {
|
221
|
-
parent = parent.parentNode;
|
222
|
-
}
|
177
|
+
if (this._rootNode && !options?.composed) {
|
178
|
+
return this._rootNode;
|
223
179
|
}
|
224
180
|
|
225
|
-
return
|
181
|
+
return this.ownerDocument;
|
226
182
|
}
|
227
183
|
|
228
184
|
/**
|
@@ -234,8 +190,11 @@ export default class Node extends EventTarget implements INode {
|
|
234
190
|
public cloneNode(deep = false): INode {
|
235
191
|
const clone = new (<typeof Node>this.constructor)();
|
236
192
|
|
237
|
-
|
238
|
-
|
193
|
+
// Document has childNodes directly when it is created
|
194
|
+
if (clone.childNodes.length) {
|
195
|
+
for (const node of clone.childNodes.slice()) {
|
196
|
+
node.parentNode.removeChild(node);
|
197
|
+
}
|
239
198
|
}
|
240
199
|
|
241
200
|
if (deep) {
|
@@ -281,8 +240,7 @@ export default class Node extends EventTarget implements INode {
|
|
281
240
|
|
282
241
|
this.childNodes.push(node);
|
283
242
|
|
284
|
-
(<Node>node.
|
285
|
-
node.isConnected = this.isConnected;
|
243
|
+
(<Node>node)._connectToNode(this);
|
286
244
|
|
287
245
|
// MutationObserver
|
288
246
|
if (this._observers.length > 0) {
|
@@ -318,8 +276,7 @@ export default class Node extends EventTarget implements INode {
|
|
318
276
|
|
319
277
|
this.childNodes.splice(index, 1);
|
320
278
|
|
321
|
-
(<Node>node.
|
322
|
-
node.isConnected = false;
|
279
|
+
(<Node>node)._connectToNode(null);
|
323
280
|
|
324
281
|
// MutationObserver
|
325
282
|
if (this._observers.length > 0) {
|
@@ -384,8 +341,7 @@ export default class Node extends EventTarget implements INode {
|
|
384
341
|
|
385
342
|
this.childNodes.splice(index, 0, newNode);
|
386
343
|
|
387
|
-
(<Node>newNode.
|
388
|
-
newNode.isConnected = this.isConnected;
|
344
|
+
(<Node>newNode)._connectToNode(this);
|
389
345
|
|
390
346
|
// MutationObserver
|
391
347
|
if (this._observers.length > 0) {
|
@@ -432,8 +388,16 @@ export default class Node extends EventTarget implements INode {
|
|
432
388
|
|
433
389
|
const returnValue = super.dispatchEvent(event);
|
434
390
|
|
435
|
-
if (event.bubbles &&
|
436
|
-
|
391
|
+
if (event.bubbles && !event._propagationStopped) {
|
392
|
+
if (this.parentNode) {
|
393
|
+
return this.parentNode.dispatchEvent(event);
|
394
|
+
}
|
395
|
+
|
396
|
+
// eslint-disable-next-line
|
397
|
+
if(event.composed && (<any>this).host) {
|
398
|
+
// eslint-disable-next-line
|
399
|
+
return (<any>this).host.dispatchEvent(event);
|
400
|
+
}
|
437
401
|
}
|
438
402
|
|
439
403
|
return returnValue;
|
@@ -480,4 +444,38 @@ export default class Node extends EventTarget implements INode {
|
|
480
444
|
}
|
481
445
|
}
|
482
446
|
}
|
447
|
+
|
448
|
+
/**
|
449
|
+
* Connects this element to another element.
|
450
|
+
*
|
451
|
+
* @param parentNode Parent node.
|
452
|
+
*/
|
453
|
+
public _connectToNode(parentNode: INode = null): void {
|
454
|
+
const isConnected = !!parentNode && parentNode.isConnected;
|
455
|
+
|
456
|
+
if (this.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
|
457
|
+
(<INode>this.parentNode) = parentNode;
|
458
|
+
(<Node>this)._rootNode = isConnected && parentNode ? (<Node>parentNode)._rootNode : null;
|
459
|
+
}
|
460
|
+
|
461
|
+
if (this.isConnected !== isConnected) {
|
462
|
+
(<boolean>this.isConnected) = isConnected;
|
463
|
+
|
464
|
+
if (isConnected && this.connectedCallback) {
|
465
|
+
this.connectedCallback();
|
466
|
+
} else if (!isConnected && this.disconnectedCallback) {
|
467
|
+
this.disconnectedCallback();
|
468
|
+
}
|
469
|
+
|
470
|
+
for (const child of this.childNodes) {
|
471
|
+
(<Node>child)._connectToNode(this);
|
472
|
+
}
|
473
|
+
|
474
|
+
// eslint-disable-next-line
|
475
|
+
if ((<any>this).shadowRoot) {
|
476
|
+
// eslint-disable-next-line
|
477
|
+
(<any>this).shadowRoot._connectToNode(this);
|
478
|
+
}
|
479
|
+
}
|
480
|
+
}
|
483
481
|
}
|
@@ -4,6 +4,7 @@ import XMLSerializer from '../../xml-serializer/XMLSerializer';
|
|
4
4
|
import IElement from '../element/IElement';
|
5
5
|
import CSSStyleSheet from '../../css/CSSStyleSheet';
|
6
6
|
import IShadowRoot from './IShadowRoot';
|
7
|
+
import IHTMLElement from '../../nodes/html-element/IHTMLElement';
|
7
8
|
|
8
9
|
/**
|
9
10
|
* ShadowRoot.
|
@@ -42,6 +43,19 @@ export default class ShadowRoot extends DocumentFragment implements IShadowRoot
|
|
42
43
|
}
|
43
44
|
}
|
44
45
|
|
46
|
+
/**
|
47
|
+
* Returns active element.
|
48
|
+
*
|
49
|
+
* @returns Active element.
|
50
|
+
*/
|
51
|
+
public get activeElement(): IHTMLElement {
|
52
|
+
const activeElement: IHTMLElement = this.ownerDocument['_activeElement'];
|
53
|
+
if (activeElement && activeElement.getRootNode() === this) {
|
54
|
+
return activeElement;
|
55
|
+
}
|
56
|
+
return null;
|
57
|
+
}
|
58
|
+
|
45
59
|
/**
|
46
60
|
* Converts to string.
|
47
61
|
*
|
@@ -3,7 +3,7 @@ import Element from '../nodes/element/Element';
|
|
3
3
|
|
4
4
|
const ATTRIBUTE_REGEXP = /\[([a-zA-Z0-9-_]+)\]|\[([a-zA-Z0-9-_]+)([~|^$*]{0,1})[ ]*=[ ]*["']{0,1}([^"']+)["']{0,1}\]/g;
|
5
5
|
const ATTRIBUTE_NAME_REGEXP = /[^a-zA-Z0-9-_$]/;
|
6
|
-
const PSUEDO_REGEXP = /:([a-zA-Z-]+)\(([0-9n+-]+|odd|even)\)|:([a-zA-Z-]+)/g;
|
6
|
+
const PSUEDO_REGEXP = /:([a-zA-Z-]+)\(([0-9n+-]+|odd|even)\)|:not\(([^)]+)\)|:([a-zA-Z-]+)/g;
|
7
7
|
const CLASS_REGEXP = /\.([a-zA-Z0-9-_$]+)/g;
|
8
8
|
const TAG_NAME_REGEXP = /^[a-zA-Z0-9-]+/;
|
9
9
|
|
@@ -29,7 +29,8 @@ export default class SelectorItem {
|
|
29
29
|
constructor(selector: string) {
|
30
30
|
this.isAll = selector === '*';
|
31
31
|
this.isID = !this.isAll ? selector.startsWith('#') : false;
|
32
|
-
this.isAttribute =
|
32
|
+
this.isAttribute =
|
33
|
+
!this.isAll && !this.isID && selector.includes('[') && !selector.includes(':not(');
|
33
34
|
this.isPseudo = !this.isAll && !this.isID && selector.includes(':');
|
34
35
|
this.isClass = !this.isAll && !this.isID && new RegExp(CLASS_REGEXP, 'g').test(selector);
|
35
36
|
this.tagName = !this.isAll && !this.isID ? selector.match(TAG_NAME_REGEXP) : null;
|
@@ -84,24 +85,17 @@ export default class SelectorItem {
|
|
84
85
|
while ((match = regexp.exec(selector))) {
|
85
86
|
if (match[1] && !this.matchesNthChild(element, match[1], match[2])) {
|
86
87
|
return false;
|
87
|
-
} else if (match[3] &&
|
88
|
+
} else if (match[3] && this.matchesAttribute(element, match[3])) {
|
89
|
+
return false;
|
90
|
+
} else if (match[4] && !this.matchesPsuedo(element, match[4])) {
|
88
91
|
return false;
|
89
92
|
}
|
90
93
|
}
|
91
94
|
}
|
92
95
|
|
93
96
|
// Attribute match
|
94
|
-
if (this.isAttribute) {
|
95
|
-
|
96
|
-
|
97
|
-
while ((match = regexp.exec(selector))) {
|
98
|
-
if (
|
99
|
-
(match[1] && !this.matchesAttributeName(element, match[1])) ||
|
100
|
-
(match[2] && !this.matchesAttributeNameAndValue(element, match[2], match[4], match[3]))
|
101
|
-
) {
|
102
|
-
return false;
|
103
|
-
}
|
104
|
-
}
|
97
|
+
if (this.isAttribute && !this.matchesAttribute(element, selector)) {
|
98
|
+
return false;
|
105
99
|
}
|
106
100
|
|
107
101
|
return true;
|
@@ -217,6 +211,31 @@ export default class SelectorItem {
|
|
217
211
|
return false;
|
218
212
|
}
|
219
213
|
|
214
|
+
/**
|
215
|
+
* Matches attribute.
|
216
|
+
*
|
217
|
+
* @param element Element.
|
218
|
+
* @param selector Selector.
|
219
|
+
* @returns True if it is a match.
|
220
|
+
*/
|
221
|
+
private matchesAttribute(element: Element, selector: string): boolean {
|
222
|
+
const regexp = new RegExp(ATTRIBUTE_REGEXP, 'g');
|
223
|
+
let match;
|
224
|
+
|
225
|
+
while ((match = regexp.exec(selector))) {
|
226
|
+
const isPsuedo = match.index > 0 && selector[match.index] === '(';
|
227
|
+
if (
|
228
|
+
!isPsuedo &&
|
229
|
+
((match[1] && !this.matchesAttributeName(element, match[1])) ||
|
230
|
+
(match[2] && !this.matchesAttributeNameAndValue(element, match[2], match[4], match[3])))
|
231
|
+
) {
|
232
|
+
return false;
|
233
|
+
}
|
234
|
+
}
|
235
|
+
|
236
|
+
return true;
|
237
|
+
}
|
238
|
+
|
220
239
|
/**
|
221
240
|
* Matches attribute name only.
|
222
241
|
*
|
@@ -224,7 +243,7 @@ export default class SelectorItem {
|
|
224
243
|
* @param attributeName Attribute name.
|
225
244
|
* @returns True if it is a match.
|
226
245
|
*/
|
227
|
-
private matchesAttributeName(element, attributeName): boolean {
|
246
|
+
private matchesAttributeName(element: Element, attributeName: string): boolean {
|
228
247
|
if (ATTRIBUTE_NAME_REGEXP.test(attributeName)) {
|
229
248
|
throw new DOMException(`The selector "${this.selector}" is not valid.`);
|
230
249
|
}
|
@@ -243,10 +262,10 @@ export default class SelectorItem {
|
|
243
262
|
* @returns True if it is a match.
|
244
263
|
*/
|
245
264
|
private matchesAttributeNameAndValue(
|
246
|
-
element,
|
247
|
-
attributeName,
|
248
|
-
attributeValue,
|
249
|
-
matchType = null
|
265
|
+
element: Element,
|
266
|
+
attributeName: string,
|
267
|
+
attributeValue: string,
|
268
|
+
matchType: string = null
|
250
269
|
): boolean {
|
251
270
|
const attribute = element._attributes[attributeName.toLowerCase()];
|
252
271
|
const value = attributeValue;
|
package/src/window/Window.ts
CHANGED
@@ -42,6 +42,7 @@ import FileReader from '../file/FileReader';
|
|
42
42
|
import History from '../history/History';
|
43
43
|
import CSSStyleDeclaration from '../css/CSSStyleDeclaration';
|
44
44
|
import MouseEvent from '../event/events/MouseEvent';
|
45
|
+
import PointerEvent from '../event/events/PointerEvent';
|
45
46
|
import FocusEvent from '../event/events/FocusEvent';
|
46
47
|
import WheelEvent from '../event/events/WheelEvent';
|
47
48
|
import DataTransfer from '../event/DataTransfer';
|
@@ -111,6 +112,7 @@ export default class Window extends EventTarget implements IWindow, NodeJS.Globa
|
|
111
112
|
public readonly AnimationEvent = AnimationEvent;
|
112
113
|
public readonly KeyboardEvent = KeyboardEvent;
|
113
114
|
public readonly MouseEvent = MouseEvent;
|
115
|
+
public readonly PointerEvent = PointerEvent;
|
114
116
|
public readonly FocusEvent = FocusEvent;
|
115
117
|
public readonly WheelEvent = WheelEvent;
|
116
118
|
public readonly InputEvent = InputEvent;
|