happy-dom 2.24.5 → 2.25.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.
Potentially problematic release.
This version of happy-dom might be problematic. Click here for more details.
- 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/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 +38 -2
- 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 +57 -63
- 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/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/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 +41 -2
- 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 +60 -62
- package/src/nodes/shadow-root/ShadowRoot.ts +14 -0
- package/src/query-selector/SelectorItem.ts +38 -19
- package/src/window/Window.ts +2 -0
@@ -13,6 +13,7 @@ import HTMLCollectionFactory from '../element/HTMLCollectionFactory';
|
|
13
13
|
export default class DocumentFragment extends Node implements IDocumentFragment {
|
14
14
|
public nodeType = Node.DOCUMENT_FRAGMENT_NODE;
|
15
15
|
public readonly children: IHTMLCollection<IElement> = HTMLCollectionFactory.create();
|
16
|
+
public _rootNode: INode = this;
|
16
17
|
|
17
18
|
/**
|
18
19
|
* Last element child.
|
@@ -598,7 +598,7 @@ export default class Element extends Node implements IElement {
|
|
598
598
|
(<IDocument>this.shadowRoot.ownerDocument) = this.ownerDocument;
|
599
599
|
(<Element>this.shadowRoot.host) = this;
|
600
600
|
(<string>this.shadowRoot.mode) = shadowRootInit.mode;
|
601
|
-
this.shadowRoot.
|
601
|
+
(<ShadowRoot>this.shadowRoot)._connectToNode(this);
|
602
602
|
return this.shadowRoot;
|
603
603
|
}
|
604
604
|
|
@@ -636,7 +636,46 @@ export default class Element extends Node implements IElement {
|
|
636
636
|
* @returns "true" if matching.
|
637
637
|
*/
|
638
638
|
public matches(selector: string): boolean {
|
639
|
-
|
639
|
+
for (const part of selector.split(',')) {
|
640
|
+
if (new SelectorItem(part.trim()).match(this)) {
|
641
|
+
return true;
|
642
|
+
}
|
643
|
+
}
|
644
|
+
return false;
|
645
|
+
}
|
646
|
+
|
647
|
+
/**
|
648
|
+
* Traverses the Element and its parents (heading toward the document root) until it finds a node that matches the provided selector string.
|
649
|
+
*
|
650
|
+
* @param selector Selector.
|
651
|
+
* @returns Closest matching element.
|
652
|
+
*/
|
653
|
+
public closest(selector: string): IElement {
|
654
|
+
let rootElement: IElement = this.ownerDocument.documentElement;
|
655
|
+
if (!this.isConnected) {
|
656
|
+
rootElement = this;
|
657
|
+
while (rootElement.parentNode) {
|
658
|
+
rootElement = <IElement>rootElement.parentNode;
|
659
|
+
}
|
660
|
+
}
|
661
|
+
const elements = rootElement.querySelectorAll(selector);
|
662
|
+
|
663
|
+
// eslint-disable-next-line
|
664
|
+
let parent: IElement = this;
|
665
|
+
while (parent) {
|
666
|
+
if (elements.includes(parent)) {
|
667
|
+
return parent;
|
668
|
+
}
|
669
|
+
parent = parent.parentElement;
|
670
|
+
}
|
671
|
+
|
672
|
+
// QuerySelectorAll() will not match the element it is looking in when searched for
|
673
|
+
// Therefore we need to check if it matches the root
|
674
|
+
if (rootElement.matches(selector)) {
|
675
|
+
return rootElement;
|
676
|
+
}
|
677
|
+
|
678
|
+
return null;
|
640
679
|
}
|
641
680
|
|
642
681
|
/**
|
@@ -152,6 +152,14 @@ export default interface IElement extends IChildNode, INonDocumentTypeChildNode,
|
|
152
152
|
*/
|
153
153
|
matches(selector: string): boolean;
|
154
154
|
|
155
|
+
/**
|
156
|
+
* Traverses the Element and its parents (heading toward the document root) until it finds a node that matches the provided selector string.
|
157
|
+
*
|
158
|
+
* @param selector Selector.
|
159
|
+
* @returns Closest matching element.
|
160
|
+
*/
|
161
|
+
closest(selector: string): IElement;
|
162
|
+
|
155
163
|
/**
|
156
164
|
* The setAttributeNode() method adds a new Attr node to the specified element.
|
157
165
|
*
|
@@ -1,8 +1,9 @@
|
|
1
1
|
import Element from '../element/Element';
|
2
|
-
import Event from '../../event/Event';
|
3
2
|
import IHTMLElement from './IHTMLElement';
|
4
3
|
import CSSStyleDeclaration from '../../css/CSSStyleDeclaration';
|
5
4
|
import Attr from '../../attribute/Attr';
|
5
|
+
import FocusEvent from '../../event/events/FocusEvent';
|
6
|
+
import PointerEvent from '../../event/events/PointerEvent';
|
6
7
|
|
7
8
|
/**
|
8
9
|
* HTML Element.
|
@@ -172,7 +173,7 @@ export default class HTMLElement extends Element implements IHTMLElement {
|
|
172
173
|
* Triggers a click event.
|
173
174
|
*/
|
174
175
|
public click(): void {
|
175
|
-
const event = new
|
176
|
+
const event = new PointerEvent('click', {
|
176
177
|
bubbles: true,
|
177
178
|
composed: true
|
178
179
|
});
|
@@ -185,8 +186,14 @@ export default class HTMLElement extends Element implements IHTMLElement {
|
|
185
186
|
* Triggers a blur event.
|
186
187
|
*/
|
187
188
|
public blur(): void {
|
189
|
+
if (this.ownerDocument['_activeElement'] !== this || !this.isConnected) {
|
190
|
+
return;
|
191
|
+
}
|
192
|
+
|
193
|
+
this.ownerDocument['_activeElement'] = null;
|
194
|
+
|
188
195
|
for (const eventType of ['blur', 'focusout']) {
|
189
|
-
const event = new
|
196
|
+
const event = new FocusEvent(eventType, {
|
190
197
|
bubbles: true,
|
191
198
|
composed: true
|
192
199
|
});
|
@@ -200,8 +207,18 @@ export default class HTMLElement extends Element implements IHTMLElement {
|
|
200
207
|
* Triggers a focus event.
|
201
208
|
*/
|
202
209
|
public focus(): void {
|
210
|
+
if (this.ownerDocument['_activeElement'] === this || !this.isConnected) {
|
211
|
+
return;
|
212
|
+
}
|
213
|
+
|
214
|
+
if (this.ownerDocument['_activeElement'] !== null) {
|
215
|
+
this.ownerDocument['_activeElement'].blur();
|
216
|
+
}
|
217
|
+
|
218
|
+
this.ownerDocument['_activeElement'] = this;
|
219
|
+
|
203
220
|
for (const eventType of ['focus', 'focusin']) {
|
204
|
-
const event = new
|
221
|
+
const event = new FocusEvent(eventType, {
|
205
222
|
bubbles: true,
|
206
223
|
composed: true
|
207
224
|
});
|
@@ -37,9 +37,6 @@ export default class HTMLInputElement extends HTMLElement implements IHTMLInputE
|
|
37
37
|
// Type specific: file
|
38
38
|
public files: File[] = [];
|
39
39
|
|
40
|
-
// Not categorized
|
41
|
-
public defaultValue = '';
|
42
|
-
|
43
40
|
// Type specific: text/password/search/tel/url/week/month
|
44
41
|
private _selectionStart = null;
|
45
42
|
private _selectionEnd = null;
|
@@ -384,21 +381,21 @@ export default class HTMLInputElement extends HTMLElement implements IHTMLInputE
|
|
384
381
|
}
|
385
382
|
|
386
383
|
/**
|
387
|
-
* Returns
|
384
|
+
* Returns defaultValue.
|
388
385
|
*
|
389
386
|
* @returns Defaultvalue.
|
390
387
|
*/
|
391
|
-
public get
|
388
|
+
public get defaultValue(): string {
|
392
389
|
return this.getAttributeNS(null, 'defaultvalue') || '';
|
393
390
|
}
|
394
391
|
|
395
392
|
/**
|
396
|
-
* Sets
|
393
|
+
* Sets defaultValue.
|
397
394
|
*
|
398
|
-
* @param
|
395
|
+
* @param defaultValue Defaultvalue.
|
399
396
|
*/
|
400
|
-
public set
|
401
|
-
this.setAttributeNS(null, 'defaultvalue',
|
397
|
+
public set defaultValue(defaultValue: string) {
|
398
|
+
this.setAttributeNS(null, 'defaultvalue', defaultValue);
|
402
399
|
}
|
403
400
|
|
404
401
|
/**
|
@@ -780,6 +777,21 @@ export default class HTMLInputElement extends HTMLElement implements IHTMLInputE
|
|
780
777
|
return this.value ? parseFloat(this.value) : NaN;
|
781
778
|
}
|
782
779
|
|
780
|
+
/**
|
781
|
+
* Selects the text.
|
782
|
+
*/
|
783
|
+
public select(): void {
|
784
|
+
if (!this._isSelectionSupported()) {
|
785
|
+
return null;
|
786
|
+
}
|
787
|
+
|
788
|
+
this._selectionStart = 0;
|
789
|
+
this._selectionEnd = this.value.length;
|
790
|
+
this._selectionDirection = HTMLInputElementSelectionDirectionEnum.none;
|
791
|
+
|
792
|
+
this.dispatchEvent(new Event('select', { bubbles: true, cancelable: true }));
|
793
|
+
}
|
794
|
+
|
783
795
|
/**
|
784
796
|
* Set selection range.
|
785
797
|
*
|
@@ -6,6 +6,7 @@ import Document from '../document/Document';
|
|
6
6
|
import IHTMLLinkElement from './IHTMLLinkElement';
|
7
7
|
import Event from '../../event/Event';
|
8
8
|
import ErrorEvent from '../../event/events/ErrorEvent';
|
9
|
+
import INode from '../../nodes/node/INode';
|
9
10
|
|
10
11
|
/**
|
11
12
|
* HTML Link Element.
|
@@ -19,79 +20,6 @@ export default class HTMLLinkElement extends HTMLElement implements IHTMLLinkEle
|
|
19
20
|
public readonly sheet: CSSStyleSheet = null;
|
20
21
|
public _evaluateCSS = true;
|
21
22
|
|
22
|
-
/**
|
23
|
-
* Returns "true" if connected to DOM.
|
24
|
-
*
|
25
|
-
* @returns "true" if connected.
|
26
|
-
*/
|
27
|
-
public get isConnected(): boolean {
|
28
|
-
return this._isConnected;
|
29
|
-
}
|
30
|
-
|
31
|
-
/**
|
32
|
-
* Sets the connected state.
|
33
|
-
*
|
34
|
-
* @param isConnected "true" if connected.
|
35
|
-
*/
|
36
|
-
public set isConnected(isConnected) {
|
37
|
-
if (this._isConnected !== isConnected) {
|
38
|
-
this._isConnected = isConnected;
|
39
|
-
|
40
|
-
for (const child of this.childNodes) {
|
41
|
-
child.isConnected = isConnected;
|
42
|
-
}
|
43
|
-
|
44
|
-
// eslint-disable-next-line
|
45
|
-
if (this.shadowRoot) {
|
46
|
-
// eslint-disable-next-line
|
47
|
-
this.shadowRoot.isConnected = isConnected;
|
48
|
-
}
|
49
|
-
|
50
|
-
if (isConnected && this._evaluateCSS) {
|
51
|
-
const href = this.getAttributeNS(null, 'href');
|
52
|
-
const rel = this.getAttributeNS(null, 'rel');
|
53
|
-
if (href !== null && rel && rel.toLowerCase() === 'stylesheet') {
|
54
|
-
(<Document>this.ownerDocument)._readyStateManager.startTask();
|
55
|
-
ResourceFetcher.fetch({ window: this.ownerDocument.defaultView, url: href })
|
56
|
-
.then(code => {
|
57
|
-
const styleSheet = new CSSStyleSheet();
|
58
|
-
styleSheet.replaceSync(code);
|
59
|
-
(<CSSStyleSheet>this.sheet) = styleSheet;
|
60
|
-
this.dispatchEvent(new Event('load'));
|
61
|
-
(<Document>this.ownerDocument)._readyStateManager.endTask();
|
62
|
-
})
|
63
|
-
.catch(error => {
|
64
|
-
this.dispatchEvent(
|
65
|
-
new ErrorEvent('error', {
|
66
|
-
message: error.message,
|
67
|
-
error
|
68
|
-
})
|
69
|
-
);
|
70
|
-
this.ownerDocument.defaultView.dispatchEvent(
|
71
|
-
new ErrorEvent('error', {
|
72
|
-
message: error.message,
|
73
|
-
error
|
74
|
-
})
|
75
|
-
);
|
76
|
-
(<Document>this.ownerDocument)._readyStateManager.endTask();
|
77
|
-
if (
|
78
|
-
!this._listeners['error'] &&
|
79
|
-
!this.ownerDocument.defaultView._listeners['error']
|
80
|
-
) {
|
81
|
-
this.ownerDocument.defaultView.console.error(error);
|
82
|
-
}
|
83
|
-
});
|
84
|
-
}
|
85
|
-
}
|
86
|
-
|
87
|
-
if (isConnected && this.connectedCallback) {
|
88
|
-
this.connectedCallback();
|
89
|
-
} else if (!isConnected && this.disconnectedCallback) {
|
90
|
-
this.disconnectedCallback();
|
91
|
-
}
|
92
|
-
}
|
93
|
-
}
|
94
|
-
|
95
23
|
/**
|
96
24
|
* Returns as.
|
97
25
|
*
|
@@ -286,4 +214,49 @@ export default class HTMLLinkElement extends HTMLElement implements IHTMLLinkEle
|
|
286
214
|
|
287
215
|
return replacedAttribute;
|
288
216
|
}
|
217
|
+
|
218
|
+
/**
|
219
|
+
* @override
|
220
|
+
*/
|
221
|
+
public _connectToNode(parentNode: INode = null): void {
|
222
|
+
const isConnected = this.isConnected;
|
223
|
+
const isParentConnected = parentNode ? parentNode.isConnected : false;
|
224
|
+
|
225
|
+
super._connectToNode(parentNode);
|
226
|
+
|
227
|
+
if (isConnected !== isParentConnected && this._evaluateCSS) {
|
228
|
+
const href = this.getAttributeNS(null, 'href');
|
229
|
+
const rel = this.getAttributeNS(null, 'rel');
|
230
|
+
|
231
|
+
if (href !== null && rel && rel.toLowerCase() === 'stylesheet') {
|
232
|
+
(<Document>this.ownerDocument)._readyStateManager.startTask();
|
233
|
+
ResourceFetcher.fetch({ window: this.ownerDocument.defaultView, url: href })
|
234
|
+
.then(code => {
|
235
|
+
const styleSheet = new CSSStyleSheet();
|
236
|
+
styleSheet.replaceSync(code);
|
237
|
+
(<CSSStyleSheet>this.sheet) = styleSheet;
|
238
|
+
this.dispatchEvent(new Event('load'));
|
239
|
+
(<Document>this.ownerDocument)._readyStateManager.endTask();
|
240
|
+
})
|
241
|
+
.catch(error => {
|
242
|
+
this.dispatchEvent(
|
243
|
+
new ErrorEvent('error', {
|
244
|
+
message: error.message,
|
245
|
+
error
|
246
|
+
})
|
247
|
+
);
|
248
|
+
this.ownerDocument.defaultView.dispatchEvent(
|
249
|
+
new ErrorEvent('error', {
|
250
|
+
message: error.message,
|
251
|
+
error
|
252
|
+
})
|
253
|
+
);
|
254
|
+
(<Document>this.ownerDocument)._readyStateManager.endTask();
|
255
|
+
if (!this._listeners['error'] && !this.ownerDocument.defaultView._listeners['error']) {
|
256
|
+
this.ownerDocument.defaultView.console.error(error);
|
257
|
+
}
|
258
|
+
});
|
259
|
+
}
|
260
|
+
}
|
261
|
+
}
|
289
262
|
}
|
@@ -4,6 +4,7 @@ import IHTMLScriptElement from './IHTMLScriptElement';
|
|
4
4
|
import ScriptUtility from './ScriptUtility';
|
5
5
|
import Event from '../../event/Event';
|
6
6
|
import ErrorEvent from '../../event/events/ErrorEvent';
|
7
|
+
import INode from '../../nodes/node/INode';
|
7
8
|
|
8
9
|
/**
|
9
10
|
* HTML Script Element.
|
@@ -16,55 +17,6 @@ export default class HTMLScriptElement extends HTMLElement implements IHTMLScrip
|
|
16
17
|
public onload: (event: Event) => void = null;
|
17
18
|
public _evaluateScript = true;
|
18
19
|
|
19
|
-
/**
|
20
|
-
* Returns "true" if connected to DOM.
|
21
|
-
*
|
22
|
-
* @returns "true" if connected.
|
23
|
-
*/
|
24
|
-
public get isConnected(): boolean {
|
25
|
-
return this._isConnected;
|
26
|
-
}
|
27
|
-
|
28
|
-
/**
|
29
|
-
* Sets the connected state.
|
30
|
-
*
|
31
|
-
* @param isConnected "true" if connected.
|
32
|
-
*/
|
33
|
-
public set isConnected(isConnected) {
|
34
|
-
if (this._isConnected !== isConnected) {
|
35
|
-
this._isConnected = isConnected;
|
36
|
-
|
37
|
-
for (const child of this.childNodes) {
|
38
|
-
child.isConnected = isConnected;
|
39
|
-
}
|
40
|
-
|
41
|
-
// eslint-disable-next-line
|
42
|
-
if (this.shadowRoot) {
|
43
|
-
// eslint-disable-next-line
|
44
|
-
this.shadowRoot.isConnected = isConnected;
|
45
|
-
}
|
46
|
-
|
47
|
-
if (isConnected && this._evaluateScript) {
|
48
|
-
const src = this.getAttributeNS(null, 'src');
|
49
|
-
|
50
|
-
if (src !== null) {
|
51
|
-
ScriptUtility.loadExternalScript(this);
|
52
|
-
} else {
|
53
|
-
const textContent = this.textContent;
|
54
|
-
if (textContent) {
|
55
|
-
this.ownerDocument.defaultView.eval(textContent);
|
56
|
-
}
|
57
|
-
}
|
58
|
-
}
|
59
|
-
|
60
|
-
if (isConnected && this.connectedCallback) {
|
61
|
-
this.connectedCallback();
|
62
|
-
} else if (!isConnected && this.disconnectedCallback) {
|
63
|
-
this.disconnectedCallback();
|
64
|
-
}
|
65
|
-
}
|
66
|
-
}
|
67
|
-
|
68
20
|
/**
|
69
21
|
* Returns type.
|
70
22
|
*
|
@@ -226,4 +178,27 @@ export default class HTMLScriptElement extends HTMLElement implements IHTMLScrip
|
|
226
178
|
public cloneNode(deep = false): IHTMLScriptElement {
|
227
179
|
return <IHTMLScriptElement>super.cloneNode(deep);
|
228
180
|
}
|
181
|
+
|
182
|
+
/**
|
183
|
+
* @override
|
184
|
+
*/
|
185
|
+
public _connectToNode(parentNode: INode = null): void {
|
186
|
+
const isConnected = this.isConnected;
|
187
|
+
const isParentConnected = parentNode ? parentNode.isConnected : false;
|
188
|
+
|
189
|
+
super._connectToNode(parentNode);
|
190
|
+
|
191
|
+
if (isConnected !== isParentConnected && this._evaluateScript) {
|
192
|
+
const src = this.getAttributeNS(null, 'src');
|
193
|
+
|
194
|
+
if (src !== null) {
|
195
|
+
ScriptUtility.loadExternalScript(this);
|
196
|
+
} else {
|
197
|
+
const textContent = this.textContent;
|
198
|
+
if (textContent) {
|
199
|
+
this.ownerDocument.defaultView.eval(textContent);
|
200
|
+
}
|
201
|
+
}
|
202
|
+
}
|
203
|
+
}
|
229
204
|
}
|
@@ -15,7 +15,7 @@ export default class HTMLStyleElement extends HTMLElement implements IHTMLStyleE
|
|
15
15
|
* @returns CSS style sheet.
|
16
16
|
*/
|
17
17
|
public get sheet(): CSSStyleSheet {
|
18
|
-
if (!this.
|
18
|
+
if (!this.isConnected) {
|
19
19
|
return null;
|
20
20
|
}
|
21
21
|
const styleSheet = new CSSStyleSheet();
|
package/src/nodes/node/INode.ts
CHANGED
@@ -8,7 +8,7 @@ export default interface INode extends IEventTarget {
|
|
8
8
|
readonly parentElement: IElement;
|
9
9
|
readonly nodeType: number;
|
10
10
|
readonly childNodes: INode[];
|
11
|
-
isConnected: boolean;
|
11
|
+
readonly isConnected: boolean;
|
12
12
|
readonly nodeValue: string;
|
13
13
|
readonly nodeName: string;
|
14
14
|
readonly previousSibling: INode;
|
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
|
*
|
@@ -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
|
*
|