happy-dom 7.3.0 → 7.5.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/css/declaration/AbstractCSSStyleDeclaration.js +9 -0
- package/lib/css/declaration/AbstractCSSStyleDeclaration.js.map +1 -1
- package/lib/css/declaration/utilities/CSSStyleDeclarationElementStyle.d.ts +0 -2
- package/lib/css/declaration/utilities/CSSStyleDeclarationElementStyle.js +54 -25
- package/lib/css/declaration/utilities/CSSStyleDeclarationElementStyle.js.map +1 -1
- package/lib/event/EventTarget.d.ts +14 -1
- package/lib/event/EventTarget.js +16 -1
- package/lib/event/EventTarget.js.map +1 -1
- package/lib/event/IEventTarget.d.ts +20 -0
- package/lib/event/NonImplementedEventTypes.js +2 -1
- package/lib/event/NonImplementedEventTypes.js.map +1 -1
- package/lib/fetch/IRequestInit.d.ts +1 -0
- package/lib/form-data/IFormData.d.ts +2 -0
- package/lib/nodes/character-data/CharacterData.js +3 -0
- package/lib/nodes/character-data/CharacterData.js.map +1 -1
- package/lib/nodes/document/Document.d.ts +110 -1
- package/lib/nodes/document/Document.js +112 -1
- package/lib/nodes/document/Document.js.map +1 -1
- package/lib/nodes/document/IDocument.d.ts +109 -1
- package/lib/nodes/element/Element.d.ts +35 -0
- package/lib/nodes/element/Element.js +42 -7
- package/lib/nodes/element/Element.js.map +1 -1
- package/lib/nodes/element/IElement.d.ts +35 -0
- package/lib/nodes/html-dialog-element/HTMLDialogElement.d.ts +3 -0
- package/lib/nodes/html-dialog-element/HTMLDialogElement.js +3 -0
- package/lib/nodes/html-dialog-element/HTMLDialogElement.js.map +1 -1
- package/lib/nodes/html-dialog-element/IHTMLDialogElement.d.ts +3 -0
- package/lib/nodes/html-element/HTMLElement.d.ts +26 -0
- package/lib/nodes/html-element/HTMLElement.js +26 -0
- package/lib/nodes/html-element/HTMLElement.js.map +1 -1
- package/lib/nodes/html-element/IHTMLElement.d.ts +26 -0
- package/lib/nodes/html-form-element/HTMLFormElement.d.ts +4 -0
- package/lib/nodes/html-form-element/HTMLFormElement.js +7 -0
- package/lib/nodes/html-form-element/HTMLFormElement.js.map +1 -1
- package/lib/nodes/html-form-element/IHTMLFormElement.d.ts +4 -0
- package/lib/nodes/html-input-element/HTMLInputElement.d.ts +4 -0
- package/lib/nodes/html-input-element/HTMLInputElement.js +4 -0
- package/lib/nodes/html-input-element/HTMLInputElement.js.map +1 -1
- package/lib/nodes/html-input-element/IHTMLInputElement.d.ts +4 -0
- package/lib/nodes/html-media-element/HTMLMediaElement.d.ts +23 -8
- package/lib/nodes/html-media-element/HTMLMediaElement.js +15 -0
- package/lib/nodes/html-media-element/HTMLMediaElement.js.map +1 -1
- package/lib/nodes/html-media-element/IHTMLMediaElement.d.ts +24 -0
- package/lib/nodes/html-select-element/HTMLSelectElement.d.ts +3 -0
- package/lib/nodes/html-select-element/HTMLSelectElement.js +3 -0
- package/lib/nodes/html-select-element/HTMLSelectElement.js.map +1 -1
- package/lib/nodes/html-select-element/IHTMLSelectElement.d.ts +3 -0
- package/lib/nodes/html-slot-element/HTMLSlotElement.d.ts +2 -0
- package/lib/nodes/html-slot-element/HTMLSlotElement.js +5 -0
- package/lib/nodes/html-slot-element/HTMLSlotElement.js.map +1 -1
- package/lib/nodes/html-slot-element/IHTMLSlotElement.d.ts +2 -0
- package/lib/nodes/html-text-area-element/HTMLTextAreaElement.d.ts +4 -1
- package/lib/nodes/html-text-area-element/HTMLTextAreaElement.js +4 -1
- package/lib/nodes/html-text-area-element/HTMLTextAreaElement.js.map +1 -1
- package/lib/nodes/html-text-area-element/IHTMLTextAreaElement.d.ts +3 -0
- package/lib/nodes/node/Node.js +9 -0
- package/lib/nodes/node/Node.js.map +1 -1
- package/lib/nodes/shadow-root/IShadowRoot.d.ts +2 -0
- package/lib/nodes/shadow-root/ShadowRoot.d.ts +2 -0
- package/lib/nodes/shadow-root/ShadowRoot.js +2 -0
- package/lib/nodes/shadow-root/ShadowRoot.js.map +1 -1
- package/lib/nodes/svg-element/ISVGElement.d.ts +7 -0
- package/lib/nodes/svg-element/ISVGSVGElement.d.ts +19 -0
- package/lib/nodes/svg-element/SVGElement.d.ts +7 -0
- package/lib/nodes/svg-element/SVGElement.js +7 -0
- package/lib/nodes/svg-element/SVGElement.js.map +1 -1
- package/lib/nodes/svg-element/SVGSVGElement.d.ts +19 -0
- package/lib/nodes/svg-element/SVGSVGElement.js +22 -0
- package/lib/nodes/svg-element/SVGSVGElement.js.map +1 -1
- package/lib/query-selector/QuerySelector.d.ts +21 -0
- package/lib/query-selector/QuerySelector.js +45 -4
- package/lib/query-selector/QuerySelector.js.map +1 -1
- package/lib/query-selector/SelectorItem.d.ts +14 -11
- package/lib/query-selector/SelectorItem.js +35 -19
- package/lib/query-selector/SelectorItem.js.map +1 -1
- package/lib/window/GlobalWindow.d.ts +2 -0
- package/lib/window/IWindow.d.ts +4 -0
- package/lib/window/Window.d.ts +3 -0
- package/package.json +2 -2
- package/src/css/declaration/AbstractCSSStyleDeclaration.ts +12 -0
- package/src/css/declaration/utilities/CSSStyleDeclarationElementStyle.ts +86 -36
- package/src/event/EventTarget.ts +17 -1
- package/src/event/IEventTarget.ts +22 -0
- package/src/event/NonImplementedEventTypes.ts +2 -1
- package/src/nodes/character-data/CharacterData.ts +4 -0
- package/src/nodes/document/Document.ts +115 -1
- package/src/nodes/document/IDocument.ts +111 -1
- package/src/nodes/element/Element.ts +46 -7
- package/src/nodes/element/IElement.ts +37 -0
- package/src/nodes/html-dialog-element/HTMLDialogElement.ts +4 -0
- package/src/nodes/html-dialog-element/IHTMLDialogElement.ts +5 -0
- package/src/nodes/html-element/HTMLElement.ts +28 -0
- package/src/nodes/html-element/IHTMLElement.ts +28 -0
- package/src/nodes/html-form-element/HTMLFormElement.ts +6 -0
- package/src/nodes/html-form-element/IHTMLFormElement.ts +6 -0
- package/src/nodes/html-input-element/HTMLInputElement.ts +5 -0
- package/src/nodes/html-input-element/IHTMLInputElement.ts +6 -0
- package/src/nodes/html-media-element/HTMLMediaElement.ts +23 -8
- package/src/nodes/html-media-element/IHTMLMediaElement.ts +26 -0
- package/src/nodes/html-select-element/HTMLSelectElement.ts +5 -0
- package/src/nodes/html-select-element/IHTMLSelectElement.ts +5 -0
- package/src/nodes/html-slot-element/HTMLSlotElement.ts +4 -0
- package/src/nodes/html-slot-element/IHTMLSlotElement.ts +4 -0
- package/src/nodes/html-text-area-element/HTMLTextAreaElement.ts +6 -1
- package/src/nodes/html-text-area-element/IHTMLTextAreaElement.ts +5 -0
- package/src/nodes/node/Node.ts +12 -0
- package/src/nodes/shadow-root/IShadowRoot.ts +4 -0
- package/src/nodes/shadow-root/ShadowRoot.ts +4 -0
- package/src/nodes/svg-element/ISVGElement.ts +9 -0
- package/src/nodes/svg-element/ISVGSVGElement.ts +21 -0
- package/src/nodes/svg-element/SVGElement.ts +9 -0
- package/src/nodes/svg-element/SVGSVGElement.ts +21 -0
- package/src/query-selector/QuerySelector.ts +66 -5
- package/src/query-selector/SelectorItem.ts +66 -37
@@ -12,6 +12,7 @@ import IHTMLOptionsCollection from '../html-option-element/IHTMLOptionsCollectio
|
|
12
12
|
import INodeList from '../node/INodeList';
|
13
13
|
import HTMLSelectElementValueSanitizer from './HTMLSelectElementValueSanitizer';
|
14
14
|
import IHTMLSelectElement from './IHTMLSelectElement';
|
15
|
+
import Event from '../../event/Event';
|
15
16
|
|
16
17
|
/**
|
17
18
|
* HTML Select Element.
|
@@ -23,6 +24,10 @@ export default class HTMLSelectElement extends HTMLElement implements IHTMLSelec
|
|
23
24
|
public type: string;
|
24
25
|
public labels: INodeList<IHTMLLabelElement>;
|
25
26
|
|
27
|
+
// Events
|
28
|
+
public onchange: (event: Event) => void | null = null;
|
29
|
+
public oninput: (event: Event) => void | null = null;
|
30
|
+
|
26
31
|
public _value = null;
|
27
32
|
public _selectedIndex = -1;
|
28
33
|
public _options: IHTMLOptionsCollection = null;
|
@@ -4,6 +4,7 @@ import IHTMLLabelElement from '../html-label-element/IHTMLLabelElement';
|
|
4
4
|
import INodeList from '../node/INodeList';
|
5
5
|
import IHTMLOptionsCollection from '../html-option-element/IHTMLOptionsCollection';
|
6
6
|
import ValidityState from '../validity-state/ValidityState';
|
7
|
+
import Event from '../../event/Event';
|
7
8
|
|
8
9
|
/**
|
9
10
|
* HTML Select Element.
|
@@ -24,4 +25,8 @@ export default interface IHTMLSelectElement extends IHTMLElement {
|
|
24
25
|
willValidate: boolean;
|
25
26
|
name: string;
|
26
27
|
multiple: boolean;
|
28
|
+
|
29
|
+
// Events
|
30
|
+
onchange: (event: Event) => void | null;
|
31
|
+
oninput: (event: Event) => void | null;
|
27
32
|
}
|
@@ -4,6 +4,7 @@ import IHTMLSlotElement from './IHTMLSlotElement';
|
|
4
4
|
import IText from '../text/IText';
|
5
5
|
import IElement from '../element/IElement';
|
6
6
|
import INode from '../node/INode';
|
7
|
+
import Event from '../../event/Event';
|
7
8
|
|
8
9
|
/**
|
9
10
|
* HTML Slot Element.
|
@@ -12,6 +13,9 @@ import INode from '../node/INode';
|
|
12
13
|
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLSlotElement.
|
13
14
|
*/
|
14
15
|
export default class HTMLSlotElement extends HTMLElement implements IHTMLSlotElement {
|
16
|
+
// Events
|
17
|
+
public onslotchange: (event: Event) => void | null = null;
|
18
|
+
|
15
19
|
/**
|
16
20
|
* Returns name.
|
17
21
|
*
|
@@ -2,6 +2,7 @@ import IHTMLElement from '../html-element/IHTMLElement';
|
|
2
2
|
import IText from '../text/IText';
|
3
3
|
import IElement from '../element/IElement';
|
4
4
|
import INode from '../node/INode';
|
5
|
+
import Event from '../../event/Event';
|
5
6
|
|
6
7
|
/**
|
7
8
|
* HTML Slot Element.
|
@@ -10,6 +11,9 @@ import INode from '../node/INode';
|
|
10
11
|
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLSlotElement.
|
11
12
|
*/
|
12
13
|
export default interface IHTMLSlotElement extends IHTMLElement {
|
14
|
+
// Events
|
15
|
+
onslotchange: (event: Event) => void | null;
|
16
|
+
|
13
17
|
name: string;
|
14
18
|
|
15
19
|
/**
|
@@ -16,11 +16,16 @@ import IHTMLTextAreaElement from './IHTMLTextAreaElement';
|
|
16
16
|
*/
|
17
17
|
export default class HTMLTextAreaElement extends HTMLElement implements IHTMLTextAreaElement {
|
18
18
|
public readonly type = 'textarea';
|
19
|
+
public defaultValue = '';
|
20
|
+
|
21
|
+
// Events
|
22
|
+
public oninput: (event: Event) => void | null = null;
|
23
|
+
public onselectionchange: (event: Event) => void | null = null;
|
24
|
+
|
19
25
|
public _value = null;
|
20
26
|
public _selectionStart = null;
|
21
27
|
public _selectionEnd = null;
|
22
28
|
public _selectionDirection = HTMLInputElementSelectionDirectionEnum.none;
|
23
|
-
public defaultValue = '';
|
24
29
|
|
25
30
|
/**
|
26
31
|
* Returns minlength.
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import Event from '../../event/Event';
|
1
2
|
import IHTMLElement from '../html-element/IHTMLElement';
|
2
3
|
import IHTMLFormElement from '../html-form-element/IHTMLFormElement';
|
3
4
|
import HTMLInputElementSelectionModeEnum from '../html-input-element/HTMLInputElementSelectionModeEnum';
|
@@ -30,6 +31,10 @@ export default interface IHTMLTextAreaElement extends IHTMLElement {
|
|
30
31
|
selectionDirection: string;
|
31
32
|
textLength: number;
|
32
33
|
|
34
|
+
// Events
|
35
|
+
oninput: (event: Event) => void | null;
|
36
|
+
onselectionchange: (event: Event) => void | null;
|
37
|
+
|
33
38
|
/**
|
34
39
|
* Set selection range.
|
35
40
|
*
|
package/src/nodes/node/Node.ts
CHANGED
@@ -308,6 +308,10 @@ export default class Node extends EventTarget implements INode {
|
|
308
308
|
}
|
309
309
|
}
|
310
310
|
|
311
|
+
if (this.isConnected) {
|
312
|
+
(this.ownerDocument || this)['_cacheID']++;
|
313
|
+
}
|
314
|
+
|
311
315
|
this.childNodes.push(node);
|
312
316
|
|
313
317
|
(<Node>node)._connectToNode(this);
|
@@ -345,6 +349,10 @@ export default class Node extends EventTarget implements INode {
|
|
345
349
|
throw new DOMException('Failed to remove node. Node is not child of parent.');
|
346
350
|
}
|
347
351
|
|
352
|
+
if (this.isConnected) {
|
353
|
+
(this.ownerDocument || this)['_cacheID']++;
|
354
|
+
}
|
355
|
+
|
348
356
|
this.childNodes.splice(index, 1);
|
349
357
|
|
350
358
|
(<Node>node)._connectToNode(null);
|
@@ -404,6 +412,10 @@ export default class Node extends EventTarget implements INode {
|
|
404
412
|
);
|
405
413
|
}
|
406
414
|
|
415
|
+
if (this.isConnected) {
|
416
|
+
(this.ownerDocument || this)['_cacheID']++;
|
417
|
+
}
|
418
|
+
|
407
419
|
if (newNode.parentNode) {
|
408
420
|
const index = newNode.parentNode.childNodes.indexOf(newNode);
|
409
421
|
if (index !== -1) {
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import IDocumentFragment from '../document-fragment/IDocumentFragment';
|
2
2
|
import IElement from '../element/IElement';
|
3
|
+
import Event from '../../event/Event';
|
3
4
|
|
4
5
|
/**
|
5
6
|
* ShadowRoot.
|
@@ -9,6 +10,9 @@ export default interface IShadowRoot extends IDocumentFragment {
|
|
9
10
|
innerHTML: string;
|
10
11
|
host: IElement;
|
11
12
|
|
13
|
+
// Events
|
14
|
+
onslotchange: (event: Event) => void | null;
|
15
|
+
|
12
16
|
/**
|
13
17
|
* Clones a node.
|
14
18
|
*
|
@@ -5,6 +5,7 @@ import IElement from '../element/IElement';
|
|
5
5
|
import CSSStyleSheet from '../../css/CSSStyleSheet';
|
6
6
|
import IShadowRoot from './IShadowRoot';
|
7
7
|
import IHTMLElement from '../../nodes/html-element/IHTMLElement';
|
8
|
+
import Event from '../../event/Event';
|
8
9
|
|
9
10
|
/**
|
10
11
|
* ShadowRoot.
|
@@ -14,6 +15,9 @@ export default class ShadowRoot extends DocumentFragment implements IShadowRoot
|
|
14
15
|
public readonly host: IElement = null;
|
15
16
|
public adoptedStyleSheets: CSSStyleSheet[] = [];
|
16
17
|
|
18
|
+
// Events
|
19
|
+
public onslotchange: (event: Event) => void | null = null;
|
20
|
+
|
17
21
|
/**
|
18
22
|
* Returns inner HTML.
|
19
23
|
*
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import Event from '../../event/Event';
|
1
2
|
import CSSStyleDeclaration from '../../css/declaration/CSSStyleDeclaration';
|
2
3
|
import IElement from '../element/IElement';
|
3
4
|
import ISVGSVGElement from './ISVGSVGElement';
|
@@ -12,4 +13,12 @@ export default interface ISVGElement extends IElement {
|
|
12
13
|
readonly ownerSVGElement: ISVGSVGElement;
|
13
14
|
readonly dataset: { [key: string]: string };
|
14
15
|
readonly style: CSSStyleDeclaration;
|
16
|
+
|
17
|
+
// Events
|
18
|
+
onabort: (event: Event) => void | null;
|
19
|
+
onerror: (event: Event) => void | null;
|
20
|
+
onload: (event: Event) => void | null;
|
21
|
+
onresize: (event: Event) => void | null;
|
22
|
+
onscroll: (event: Event) => void | null;
|
23
|
+
onunload: (event: Event) => void | null;
|
15
24
|
}
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import Event from '../../event/Event';
|
1
2
|
import INode from '../node/INode';
|
2
3
|
import ISVGGraphicsElement from './ISVGGraphicsElement';
|
3
4
|
import SVGAngle from './SVGAngle';
|
@@ -25,6 +26,26 @@ export default interface ISVGSVGElement extends ISVGGraphicsElement {
|
|
25
26
|
currentTranslate: SVGPoint;
|
26
27
|
viewBox: SVGAnimatedRect;
|
27
28
|
|
29
|
+
// Events
|
30
|
+
onafterprint: (event: Event) => void | null;
|
31
|
+
onbeforeprint: (event: Event) => void | null;
|
32
|
+
onbeforeunload: (event: Event) => void | null;
|
33
|
+
ongamepadconnected: (event: Event) => void | null;
|
34
|
+
ongamepaddisconnected: (event: Event) => void | null;
|
35
|
+
onhashchange: (event: Event) => void | null;
|
36
|
+
onlanguagechange: (event: Event) => void | null;
|
37
|
+
onmessage: (event: Event) => void | null;
|
38
|
+
onmessageerror: (event: Event) => void | null;
|
39
|
+
onoffline: (event: Event) => void | null;
|
40
|
+
ononline: (event: Event) => void | null;
|
41
|
+
onpagehide: (event: Event) => void | null;
|
42
|
+
onpageshow: (event: Event) => void | null;
|
43
|
+
onpopstate: (event: Event) => void | null;
|
44
|
+
onrejectionhandled: (event: Event) => void | null;
|
45
|
+
onstorage: (event: Event) => void | null;
|
46
|
+
onunhandledrejection: (event: Event) => void | null;
|
47
|
+
onunload: (event: Event) => void | null;
|
48
|
+
|
28
49
|
/**
|
29
50
|
* Pauses animation.
|
30
51
|
*/
|
@@ -3,6 +3,7 @@ import Element from '../element/Element';
|
|
3
3
|
import ISVGElement from './ISVGElement';
|
4
4
|
import ISVGSVGElement from './ISVGSVGElement';
|
5
5
|
import IAttr from '../attr/IAttr';
|
6
|
+
import Event from '../../event/Event';
|
6
7
|
|
7
8
|
/**
|
8
9
|
* SVG Element.
|
@@ -11,6 +12,14 @@ import IAttr from '../attr/IAttr';
|
|
11
12
|
* https://developer.mozilla.org/en-US/docs/Web/API/SVGElement.
|
12
13
|
*/
|
13
14
|
export default class SVGElement extends Element implements ISVGElement {
|
15
|
+
// Events
|
16
|
+
public onabort: (event: Event) => void | null = null;
|
17
|
+
public onerror: (event: Event) => void | null = null;
|
18
|
+
public onload: (event: Event) => void | null = null;
|
19
|
+
public onresize: (event: Event) => void | null = null;
|
20
|
+
public onscroll: (event: Event) => void | null = null;
|
21
|
+
public onunload: (event: Event) => void | null = null;
|
22
|
+
|
14
23
|
private _style: CSSStyleDeclaration = null;
|
15
24
|
|
16
25
|
/**
|
@@ -8,11 +8,32 @@ import SVGTransform from './SVGTransform';
|
|
8
8
|
import SVGAnimatedRect from './SVGAnimatedRect';
|
9
9
|
import ISVGSVGElement from './ISVGSVGElement';
|
10
10
|
import INode from '../node/INode';
|
11
|
+
import Event from '../../event/Event';
|
11
12
|
|
12
13
|
/**
|
13
14
|
* SVGSVGElement.
|
14
15
|
*/
|
15
16
|
export default class SVGSVGElement extends SVGGraphicsElement implements ISVGSVGElement {
|
17
|
+
// Events
|
18
|
+
public onafterprint: (event: Event) => void | null = null;
|
19
|
+
public onbeforeprint: (event: Event) => void | null = null;
|
20
|
+
public onbeforeunload: (event: Event) => void | null = null;
|
21
|
+
public ongamepadconnected: (event: Event) => void | null = null;
|
22
|
+
public ongamepaddisconnected: (event: Event) => void | null = null;
|
23
|
+
public onhashchange: (event: Event) => void | null = null;
|
24
|
+
public onlanguagechange: (event: Event) => void | null = null;
|
25
|
+
public onmessage: (event: Event) => void | null = null;
|
26
|
+
public onmessageerror: (event: Event) => void | null = null;
|
27
|
+
public onoffline: (event: Event) => void | null = null;
|
28
|
+
public ononline: (event: Event) => void | null = null;
|
29
|
+
public onpagehide: (event: Event) => void | null = null;
|
30
|
+
public onpageshow: (event: Event) => void | null = null;
|
31
|
+
public onpopstate: (event: Event) => void | null = null;
|
32
|
+
public onrejectionhandled: (event: Event) => void | null = null;
|
33
|
+
public onstorage: (event: Event) => void | null = null;
|
34
|
+
public onunhandledrejection: (event: Event) => void | null = null;
|
35
|
+
public onunload: (event: Event) => void | null = null;
|
36
|
+
|
16
37
|
/**
|
17
38
|
* Returns preserveAspectRatio.
|
18
39
|
*
|
@@ -8,9 +8,6 @@ import NodeListFactory from '../nodes/node/NodeListFactory';
|
|
8
8
|
|
9
9
|
const SELECTOR_PART_REGEXP = /(\[[^\]]+\]|[a-zA-Z0-9-_.#"*:()\]]+)|([ ,>]+)/g;
|
10
10
|
|
11
|
-
// The above one seem to work fine and is faster, but this one can be useful if more rules need to be added as it is more "correct".
|
12
|
-
// Const SELECTOR_PART_REGEXP = /([a-zA-Z0-9-$.]+|\[[a-zA-Z0-9-]+\]|\[[a-zA-Z0-9$-~|^$*]+[ ]*=[ ]*"[^"]+"\])|([ ,]+)/g;
|
13
|
-
|
14
11
|
/**
|
15
12
|
* Utility for query selection in an HTML element.
|
16
13
|
*
|
@@ -57,6 +54,70 @@ export default class QuerySelector {
|
|
57
54
|
return null;
|
58
55
|
}
|
59
56
|
|
57
|
+
/**
|
58
|
+
* Checks if a node matches a selector and returns priority weight.
|
59
|
+
*
|
60
|
+
* @param node Node to search in.
|
61
|
+
* @param selector Selector.
|
62
|
+
* @returns Result.
|
63
|
+
*/
|
64
|
+
public static match(node: INode, selector: string): { priorityWeight: number; matches: boolean } {
|
65
|
+
for (const parts of this.getSelectorParts(selector)) {
|
66
|
+
const result = this.matchesSelector(node, node, parts.reverse());
|
67
|
+
|
68
|
+
if (result.matches) {
|
69
|
+
return result;
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
return { priorityWeight: 0, matches: false };
|
74
|
+
}
|
75
|
+
|
76
|
+
/**
|
77
|
+
* Checks if a node matches a selector.
|
78
|
+
*
|
79
|
+
* @param targetNode Target node.
|
80
|
+
* @param currentNode Current node.
|
81
|
+
* @param selectorParts Selector parts.
|
82
|
+
* @param [priorityWeight] Priority weight.
|
83
|
+
* @returns Result.
|
84
|
+
*/
|
85
|
+
private static matchesSelector(
|
86
|
+
targetNode: INode,
|
87
|
+
currentNode: INode,
|
88
|
+
selectorParts: string[],
|
89
|
+
priorityWeight = 0
|
90
|
+
): {
|
91
|
+
priorityWeight: number;
|
92
|
+
matches: boolean;
|
93
|
+
} {
|
94
|
+
const isDirectChild = selectorParts[0] === '>';
|
95
|
+
if (isDirectChild) {
|
96
|
+
selectorParts = selectorParts.slice(1);
|
97
|
+
if (selectorParts.length === 0) {
|
98
|
+
return { priorityWeight: 0, matches: false };
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
if (selectorParts.length === 0) {
|
103
|
+
return { priorityWeight, matches: true };
|
104
|
+
}
|
105
|
+
|
106
|
+
const selector = new SelectorItem(selectorParts[0]);
|
107
|
+
const result = selector.match(<Element>currentNode);
|
108
|
+
|
109
|
+
if (targetNode === currentNode && !result.matches) {
|
110
|
+
return { priorityWeight: 0, matches: false };
|
111
|
+
}
|
112
|
+
|
113
|
+
return this.matchesSelector(
|
114
|
+
isDirectChild ? currentNode.parentNode : targetNode,
|
115
|
+
currentNode.parentNode,
|
116
|
+
selectorParts.slice(1),
|
117
|
+
priorityWeight + result.priorityWeight
|
118
|
+
);
|
119
|
+
}
|
120
|
+
|
60
121
|
/**
|
61
122
|
* Finds elements based on a query selector for a part of a list of selectors separated with comma.
|
62
123
|
*
|
@@ -81,7 +142,7 @@ export default class QuerySelector {
|
|
81
142
|
|
82
143
|
for (const node of nodes) {
|
83
144
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
84
|
-
if (selector.match(<Element>node)) {
|
145
|
+
if (selector.match(<Element>node).matches) {
|
85
146
|
if (selectorParts.length === 1) {
|
86
147
|
if (rootNode !== node) {
|
87
148
|
matched.push(node);
|
@@ -125,7 +186,7 @@ export default class QuerySelector {
|
|
125
186
|
const selector = selectorItem || new SelectorItem(selectorParts[0]);
|
126
187
|
|
127
188
|
for (const node of nodes) {
|
128
|
-
if (node.nodeType === Node.ELEMENT_NODE && selector.match(<Element>node)) {
|
189
|
+
if (node.nodeType === Node.ELEMENT_NODE && selector.match(<Element>node).matches) {
|
129
190
|
if (selectorParts.length === 1) {
|
130
191
|
if (rootNode !== node) {
|
131
192
|
return <Element>node;
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import DOMException from '../exception/DOMException';
|
2
|
+
import IElement from '../nodes/element/IElement';
|
2
3
|
import Element from '../nodes/element/Element';
|
3
4
|
|
4
5
|
const ATTRIBUTE_REGEXP =
|
@@ -13,12 +14,12 @@ const ID_REGEXP = /#[A-Za-z][-A-Za-z0-9_]*/g;
|
|
13
14
|
* Selector item.
|
14
15
|
*/
|
15
16
|
export default class SelectorItem {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
private isAll: boolean;
|
18
|
+
private isID: boolean;
|
19
|
+
private isAttribute: boolean;
|
20
|
+
private isPseudo: boolean;
|
21
|
+
private isClass: boolean;
|
22
|
+
private isTagName: boolean;
|
22
23
|
private tagName = null;
|
23
24
|
private selector: string;
|
24
25
|
private id: string;
|
@@ -42,6 +43,7 @@ export default class SelectorItem {
|
|
42
43
|
this.isTagName = this.tagName !== null;
|
43
44
|
this.selector = selector;
|
44
45
|
this.id = null;
|
46
|
+
|
45
47
|
if (!this.isAll && this.isID) {
|
46
48
|
const idMatches = baseSelector.match(ID_REGEXP);
|
47
49
|
if (idMatches) {
|
@@ -54,46 +56,60 @@ export default class SelectorItem {
|
|
54
56
|
* Matches a selector against an element.
|
55
57
|
*
|
56
58
|
* @param element HTML element.
|
57
|
-
* @returns
|
59
|
+
* @returns Result.
|
58
60
|
*/
|
59
|
-
public match(element:
|
61
|
+
public match(element: IElement): { priorityWeight: number; matches: boolean } {
|
60
62
|
const selector = this.selector;
|
61
63
|
|
64
|
+
let priorityWeight = 0;
|
65
|
+
|
62
66
|
// Is all (*)
|
63
67
|
if (this.isAll) {
|
64
|
-
return true;
|
68
|
+
return { priorityWeight: 0, matches: true };
|
65
69
|
}
|
66
70
|
|
67
71
|
// ID Match
|
68
72
|
if (this.isID) {
|
73
|
+
priorityWeight += 100;
|
74
|
+
|
69
75
|
if (this.id !== element.id) {
|
70
|
-
return false;
|
76
|
+
return { priorityWeight: 0, matches: false };
|
71
77
|
}
|
72
78
|
}
|
73
79
|
|
74
80
|
// Tag name match
|
75
81
|
if (this.isTagName) {
|
82
|
+
priorityWeight += 1;
|
83
|
+
|
76
84
|
if (this.tagName !== element.tagName) {
|
77
|
-
return false;
|
85
|
+
return { priorityWeight: 0, matches: false };
|
78
86
|
}
|
79
87
|
}
|
80
88
|
|
81
89
|
// Class match
|
82
|
-
if (this.isClass
|
83
|
-
|
90
|
+
if (this.isClass) {
|
91
|
+
const result = this.matchesClass(element, selector);
|
92
|
+
priorityWeight += result.priorityWeight;
|
93
|
+
if (!result.matches) {
|
94
|
+
return { priorityWeight: 0, matches: false };
|
95
|
+
}
|
84
96
|
}
|
85
97
|
|
86
98
|
// Pseudo match
|
87
99
|
if (this.isPseudo && !this.matchesPsuedo(element, selector)) {
|
88
|
-
return false;
|
100
|
+
return { priorityWeight: 0, matches: false };
|
89
101
|
}
|
90
102
|
|
91
103
|
// Attribute match
|
92
|
-
if (this.isAttribute
|
93
|
-
|
104
|
+
if (this.isAttribute) {
|
105
|
+
const result = this.matchesAttribute(element, selector);
|
106
|
+
priorityWeight += result.priorityWeight;
|
107
|
+
if (!result.matches) {
|
108
|
+
return { priorityWeight: 0, matches: false };
|
109
|
+
}
|
94
110
|
}
|
95
111
|
|
96
|
-
return true;
|
112
|
+
return { priorityWeight, matches: true };
|
97
113
|
}
|
98
114
|
|
99
115
|
/**
|
@@ -103,7 +119,7 @@ export default class SelectorItem {
|
|
103
119
|
* @param selector Selector.
|
104
120
|
* @returns True if it is a match.
|
105
121
|
*/
|
106
|
-
private matchesPsuedo(element:
|
122
|
+
private matchesPsuedo(element: IElement, selector: string): boolean {
|
107
123
|
const regexp = new RegExp(PSUEDO_REGEXP, 'g');
|
108
124
|
let match: RegExpMatchArray;
|
109
125
|
|
@@ -113,8 +129,8 @@ export default class SelectorItem {
|
|
113
129
|
return false;
|
114
130
|
} else if (
|
115
131
|
match[3] &&
|
116
|
-
((isNotClass && this.matchesClass(element, match[3])) ||
|
117
|
-
(!isNotClass && this.matchesAttribute(element, match[3])))
|
132
|
+
((isNotClass && this.matchesClass(element, match[3]).matches) ||
|
133
|
+
(!isNotClass && this.matchesAttribute(element, match[3])).matches)
|
118
134
|
) {
|
119
135
|
return false;
|
120
136
|
} else if (match[4] && !this.matchesPsuedoExpression(element, match[4])) {
|
@@ -133,8 +149,8 @@ export default class SelectorItem {
|
|
133
149
|
* @param place Place.
|
134
150
|
* @returns True if it is a match.
|
135
151
|
*/
|
136
|
-
private matchesNthChild(element:
|
137
|
-
let children = element.parentNode ? (<
|
152
|
+
private matchesNthChild(element: IElement, psuedo: string, place: string): boolean {
|
153
|
+
let children = element.parentNode ? (<IElement>element.parentNode).children : [];
|
138
154
|
|
139
155
|
switch (psuedo.toLowerCase()) {
|
140
156
|
case 'nth-of-type':
|
@@ -188,8 +204,8 @@ export default class SelectorItem {
|
|
188
204
|
* @param psuedo Psuedo name.
|
189
205
|
* @returns True if it is a match.
|
190
206
|
*/
|
191
|
-
private matchesPsuedoExpression(element:
|
192
|
-
const parent = <
|
207
|
+
private matchesPsuedoExpression(element: IElement, psuedo: string): boolean {
|
208
|
+
const parent = <IElement>element.parentNode;
|
193
209
|
|
194
210
|
if (!parent) {
|
195
211
|
return false;
|
@@ -240,24 +256,31 @@ export default class SelectorItem {
|
|
240
256
|
*
|
241
257
|
* @param element Element.
|
242
258
|
* @param selector Selector.
|
243
|
-
* @returns
|
259
|
+
* @returns Result.
|
244
260
|
*/
|
245
|
-
private matchesAttribute(
|
261
|
+
private matchesAttribute(
|
262
|
+
element: IElement,
|
263
|
+
selector: string
|
264
|
+
): { priorityWeight: number; matches: boolean } {
|
246
265
|
const regexp = new RegExp(ATTRIBUTE_REGEXP, 'g');
|
247
266
|
let match: RegExpMatchArray;
|
267
|
+
let priorityWeight = 0;
|
248
268
|
|
249
269
|
while ((match = regexp.exec(selector))) {
|
250
270
|
const isPsuedo = match.index > 0 && selector[match.index - 1] === '(';
|
271
|
+
|
272
|
+
priorityWeight += 10;
|
273
|
+
|
251
274
|
if (
|
252
275
|
!isPsuedo &&
|
253
276
|
((match[1] && !this.matchesAttributeName(element, match[1])) ||
|
254
277
|
(match[2] && !this.matchesAttributeNameAndValue(element, match[2], match[4], match[3])))
|
255
278
|
) {
|
256
|
-
return false;
|
279
|
+
return { priorityWeight: 0, matches: false };
|
257
280
|
}
|
258
281
|
}
|
259
282
|
|
260
|
-
return true;
|
283
|
+
return { priorityWeight, matches: true };
|
261
284
|
}
|
262
285
|
|
263
286
|
/**
|
@@ -265,20 +288,26 @@ export default class SelectorItem {
|
|
265
288
|
*
|
266
289
|
* @param element Element.
|
267
290
|
* @param selector Selector.
|
268
|
-
* @returns
|
291
|
+
* @returns Result.
|
269
292
|
*/
|
270
|
-
private matchesClass(
|
293
|
+
private matchesClass(
|
294
|
+
element: IElement,
|
295
|
+
selector: string
|
296
|
+
): { priorityWeight: number; matches: boolean } {
|
271
297
|
const regexp = new RegExp(CLASS_REGEXP, 'g');
|
272
298
|
const classList = element.className.split(' ');
|
299
|
+
const classSelector = selector.split(':')[0];
|
300
|
+
let priorityWeight = 0;
|
273
301
|
let match: RegExpMatchArray;
|
274
302
|
|
275
|
-
while ((match = regexp.exec(
|
303
|
+
while ((match = regexp.exec(classSelector))) {
|
304
|
+
priorityWeight += 10;
|
276
305
|
if (!classList.includes(match[1])) {
|
277
|
-
return false;
|
306
|
+
return { priorityWeight: 0, matches: false };
|
278
307
|
}
|
279
308
|
}
|
280
309
|
|
281
|
-
return true;
|
310
|
+
return { priorityWeight, matches: true };
|
282
311
|
}
|
283
312
|
|
284
313
|
/**
|
@@ -288,12 +317,12 @@ export default class SelectorItem {
|
|
288
317
|
* @param attributeName Attribute name.
|
289
318
|
* @returns True if it is a match.
|
290
319
|
*/
|
291
|
-
private matchesAttributeName(element:
|
320
|
+
private matchesAttributeName(element: IElement, attributeName: string): boolean {
|
292
321
|
if (ATTRIBUTE_NAME_REGEXP.test(attributeName)) {
|
293
322
|
throw new DOMException(`The selector "${this.selector}" is not valid.`);
|
294
323
|
}
|
295
324
|
|
296
|
-
return !!element._attributes[attributeName.toLowerCase()];
|
325
|
+
return !!(<Element>element)._attributes[attributeName.toLowerCase()];
|
297
326
|
}
|
298
327
|
|
299
328
|
/** .
|
@@ -314,12 +343,12 @@ export default class SelectorItem {
|
|
314
343
|
* @param matchType
|
315
344
|
*/
|
316
345
|
private matchesAttributeNameAndValue(
|
317
|
-
element:
|
346
|
+
element: IElement,
|
318
347
|
attributeName: string,
|
319
348
|
attributeValue: string,
|
320
349
|
matchType: string = null
|
321
350
|
): boolean {
|
322
|
-
const attribute = element._attributes[attributeName.toLowerCase()];
|
351
|
+
const attribute = (<Element>element)._attributes[attributeName.toLowerCase()];
|
323
352
|
const value = attributeValue;
|
324
353
|
|
325
354
|
if (ATTRIBUTE_NAME_REGEXP.test(attributeName)) {
|