happy-dom 2.41.0 → 2.43.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/CSSStyleDeclaration.js +1 -1
- package/lib/css/CSSStyleDeclaration.js.map +1 -1
- package/lib/dom-token-list/DOMTokenList.d.ts +104 -0
- package/lib/dom-token-list/DOMTokenList.js +209 -0
- package/lib/dom-token-list/DOMTokenList.js.map +1 -0
- package/lib/dom-token-list/IDOMTokenList.d.ts +18 -0
- package/lib/dom-token-list/IDOMTokenList.js +3 -0
- package/lib/dom-token-list/IDOMTokenList.js.map +1 -0
- package/lib/nodes/document/Document.d.ts +7 -0
- package/lib/nodes/document/Document.js +12 -0
- package/lib/nodes/document/Document.js.map +1 -1
- package/lib/nodes/document/IDocument.d.ts +13 -2
- package/lib/nodes/element/Element.d.ts +15 -5
- package/lib/nodes/element/Element.js +28 -3
- package/lib/nodes/element/Element.js.map +1 -1
- package/lib/nodes/element/IElement.d.ts +2 -2
- package/lib/nodes/html-label-element/HTMLLabelElement.d.ts +0 -1
- package/lib/nodes/html-label-element/HTMLLabelElement.js +2 -6
- package/lib/nodes/html-label-element/HTMLLabelElement.js.map +1 -1
- package/lib/nodes/html-link-element/HTMLLinkElement.d.ts +12 -0
- package/lib/nodes/html-link-element/HTMLLinkElement.js +26 -0
- package/lib/nodes/html-link-element/HTMLLinkElement.js.map +1 -1
- package/lib/nodes/html-link-element/IHTMLLinkElement.d.ts +2 -0
- package/lib/query-selector/SelectorItem.d.ts +18 -2
- package/lib/query-selector/SelectorItem.js +54 -25
- package/lib/query-selector/SelectorItem.js.map +1 -1
- package/lib/window/IWindow.d.ts +3 -1
- package/lib/window/Window.d.ts +1 -0
- package/lib/window/Window.js +1 -0
- package/lib/window/Window.js.map +1 -1
- package/package.json +2 -2
- package/src/css/CSSStyleDeclaration.ts +1 -1
- package/src/dom-token-list/DOMTokenList.ts +219 -0
- package/src/dom-token-list/IDOMTokenList.ts +19 -0
- package/src/nodes/document/Document.ts +10 -0
- package/src/nodes/document/IDocument.ts +13 -2
- package/src/nodes/element/Element.ts +30 -3
- package/src/nodes/element/IElement.ts +2 -2
- package/src/nodes/html-label-element/HTMLLabelElement.ts +1 -5
- package/src/nodes/html-link-element/HTMLLinkElement.ts +26 -0
- package/src/nodes/html-link-element/IHTMLLinkElement.ts +2 -0
- package/src/query-selector/SelectorItem.ts +62 -26
- package/src/window/IWindow.ts +3 -1
- package/src/window/Window.ts +1 -0
- package/lib/nodes/element/ClassList.d.ts +0 -40
- package/lib/nodes/element/ClassList.js +0 -99
- package/lib/nodes/element/ClassList.js.map +0 -1
- package/src/nodes/element/ClassList.ts +0 -92
@@ -0,0 +1,219 @@
|
|
1
|
+
import DOMException from '../exception/DOMException';
|
2
|
+
import Element from '../nodes/element/Element';
|
3
|
+
import IDOMTokenList from './IDOMTokenList';
|
4
|
+
|
5
|
+
/**
|
6
|
+
* DOM Token List.
|
7
|
+
*
|
8
|
+
* Reference:
|
9
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList.
|
10
|
+
*/
|
11
|
+
export default class DOMTokenList implements IDOMTokenList {
|
12
|
+
public readonly length = 0;
|
13
|
+
private _ownerElement: Element;
|
14
|
+
private _attributeName: string;
|
15
|
+
|
16
|
+
/**
|
17
|
+
* Constructor.
|
18
|
+
*
|
19
|
+
* @param ownerElement Owner element.
|
20
|
+
* @param attributeName Attribute name.
|
21
|
+
*/
|
22
|
+
constructor(ownerElement: Element, attributeName) {
|
23
|
+
this._ownerElement = ownerElement;
|
24
|
+
this._attributeName = attributeName;
|
25
|
+
this._updateIndices();
|
26
|
+
}
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Set value.
|
30
|
+
*
|
31
|
+
* @param value Value.
|
32
|
+
*/
|
33
|
+
public set value(value: string) {
|
34
|
+
this._ownerElement.setAttributeNS(null, this._attributeName, value);
|
35
|
+
}
|
36
|
+
|
37
|
+
/**
|
38
|
+
* Get value.
|
39
|
+
*/
|
40
|
+
public get value(): string {
|
41
|
+
return this._ownerElement.getAttributeNS(null, this._attributeName);
|
42
|
+
}
|
43
|
+
|
44
|
+
/**
|
45
|
+
* Get ClassName.
|
46
|
+
*
|
47
|
+
* @param index Index.
|
48
|
+
* */
|
49
|
+
public item(index: number | string): string {
|
50
|
+
index = typeof index === 'number' ? index : 0;
|
51
|
+
return index >= 0 && this[index] ? this[index] : null;
|
52
|
+
}
|
53
|
+
|
54
|
+
/**
|
55
|
+
* Replace Token.
|
56
|
+
*
|
57
|
+
* @param token Token.
|
58
|
+
* @param newToken NewToken.
|
59
|
+
*/
|
60
|
+
public replace(token: string, newToken: string): boolean {
|
61
|
+
const attr = this._ownerElement.getAttributeNS(null, this._attributeName);
|
62
|
+
const list = attr ? attr.split(' ') : [];
|
63
|
+
const index = list.indexOf(token);
|
64
|
+
if (index === -1) {
|
65
|
+
return false;
|
66
|
+
}
|
67
|
+
list[index] = newToken;
|
68
|
+
this._ownerElement.setAttributeNS(null, this._attributeName, list.join(' '));
|
69
|
+
return true;
|
70
|
+
}
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Supports.
|
74
|
+
*
|
75
|
+
* @param token Token.
|
76
|
+
*/
|
77
|
+
public supports(token: string): boolean {
|
78
|
+
// TODO: Only implemented for classList, which does not have any supported tokens
|
79
|
+
throw new DOMException(
|
80
|
+
`Failed to execute '${token}' on 'DOMTokenList': DOMTokenList has no supported tokens.`,
|
81
|
+
'TypeError'
|
82
|
+
);
|
83
|
+
}
|
84
|
+
|
85
|
+
/**
|
86
|
+
* Returns an iterator, allowing you to go through all values of the key/value pairs contained in this object.
|
87
|
+
*
|
88
|
+
*
|
89
|
+
*/
|
90
|
+
public values(): IterableIterator<string> {
|
91
|
+
const attr = this._ownerElement.getAttributeNS(null, this._attributeName);
|
92
|
+
return (attr ? attr.split(' ') : []).values();
|
93
|
+
}
|
94
|
+
|
95
|
+
/**
|
96
|
+
* Returns an iterator, allowing you to go through all key/value pairs contained in this object.
|
97
|
+
*
|
98
|
+
*
|
99
|
+
*/
|
100
|
+
public entries(): IterableIterator<[number, string]> {
|
101
|
+
const attr = this._ownerElement.getAttributeNS(null, this._attributeName);
|
102
|
+
return (attr ? attr.split(' ') : []).entries();
|
103
|
+
}
|
104
|
+
|
105
|
+
/**
|
106
|
+
* Executes a provided callback function once for each DOMTokenList element.
|
107
|
+
*
|
108
|
+
* @param callback
|
109
|
+
* @param thisArg
|
110
|
+
*/
|
111
|
+
public forEach(callback: (currentValue, currentIndex, listObj) => void, thisArg?: this): void {
|
112
|
+
const attr = this._ownerElement.getAttributeNS(null, this._attributeName);
|
113
|
+
return (attr ? attr.split(' ') : []).forEach(callback, thisArg);
|
114
|
+
}
|
115
|
+
|
116
|
+
/**
|
117
|
+
* Returns an iterator, allowing you to go through all keys of the key/value pairs contained in this object.
|
118
|
+
*
|
119
|
+
*/
|
120
|
+
public keys(): IterableIterator<number> {
|
121
|
+
const attr = this._ownerElement.getAttributeNS(null, this._attributeName);
|
122
|
+
return (attr ? attr.split(' ') : []).keys();
|
123
|
+
}
|
124
|
+
|
125
|
+
/**
|
126
|
+
* Adds tokens.
|
127
|
+
*
|
128
|
+
* @param tokens Tokens.
|
129
|
+
*/
|
130
|
+
public add(...tokens: string[]): void {
|
131
|
+
const attr = this._ownerElement.getAttributeNS(null, this._attributeName);
|
132
|
+
const list = attr ? attr.split(' ') : [];
|
133
|
+
|
134
|
+
for (const token of tokens) {
|
135
|
+
const index = list.indexOf(token);
|
136
|
+
if (index === -1) {
|
137
|
+
list.push(token);
|
138
|
+
} else {
|
139
|
+
list[index] = token;
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
this._ownerElement.setAttributeNS(null, this._attributeName, list.join(' '));
|
144
|
+
}
|
145
|
+
|
146
|
+
/**
|
147
|
+
* Removes tokens.
|
148
|
+
*
|
149
|
+
* @param tokens Tokens.
|
150
|
+
*/
|
151
|
+
public remove(...tokens: string[]): void {
|
152
|
+
const attr = this._ownerElement.getAttributeNS(null, this._attributeName);
|
153
|
+
const list = attr ? attr.split(' ') : [];
|
154
|
+
|
155
|
+
for (const token of tokens) {
|
156
|
+
const index = list.indexOf(token);
|
157
|
+
if (index !== -1) {
|
158
|
+
list.splice(index, 1);
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
162
|
+
this._ownerElement.setAttributeNS(null, this._attributeName, list.join(' '));
|
163
|
+
}
|
164
|
+
|
165
|
+
/**
|
166
|
+
* Check if the list contains a class.
|
167
|
+
*
|
168
|
+
* @param className Class name.
|
169
|
+
* @returns TRUE if it contains.
|
170
|
+
*/
|
171
|
+
public contains(className: string): boolean {
|
172
|
+
const attr = this._ownerElement.getAttributeNS(null, this._attributeName);
|
173
|
+
return (attr ? attr.split(' ') : []).includes(className);
|
174
|
+
}
|
175
|
+
|
176
|
+
/**
|
177
|
+
* Toggle a class name.
|
178
|
+
*
|
179
|
+
* @param token A string representing the class name you want to toggle.
|
180
|
+
* @param [force] If included, turns the toggle into a one way-only operation. If set to `false`, then class name will only be removed, but not added. If set to `true`, then class name will only be added, but not removed.
|
181
|
+
* @returns A boolean value, `true` or `false`, indicating whether class name is in the list after the call or not.
|
182
|
+
*/
|
183
|
+
public toggle(token: string, force?: boolean): boolean {
|
184
|
+
let shouldAdd: boolean;
|
185
|
+
|
186
|
+
if (force !== undefined) {
|
187
|
+
shouldAdd = force;
|
188
|
+
} else {
|
189
|
+
shouldAdd = !this.contains(token);
|
190
|
+
}
|
191
|
+
|
192
|
+
if (shouldAdd) {
|
193
|
+
this.add(token);
|
194
|
+
return true;
|
195
|
+
}
|
196
|
+
|
197
|
+
this.remove(token);
|
198
|
+
|
199
|
+
return false;
|
200
|
+
}
|
201
|
+
|
202
|
+
/**
|
203
|
+
* Updates indices.
|
204
|
+
*/
|
205
|
+
public _updateIndices(): void {
|
206
|
+
const attr = this._ownerElement.getAttribute('class');
|
207
|
+
const list = attr ? Array.from(new Set(attr.split(' '))) : [];
|
208
|
+
|
209
|
+
for (let i = list.length - 1, max = this.length; i < max; i++) {
|
210
|
+
delete this[i];
|
211
|
+
}
|
212
|
+
|
213
|
+
for (let i = 0, max = list.length; i < max; i++) {
|
214
|
+
this[i] = list[i];
|
215
|
+
}
|
216
|
+
|
217
|
+
(<number>this.length) = list.length;
|
218
|
+
}
|
219
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
/**
|
2
|
+
* IDOMTokenList.
|
3
|
+
*/
|
4
|
+
export default interface IDOMTokenList {
|
5
|
+
value: string;
|
6
|
+
readonly length: number;
|
7
|
+
item(index: number | string): string;
|
8
|
+
contains(token: string): boolean;
|
9
|
+
add(...tokens: string[]): void;
|
10
|
+
remove(...tokens: string[]): void;
|
11
|
+
toggle(token: string, force?: boolean): boolean;
|
12
|
+
replace(token: string, newToken: string): boolean;
|
13
|
+
supports(token: string): boolean;
|
14
|
+
|
15
|
+
values(): IterableIterator<string>;
|
16
|
+
entries(): IterableIterator<[number, string]>;
|
17
|
+
forEach(callback: (currentValue, currentIndex, listObj) => void, thisArg?: this): void;
|
18
|
+
keys(): IterableIterator<number>;
|
19
|
+
}
|
@@ -21,6 +21,7 @@ import CSSStyleSheet from '../../css/CSSStyleSheet';
|
|
21
21
|
import DOMException from '../../exception/DOMException';
|
22
22
|
import CookieUtility from '../../cookie/CookieUtility';
|
23
23
|
import IElement from '../element/IElement';
|
24
|
+
import IHTMLScriptElement from '../html-script-element/IHTMLScriptElement';
|
24
25
|
import IHTMLElement from '../html-element/IHTMLElement';
|
25
26
|
import IDocumentType from '../document-type/IDocumentType';
|
26
27
|
import INode from '../node/INode';
|
@@ -240,6 +241,15 @@ export default class Document extends Node implements IDocument {
|
|
240
241
|
return this._defaultView.location;
|
241
242
|
}
|
242
243
|
|
244
|
+
/**
|
245
|
+
* Returns scripts.
|
246
|
+
*
|
247
|
+
* @returns Scripts.
|
248
|
+
*/
|
249
|
+
public get scripts(): IHTMLCollection<IHTMLScriptElement> {
|
250
|
+
return <IHTMLCollection<IHTMLScriptElement>>this.getElementsByTagName('script');
|
251
|
+
}
|
252
|
+
|
243
253
|
/**
|
244
254
|
* Inserts a set of Node objects or DOMString objects after the last child of the ParentNode. DOMString objects are inserted as equivalent Text nodes.
|
245
255
|
*
|
@@ -12,6 +12,11 @@ import INode from '../node/INode';
|
|
12
12
|
import ICharacterData from '../character-data/ICharacterData';
|
13
13
|
import IDocumentFragment from '../document-fragment/IDocumentFragment';
|
14
14
|
import Selection from '../../selection/Selection';
|
15
|
+
import IHTMLCollection from '../element/IHTMLCollection';
|
16
|
+
import IHTMLScriptElement from '../html-script-element/IHTMLScriptElement';
|
17
|
+
import CSSStyleSheet from '../../css/CSSStyleSheet';
|
18
|
+
import Location from '../../location/Location';
|
19
|
+
import DocumentReadyStateEnum from './DocumentReadyStateEnum';
|
15
20
|
|
16
21
|
/**
|
17
22
|
* Document.
|
@@ -24,7 +29,13 @@ export default interface IDocument extends IParentNode {
|
|
24
29
|
readonly doctype: IDocumentType;
|
25
30
|
readonly body: IHTMLElement;
|
26
31
|
readonly head: IHTMLElement;
|
32
|
+
readonly scripts: IHTMLCollection<IHTMLScriptElement>;
|
27
33
|
readonly activeElement: IHTMLElement;
|
34
|
+
readonly styleSheets: CSSStyleSheet[];
|
35
|
+
readonly scrollingElement: IHTMLElement;
|
36
|
+
readonly location: Location;
|
37
|
+
readonly readyState: DocumentReadyStateEnum;
|
38
|
+
cookie: string;
|
28
39
|
|
29
40
|
/**
|
30
41
|
* Replaces the document HTML with new HTML.
|
@@ -69,7 +80,7 @@ export default interface IDocument extends IParentNode {
|
|
69
80
|
* @param data Text data.
|
70
81
|
* @returns Text node.
|
71
82
|
*/
|
72
|
-
createTextNode(data
|
83
|
+
createTextNode(data?: string): ICharacterData;
|
73
84
|
|
74
85
|
/**
|
75
86
|
* Creates a comment node.
|
@@ -77,7 +88,7 @@ export default interface IDocument extends IParentNode {
|
|
77
88
|
* @param data Text data.
|
78
89
|
* @returns Text node.
|
79
90
|
*/
|
80
|
-
createComment(data
|
91
|
+
createComment(data?: string): ICharacterData;
|
81
92
|
|
82
93
|
/**
|
83
94
|
* Creates a document fragment.
|
@@ -3,7 +3,8 @@ import ShadowRoot from '../shadow-root/ShadowRoot';
|
|
3
3
|
import Attr from '../../attribute/Attr';
|
4
4
|
import DOMRect from './DOMRect';
|
5
5
|
import Range from './Range';
|
6
|
-
import
|
6
|
+
import DOMTokenList from '../../dom-token-list/DOMTokenList';
|
7
|
+
import IDOMTokenList from '../../dom-token-list/IDOMTokenList';
|
7
8
|
import QuerySelector from '../../query-selector/QuerySelector';
|
8
9
|
import SelectorItem from '../../query-selector/SelectorItem';
|
9
10
|
import MutationRecord from '../../mutation-observer/MutationRecord';
|
@@ -36,13 +37,26 @@ export default class Element extends Node implements IElement {
|
|
36
37
|
public tagName: string = null;
|
37
38
|
public nodeType = Node.ELEMENT_NODE;
|
38
39
|
public shadowRoot: IShadowRoot = null;
|
39
|
-
public
|
40
|
+
public _attributes: { [k: string]: Attr } = {};
|
40
41
|
public scrollTop = 0;
|
41
42
|
public scrollLeft = 0;
|
42
43
|
public children: IHTMLCollection<IElement> = HTMLCollectionFactory.create();
|
43
|
-
public _attributes: { [k: string]: Attr } = {};
|
44
44
|
public readonly namespaceURI: string = null;
|
45
45
|
|
46
|
+
private _classList: DOMTokenList = null;
|
47
|
+
|
48
|
+
/**
|
49
|
+
* Returns class list.
|
50
|
+
*
|
51
|
+
* @returns Class list.
|
52
|
+
*/
|
53
|
+
public get classList(): IDOMTokenList {
|
54
|
+
if (!this._classList) {
|
55
|
+
this._classList = new DOMTokenList(this, 'class');
|
56
|
+
}
|
57
|
+
return <IDOMTokenList>this._classList;
|
58
|
+
}
|
59
|
+
|
46
60
|
/**
|
47
61
|
* Returns ID.
|
48
62
|
*
|
@@ -769,6 +783,8 @@ export default class Element extends Node implements IElement {
|
|
769
783
|
|
770
784
|
this._attributes[name] = attribute;
|
771
785
|
|
786
|
+
this._updateDomListIndices();
|
787
|
+
|
772
788
|
if (
|
773
789
|
this.attributeChangedCallback &&
|
774
790
|
(<typeof Element>this.constructor)._observedAttributes &&
|
@@ -842,6 +858,8 @@ export default class Element extends Node implements IElement {
|
|
842
858
|
public removeAttributeNode(attribute: Attr): void {
|
843
859
|
delete this._attributes[attribute.name];
|
844
860
|
|
861
|
+
this._updateDomListIndices();
|
862
|
+
|
845
863
|
if (
|
846
864
|
this.attributeChangedCallback &&
|
847
865
|
(<typeof Element>this.constructor)._observedAttributes &&
|
@@ -933,4 +951,13 @@ export default class Element extends Node implements IElement {
|
|
933
951
|
}
|
934
952
|
return name.toLowerCase();
|
935
953
|
}
|
954
|
+
|
955
|
+
/**
|
956
|
+
* Updates DOM list indices.
|
957
|
+
*/
|
958
|
+
protected _updateDomListIndices(): void {
|
959
|
+
if (this._classList) {
|
960
|
+
this._classList._updateIndices();
|
961
|
+
}
|
962
|
+
}
|
936
963
|
}
|
@@ -2,7 +2,7 @@ import IShadowRoot from '../shadow-root/IShadowRoot';
|
|
2
2
|
import Attr from '../../attribute/Attr';
|
3
3
|
import DOMRect from './DOMRect';
|
4
4
|
import Range from './Range';
|
5
|
-
import
|
5
|
+
import IDOMTokenList from '../../dom-token-list/IDOMTokenList';
|
6
6
|
import INode from './../node/INode';
|
7
7
|
import IChildNode from '../child-node/IChildNode';
|
8
8
|
import IParentNode from '../parent-node/IParentNode';
|
@@ -16,7 +16,7 @@ export type TInsertAdjacentPositions = 'beforebegin' | 'afterbegin' | 'beforeend
|
|
16
16
|
export default interface IElement extends IChildNode, INonDocumentTypeChildNode, IParentNode {
|
17
17
|
readonly tagName: string;
|
18
18
|
readonly shadowRoot: IShadowRoot;
|
19
|
-
readonly classList:
|
19
|
+
readonly classList: IDOMTokenList;
|
20
20
|
readonly namespaceURI: string;
|
21
21
|
scrollTop: number;
|
22
22
|
scrollLeft: number;
|
@@ -10,8 +10,6 @@ import IHTMLLabelElement from './IHTMLLabelElement';
|
|
10
10
|
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement.
|
11
11
|
*/
|
12
12
|
export default class HTMLLabelElement extends HTMLElement implements IHTMLLabelElement {
|
13
|
-
public _htmlFor: string = null;
|
14
|
-
|
15
13
|
/**
|
16
14
|
* Returns a string containing the ID of the labeled control. This reflects the "for" attribute.
|
17
15
|
*
|
@@ -73,8 +71,6 @@ export default class HTMLLabelElement extends HTMLElement implements IHTMLLabelE
|
|
73
71
|
* @returns Cloned node.
|
74
72
|
*/
|
75
73
|
public cloneNode(deep = false): IHTMLLabelElement {
|
76
|
-
|
77
|
-
clone._htmlFor = this._htmlFor;
|
78
|
-
return clone;
|
74
|
+
return <HTMLLabelElement>super.cloneNode(deep);
|
79
75
|
}
|
80
76
|
}
|
@@ -7,6 +7,8 @@ import IHTMLLinkElement from './IHTMLLinkElement';
|
|
7
7
|
import Event from '../../event/Event';
|
8
8
|
import ErrorEvent from '../../event/events/ErrorEvent';
|
9
9
|
import INode from '../../nodes/node/INode';
|
10
|
+
import DOMTokenList from '../../dom-token-list/DOMTokenList';
|
11
|
+
import IDOMTokenList from '../../dom-token-list/IDOMTokenList';
|
10
12
|
|
11
13
|
/**
|
12
14
|
* HTML Link Element.
|
@@ -19,6 +21,19 @@ export default class HTMLLinkElement extends HTMLElement implements IHTMLLinkEle
|
|
19
21
|
public onload: (event: Event) => void = null;
|
20
22
|
public readonly sheet: CSSStyleSheet = null;
|
21
23
|
public _evaluateCSS = true;
|
24
|
+
private _relList: DOMTokenList = null;
|
25
|
+
|
26
|
+
/**
|
27
|
+
* Returns rel list.
|
28
|
+
*
|
29
|
+
* @returns Rel list.
|
30
|
+
*/
|
31
|
+
public get relList(): IDOMTokenList {
|
32
|
+
if (!this._relList) {
|
33
|
+
this._relList = new DOMTokenList(this, 'rel');
|
34
|
+
}
|
35
|
+
return <IDOMTokenList>this._relList;
|
36
|
+
}
|
22
37
|
|
23
38
|
/**
|
24
39
|
* Returns as.
|
@@ -259,4 +274,15 @@ export default class HTMLLinkElement extends HTMLElement implements IHTMLLinkEle
|
|
259
274
|
}
|
260
275
|
}
|
261
276
|
}
|
277
|
+
|
278
|
+
/**
|
279
|
+
* Updates DOM list indices.
|
280
|
+
*/
|
281
|
+
protected _updateDomListIndices(): void {
|
282
|
+
super._updateDomListIndices();
|
283
|
+
|
284
|
+
if (this._relList) {
|
285
|
+
this._relList._updateIndices();
|
286
|
+
}
|
287
|
+
}
|
262
288
|
}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import CSSStyleSheet from '../../css/CSSStyleSheet';
|
2
|
+
import IDOMTokenList from '../../dom-token-list/IDOMTokenList';
|
2
3
|
import IHTMLElement from '../html-element/IHTMLElement';
|
3
4
|
|
4
5
|
/**
|
@@ -9,6 +10,7 @@ import IHTMLElement from '../html-element/IHTMLElement';
|
|
9
10
|
*/
|
10
11
|
export default interface IHTMLLinkElement extends IHTMLElement {
|
11
12
|
readonly sheet: CSSStyleSheet;
|
13
|
+
readonly relList: IDOMTokenList;
|
12
14
|
as: string;
|
13
15
|
crossOrigin: string;
|
14
16
|
href: string;
|
@@ -27,10 +27,11 @@ export default class SelectorItem {
|
|
27
27
|
* @param selector Selector.
|
28
28
|
*/
|
29
29
|
constructor(selector: string) {
|
30
|
+
const isNotPseudo = selector.includes(':not(');
|
31
|
+
|
30
32
|
this.isAll = selector === '*';
|
31
33
|
this.isID = !this.isAll ? selector.startsWith('#') : false;
|
32
|
-
this.isAttribute =
|
33
|
-
!this.isAll && !this.isID && selector.includes('[') && !selector.includes(':not(');
|
34
|
+
this.isAttribute = !this.isAll && !this.isID && selector.includes('[') && !isNotPseudo;
|
34
35
|
this.isPseudo = !this.isAll && !this.isID && selector.includes(':');
|
35
36
|
this.isClass = !this.isAll && !this.isID && new RegExp(CLASS_REGEXP, 'g').test(selector);
|
36
37
|
this.tagName = !this.isAll && !this.isID ? selector.match(TAG_NAME_REGEXP) : null;
|
@@ -48,7 +49,6 @@ export default class SelectorItem {
|
|
48
49
|
*/
|
49
50
|
public match(element: Element): boolean {
|
50
51
|
const selector = this.selector;
|
51
|
-
let match;
|
52
52
|
|
53
53
|
// Is all (*)
|
54
54
|
if (this.isAll) {
|
@@ -68,29 +68,13 @@ export default class SelectorItem {
|
|
68
68
|
}
|
69
69
|
|
70
70
|
// Class match
|
71
|
-
if (this.isClass) {
|
72
|
-
|
73
|
-
|
74
|
-
while ((match = regexp.exec(selector))) {
|
75
|
-
if (!element.classList.contains(match[1])) {
|
76
|
-
return false;
|
77
|
-
}
|
78
|
-
}
|
71
|
+
if (this.isClass && !this.matchesClass(element, selector)) {
|
72
|
+
return false;
|
79
73
|
}
|
80
74
|
|
81
75
|
// Pseudo match
|
82
|
-
if (this.isPseudo) {
|
83
|
-
|
84
|
-
|
85
|
-
while ((match = regexp.exec(selector))) {
|
86
|
-
if (match[1] && !this.matchesNthChild(element, match[1], match[2])) {
|
87
|
-
return false;
|
88
|
-
} else if (match[3] && this.matchesAttribute(element, match[3])) {
|
89
|
-
return false;
|
90
|
-
} else if (match[4] && !this.matchesPsuedo(element, match[4])) {
|
91
|
-
return false;
|
92
|
-
}
|
93
|
-
}
|
76
|
+
if (this.isPseudo && !this.matchesPsuedo(element, selector)) {
|
77
|
+
return false;
|
94
78
|
}
|
95
79
|
|
96
80
|
// Attribute match
|
@@ -101,6 +85,35 @@ export default class SelectorItem {
|
|
101
85
|
return true;
|
102
86
|
}
|
103
87
|
|
88
|
+
/**
|
89
|
+
* Matches a psuedo selector.
|
90
|
+
*
|
91
|
+
* @param element Element.
|
92
|
+
* @param selector Selector.
|
93
|
+
* @returns True if it is a match.
|
94
|
+
*/
|
95
|
+
private matchesPsuedo(element: Element, selector: string): boolean {
|
96
|
+
const regexp = new RegExp(PSUEDO_REGEXP, 'g');
|
97
|
+
let match: RegExpMatchArray;
|
98
|
+
|
99
|
+
while ((match = regexp.exec(selector))) {
|
100
|
+
const isNotClass = match[3] && match[3].trim()[0] === '.';
|
101
|
+
if (match[1] && !this.matchesNthChild(element, match[1], match[2])) {
|
102
|
+
return false;
|
103
|
+
} else if (
|
104
|
+
match[3] &&
|
105
|
+
((isNotClass && this.matchesClass(element, match[3])) ||
|
106
|
+
(!isNotClass && this.matchesAttribute(element, match[3])))
|
107
|
+
) {
|
108
|
+
return false;
|
109
|
+
} else if (match[4] && !this.matchesPsuedoExpression(element, match[4])) {
|
110
|
+
return false;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
return true;
|
115
|
+
}
|
116
|
+
|
104
117
|
/**
|
105
118
|
* Matches a nth-child selector.
|
106
119
|
*
|
@@ -158,13 +171,13 @@ export default class SelectorItem {
|
|
158
171
|
}
|
159
172
|
|
160
173
|
/**
|
161
|
-
* Matches a psuedo selector.
|
174
|
+
* Matches a psuedo selector expression.
|
162
175
|
*
|
163
176
|
* @param element Element.
|
164
177
|
* @param psuedo Psuedo name.
|
165
178
|
* @returns True if it is a match.
|
166
179
|
*/
|
167
|
-
private
|
180
|
+
private matchesPsuedoExpression(element: Element, psuedo: string): boolean {
|
168
181
|
const parent = <Element>element.parentNode;
|
169
182
|
|
170
183
|
if (!parent) {
|
@@ -220,7 +233,7 @@ export default class SelectorItem {
|
|
220
233
|
*/
|
221
234
|
private matchesAttribute(element: Element, selector: string): boolean {
|
222
235
|
const regexp = new RegExp(ATTRIBUTE_REGEXP, 'g');
|
223
|
-
let match;
|
236
|
+
let match: RegExpMatchArray;
|
224
237
|
|
225
238
|
while ((match = regexp.exec(selector))) {
|
226
239
|
const isPsuedo = match.index > 0 && selector[match.index] === '(';
|
@@ -236,6 +249,29 @@ export default class SelectorItem {
|
|
236
249
|
return true;
|
237
250
|
}
|
238
251
|
|
252
|
+
/**
|
253
|
+
* Matches class.
|
254
|
+
*
|
255
|
+
* @param element Element.
|
256
|
+
* @param selector Selector.
|
257
|
+
* @returns True if it is a match.
|
258
|
+
*/
|
259
|
+
private matchesClass(element: Element, selector: string): boolean {
|
260
|
+
const regexp = new RegExp(CLASS_REGEXP, 'g');
|
261
|
+
const classList = element.className.split(' ');
|
262
|
+
let previousIndex = 0;
|
263
|
+
let match: RegExpMatchArray;
|
264
|
+
|
265
|
+
while ((match = regexp.exec(selector)) && match.index === previousIndex) {
|
266
|
+
if (!classList.includes(match[1])) {
|
267
|
+
return false;
|
268
|
+
}
|
269
|
+
previousIndex = match.index + match[0].length - 1;
|
270
|
+
}
|
271
|
+
|
272
|
+
return true;
|
273
|
+
}
|
274
|
+
|
239
275
|
/**
|
240
276
|
* Matches attribute name only.
|
241
277
|
*
|
package/src/window/IWindow.ts
CHANGED
@@ -69,11 +69,12 @@ import URLSearchParams from '../url-search-params/URLSearchParams';
|
|
69
69
|
import HTMLCollection from '../nodes/element/HTMLCollection';
|
70
70
|
import NodeList from '../nodes/node/NodeList';
|
71
71
|
import Selection from '../selection/Selection';
|
72
|
+
import IEventTarget from '../event/IEventTarget';
|
72
73
|
|
73
74
|
/**
|
74
75
|
* Window.
|
75
76
|
*/
|
76
|
-
export default interface IWindow {
|
77
|
+
export default interface IWindow extends IEventTarget {
|
77
78
|
// Public Properties
|
78
79
|
readonly happyDOM: {
|
79
80
|
whenAsyncComplete: () => Promise<void>;
|
@@ -166,6 +167,7 @@ export default interface IWindow {
|
|
166
167
|
readonly top: IWindow;
|
167
168
|
readonly parent: IWindow;
|
168
169
|
readonly window: IWindow;
|
170
|
+
readonly globalThis: IWindow;
|
169
171
|
readonly screen: Screen;
|
170
172
|
readonly innerWidth: number;
|
171
173
|
readonly innerHeight: number;
|
package/src/window/Window.ts
CHANGED
@@ -178,6 +178,7 @@ export default class Window extends EventTarget implements IWindow, NodeJS.Globa
|
|
178
178
|
public readonly top = this;
|
179
179
|
public readonly parent = this;
|
180
180
|
public readonly window = this;
|
181
|
+
public readonly globalThis = this;
|
181
182
|
public readonly screen = new Screen();
|
182
183
|
public readonly innerWidth = 1024;
|
183
184
|
public readonly innerHeight = 768;
|
@@ -1,40 +0,0 @@
|
|
1
|
-
import Element from './Element';
|
2
|
-
/**
|
3
|
-
* Class list.
|
4
|
-
*/
|
5
|
-
export default class ClassList {
|
6
|
-
private _ownerElement;
|
7
|
-
/**
|
8
|
-
* Adds class names.
|
9
|
-
*
|
10
|
-
* @param ownerElement Owner element.
|
11
|
-
*/
|
12
|
-
constructor(ownerElement: Element);
|
13
|
-
/**
|
14
|
-
* Adds class names.
|
15
|
-
*
|
16
|
-
* @param classNames Class names.
|
17
|
-
*/
|
18
|
-
add(...classNames: string[]): void;
|
19
|
-
/**
|
20
|
-
* Adds class names.
|
21
|
-
*
|
22
|
-
* @param classNames Class names.
|
23
|
-
*/
|
24
|
-
remove(...classNames: string[]): void;
|
25
|
-
/**
|
26
|
-
* Check if the list contains a class.
|
27
|
-
*
|
28
|
-
* @param className Class name.
|
29
|
-
* @returns TRUE if it contains.
|
30
|
-
*/
|
31
|
-
contains(className: string): boolean;
|
32
|
-
/**
|
33
|
-
* Toggle a class name.
|
34
|
-
*
|
35
|
-
* @param className A string representing the class name you want to toggle.
|
36
|
-
* @param force If included, turns the toggle into a one way-only operation. If set to `false`, then class name will only be removed, but not added. If set to `true`, then class name will only be added, but not removed.
|
37
|
-
* @returns A boolean value, `true` or `false`, indicating whether class name is in the list after the call or not.
|
38
|
-
*/
|
39
|
-
toggle(className: string, force?: boolean): boolean;
|
40
|
-
}
|