happy-dom 7.5.10 → 7.5.12

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.

Files changed (31) hide show
  1. package/lib/nodes/element/Element.d.ts +1 -13
  2. package/lib/nodes/element/Element.js +0 -12
  3. package/lib/nodes/element/Element.js.map +1 -1
  4. package/lib/nodes/html-option-element/HTMLOptionElement.js +1 -2
  5. package/lib/nodes/html-option-element/HTMLOptionElement.js.map +1 -1
  6. package/lib/nodes/html-option-element/HTMLOptionsCollection.d.ts +11 -5
  7. package/lib/nodes/html-option-element/HTMLOptionsCollection.js +29 -15
  8. package/lib/nodes/html-option-element/HTMLOptionsCollection.js.map +1 -1
  9. package/lib/nodes/html-option-element/IHTMLOptionsCollection.d.ts +6 -0
  10. package/lib/nodes/html-select-element/HTMLSelectElement.d.ts +58 -8
  11. package/lib/nodes/html-select-element/HTMLSelectElement.js +142 -23
  12. package/lib/nodes/html-select-element/HTMLSelectElement.js.map +1 -1
  13. package/lib/nodes/html-select-element/IHTMLSelectElement.d.ts +26 -4
  14. package/lib/nodes/node/Node.d.ts +1 -1
  15. package/lib/nodes/node/Node.js +1 -1
  16. package/package.json +2 -2
  17. package/src/nodes/element/Element.ts +3 -15
  18. package/src/nodes/html-option-element/HTMLOptionElement.ts +1 -2
  19. package/src/nodes/html-option-element/HTMLOptionsCollection.ts +39 -19
  20. package/src/nodes/html-option-element/IHTMLOptionsCollection.ts +7 -0
  21. package/src/nodes/html-select-element/HTMLSelectElement.ts +178 -28
  22. package/src/nodes/html-select-element/IHTMLSelectElement.ts +32 -4
  23. package/src/nodes/node/Node.ts +1 -1
  24. package/lib/nodes/html-option-element/HTMLOptionElementValueSanitizer.d.ts +0 -11
  25. package/lib/nodes/html-option-element/HTMLOptionElementValueSanitizer.js +0 -18
  26. package/lib/nodes/html-option-element/HTMLOptionElementValueSanitizer.js.map +0 -1
  27. package/lib/nodes/html-select-element/HTMLSelectElementValueSanitizer.d.ts +0 -11
  28. package/lib/nodes/html-select-element/HTMLSelectElementValueSanitizer.js +0 -18
  29. package/lib/nodes/html-select-element/HTMLSelectElementValueSanitizer.js.map +0 -1
  30. package/src/nodes/html-option-element/HTMLOptionElementValueSanitizer.ts +0 -15
  31. package/src/nodes/html-select-element/HTMLSelectElementValueSanitizer.ts +0 -15
@@ -5,14 +5,16 @@ import IHTMLElement from '../html-element/IHTMLElement';
5
5
  import IHTMLFormElement from '../html-form-element/IHTMLFormElement';
6
6
  import ValidityState from '../validity-state/ValidityState';
7
7
  import IHTMLLabelElement from '../html-label-element/IHTMLLabelElement';
8
- import HTMLOptGroupElement from '../html-opt-group-element/HTMLOptGroupElement';
9
8
  import HTMLOptionElement from '../html-option-element/HTMLOptionElement';
10
9
  import HTMLOptionsCollection from '../html-option-element/HTMLOptionsCollection';
11
- import IHTMLOptionsCollection from '../html-option-element/IHTMLOptionsCollection';
12
10
  import INodeList from '../node/INodeList';
13
- import HTMLSelectElementValueSanitizer from './HTMLSelectElementValueSanitizer';
14
11
  import IHTMLSelectElement from './IHTMLSelectElement';
15
12
  import Event from '../../event/Event';
13
+ import IHTMLOptionElement from '../html-option-element/IHTMLOptionElement';
14
+ import IHTMLOptGroupElement from '../html-opt-group-element/IHTMLOptGroupElement';
15
+ import IHTMLOptionsCollection from '../html-option-element/IHTMLOptionsCollection';
16
+ import INode from '../node/INode';
17
+ import NodeTypeEnum from '../node/NodeTypeEnum';
16
18
 
17
19
  /**
18
20
  * HTML Select Element.
@@ -21,17 +23,13 @@ import Event from '../../event/Event';
21
23
  * https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement.
22
24
  */
23
25
  export default class HTMLSelectElement extends HTMLElement implements IHTMLSelectElement {
24
- public type: string;
25
26
  public labels: INodeList<IHTMLLabelElement>;
27
+ public readonly options: IHTMLOptionsCollection = new HTMLOptionsCollection(this);
26
28
 
27
29
  // Events
28
30
  public onchange: (event: Event) => void | null = null;
29
31
  public oninput: (event: Event) => void | null = null;
30
32
 
31
- public _value = null;
32
- public _selectedIndex = -1;
33
- public _options: IHTMLOptionsCollection = null;
34
-
35
33
  /**
36
34
  * Returns name.
37
35
  *
@@ -116,6 +114,24 @@ export default class HTMLSelectElement extends HTMLElement implements IHTMLSelec
116
114
  }
117
115
  }
118
116
 
117
+ /**
118
+ * Returns length.
119
+ *
120
+ * @returns length.
121
+ */
122
+ public get length(): number {
123
+ return this.options.length;
124
+ }
125
+
126
+ /**
127
+ * Sets length.
128
+ *
129
+ * @param length Length.
130
+ */
131
+ public set length(length: number) {
132
+ this.options.length = length;
133
+ }
134
+
119
135
  /**
120
136
  * Returns required.
121
137
  *
@@ -138,13 +154,28 @@ export default class HTMLSelectElement extends HTMLElement implements IHTMLSelec
138
154
  }
139
155
  }
140
156
 
157
+ /**
158
+ * Returns type.
159
+ *
160
+ * @returns type.
161
+ */
162
+ public get type(): string {
163
+ return this.hasAttributeNS(null, 'multiple') ? 'select-multiple' : 'select-one';
164
+ }
165
+
141
166
  /**
142
167
  * Returns value.
143
168
  *
144
169
  * @returns Value.
145
170
  */
146
171
  public get value(): string {
147
- return this._value;
172
+ if (this.options.selectedIndex === -1) {
173
+ return '';
174
+ }
175
+
176
+ const option = this.options[this.options.selectedIndex];
177
+
178
+ return option instanceof HTMLOptionElement ? option.value : '';
148
179
  }
149
180
 
150
181
  /**
@@ -153,12 +184,9 @@ export default class HTMLSelectElement extends HTMLElement implements IHTMLSelec
153
184
  * @param value Value.
154
185
  */
155
186
  public set value(value: string) {
156
- this._value = HTMLSelectElementValueSanitizer.sanitize(value);
157
-
158
- const idx = this.options.findIndex((o) => o.nodeValue === value);
159
- if (idx > -1) {
160
- this._selectedIndex = idx;
161
- }
187
+ this.options.selectedIndex = this.options.findIndex(
188
+ (o) => o instanceof HTMLOptionElement && o.value === value
189
+ );
162
190
  }
163
191
 
164
192
  /**
@@ -167,7 +195,7 @@ export default class HTMLSelectElement extends HTMLElement implements IHTMLSelec
167
195
  * @returns Value.
168
196
  */
169
197
  public get selectedIndex(): number {
170
- return this._options ? this._options.selectedIndex : -1;
198
+ return this.options.selectedIndex;
171
199
  }
172
200
 
173
201
  /**
@@ -176,14 +204,14 @@ export default class HTMLSelectElement extends HTMLElement implements IHTMLSelec
176
204
  * @param value Value.
177
205
  */
178
206
  public set selectedIndex(value: number) {
179
- if (value > this.options.length - 1 || value < 0) {
207
+ if (value > this.options.length - 1 || value < -1) {
180
208
  throw new DOMException(
181
209
  'Select elements selected index must be valid',
182
210
  DOMExceptionNameEnum.indexSizeError
183
211
  );
184
212
  }
185
213
 
186
- this._options.selectedIndex = value;
214
+ this.options.selectedIndex = value;
187
215
  }
188
216
 
189
217
  /**
@@ -224,21 +252,143 @@ export default class HTMLSelectElement extends HTMLElement implements IHTMLSelec
224
252
  }
225
253
 
226
254
  /**
227
- * Returns options.
255
+ * Returns item from options collection by index.
256
+ *
257
+ * @param index Index.
258
+ */
259
+ public item(index: number): IHTMLOptionElement | IHTMLOptGroupElement {
260
+ return this.options.item(index);
261
+ }
262
+
263
+ /**
264
+ * Adds new option to options collection.
228
265
  *
229
- * @returns Options.
266
+ * @param element HTMLOptionElement or HTMLOptGroupElement to add.
267
+ * @param before HTMLOptionElement or index number.
268
+ */
269
+ public add(
270
+ element: IHTMLOptionElement | IHTMLOptGroupElement,
271
+ before?: number | IHTMLOptionElement | IHTMLOptGroupElement
272
+ ): void {
273
+ this.options.add(element, before);
274
+ }
275
+
276
+ /**
277
+ * Removes indexed element from collection or the select element.
278
+ *
279
+ * @param [index] Index.
280
+ */
281
+ public override remove(index?: number): void {
282
+ if (typeof index === 'number') {
283
+ this.options.remove(index);
284
+ } else {
285
+ super.remove();
286
+ }
287
+ }
288
+
289
+ /**
290
+ * @override
291
+ */
292
+ public override appendChild(node: INode): INode {
293
+ if (node.nodeType === NodeTypeEnum.elementNode) {
294
+ const element = <IHTMLElement>node;
295
+ const previousLength = this.options.length;
296
+
297
+ if (element.tagName === 'OPTION' || element.tagName === 'OPTGROUP') {
298
+ this.options.push(<IHTMLOptionElement | IHTMLOptGroupElement>element);
299
+ }
300
+
301
+ this._updateIndexProperties(previousLength, this.options.length);
302
+ }
303
+
304
+ return super.appendChild(node);
305
+ }
306
+
307
+ /**
308
+ * @override
309
+ */
310
+ public override insertBefore(newNode: INode, referenceNode: INode | null): INode {
311
+ const returnValue = super.insertBefore(newNode, referenceNode);
312
+
313
+ if (
314
+ newNode.nodeType === NodeTypeEnum.elementNode &&
315
+ referenceNode?.nodeType === NodeTypeEnum.elementNode
316
+ ) {
317
+ const newElement = <IHTMLElement>newNode;
318
+ const previousLength = this.options.length;
319
+
320
+ if (newElement.tagName === 'OPTION' || newElement.tagName === 'OPTGROUP') {
321
+ const referenceElement = <IHTMLElement>referenceNode;
322
+
323
+ if (
324
+ referenceElement &&
325
+ (referenceElement.tagName === 'OPTION' || referenceElement.tagName === 'OPTGROUP')
326
+ ) {
327
+ const referenceIndex = this.options.indexOf(
328
+ <IHTMLOptGroupElement | IHTMLOptionElement>referenceElement
329
+ );
330
+ if (referenceIndex !== -1) {
331
+ this.options.splice(
332
+ referenceIndex,
333
+ 0,
334
+ <IHTMLOptionElement | IHTMLOptGroupElement>newElement
335
+ );
336
+ }
337
+ } else {
338
+ this.options.push(<IHTMLOptionElement | IHTMLOptGroupElement>newElement);
339
+ }
340
+ }
341
+
342
+ this._updateIndexProperties(previousLength, this.options.length);
343
+ }
344
+
345
+ return returnValue;
346
+ }
347
+
348
+ /**
349
+ * @override
230
350
  */
231
- public get options(): IHTMLOptionsCollection {
232
- if (this._options === null) {
233
- this._options = new HTMLOptionsCollection();
234
- const childs = <INodeList<IHTMLElement>>this.childNodes;
235
- for (const child of childs) {
236
- if (child.tagName === 'OPTION') {
237
- this._options.add(<HTMLOptionElement | HTMLOptGroupElement>child);
351
+ public override removeChild(node: INode): INode {
352
+ if (node.nodeType === NodeTypeEnum.elementNode) {
353
+ const element = <IHTMLElement>node;
354
+ const previousLength = this.options.length;
355
+
356
+ if (element.tagName === 'OPTION' || element.tagName === 'OPTION') {
357
+ const index = this.options.indexOf(<IHTMLOptionElement | IHTMLOptGroupElement>node);
358
+ if (index !== -1) {
359
+ this.options.splice(index, 1);
238
360
  }
239
361
  }
362
+
363
+ this._updateIndexProperties(previousLength, this.options.length);
240
364
  }
241
365
 
242
- return this._options;
366
+ return super.removeChild(node);
367
+ }
368
+
369
+ /**
370
+ * Updates index properties.
371
+ *
372
+ * @param previousLength Length before the update.
373
+ * @param newLength Length after the update.
374
+ */
375
+ protected _updateIndexProperties(previousLength: number, newLength: number): void {
376
+ if (previousLength > newLength) {
377
+ for (let i = newLength; i < previousLength; i++) {
378
+ if (this.hasOwnProperty(String(i))) {
379
+ delete this[String(i)];
380
+ }
381
+ }
382
+ } else if (previousLength < newLength) {
383
+ for (let i = previousLength; i < newLength; i++) {
384
+ Object.defineProperty(this, String(i), {
385
+ get: () => {
386
+ return this.options[i];
387
+ },
388
+ enumerable: true,
389
+ configurable: true
390
+ });
391
+ }
392
+ }
243
393
  }
244
394
  }
@@ -5,6 +5,8 @@ import INodeList from '../node/INodeList';
5
5
  import IHTMLOptionsCollection from '../html-option-element/IHTMLOptionsCollection';
6
6
  import ValidityState from '../validity-state/ValidityState';
7
7
  import Event from '../../event/Event';
8
+ import IHTMLOptionElement from '../html-option-element/IHTMLOptionElement';
9
+ import IHTMLOptGroupElement from '../html-opt-group-element/IHTMLOptGroupElement';
8
10
 
9
11
  /**
10
12
  * HTML Select Element.
@@ -15,18 +17,44 @@ import Event from '../../event/Event';
15
17
  export default interface IHTMLSelectElement extends IHTMLElement {
16
18
  readonly form: IHTMLFormElement;
17
19
  readonly labels: INodeList<IHTMLLabelElement>;
18
- type: string;
20
+ readonly options: IHTMLOptionsCollection;
21
+ readonly type: string;
22
+ readonly validity: ValidityState;
23
+ readonly willValidate: boolean;
19
24
  autofocus: boolean;
20
25
  disabled: boolean;
21
- options: IHTMLOptionsCollection;
26
+ length: number;
22
27
  selectedIndex: number;
23
- validity: ValidityState;
24
28
  value: string;
25
- willValidate: boolean;
26
29
  name: string;
27
30
  multiple: boolean;
28
31
 
29
32
  // Events
30
33
  onchange: (event: Event) => void | null;
31
34
  oninput: (event: Event) => void | null;
35
+
36
+ /**
37
+ * Adds new option to collection.
38
+ *
39
+ * @param element HTMLOptionElement or HTMLOptGroupElement to add.
40
+ * @param before HTMLOptionElement or index number.
41
+ */
42
+ add(
43
+ element: IHTMLOptionElement | IHTMLOptGroupElement,
44
+ before?: number | IHTMLOptionElement | IHTMLOptGroupElement
45
+ ): void;
46
+
47
+ /**
48
+ * Returns option element by index.
49
+ *
50
+ * @param index Index.
51
+ */
52
+ item(index: number): IHTMLOptionElement | IHTMLOptGroupElement;
53
+
54
+ /**
55
+ * Removes option element from the collection.
56
+ *
57
+ * @param index Index.
58
+ */
59
+ remove(index?: number): void;
32
60
  }
@@ -388,7 +388,7 @@ export default class Node extends EventTarget implements INode {
388
388
  * Inserts a node before another.
389
389
  *
390
390
  * @param newNode Node to insert.
391
- * @param [referenceNode] Node to insert before.
391
+ * @param referenceNode Node to insert before.
392
392
  * @returns Inserted node.
393
393
  */
394
394
  public insertBefore(newNode: INode, referenceNode: INode | null): INode {
@@ -1,11 +0,0 @@
1
- /**
2
- * HTML select element value sanitizer.
3
- */
4
- export default class HTMLOptionElementValueSanitizer {
5
- /**
6
- * Sanitizes a value.
7
- *
8
- * @param value Value.
9
- */
10
- static sanitize(value: string): string;
11
- }
@@ -1,18 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const NEW_LINES_REGEXP = /[\n\r]/gm;
4
- /**
5
- * HTML select element value sanitizer.
6
- */
7
- class HTMLOptionElementValueSanitizer {
8
- /**
9
- * Sanitizes a value.
10
- *
11
- * @param value Value.
12
- */
13
- static sanitize(value) {
14
- return value.trim().replace(NEW_LINES_REGEXP, '');
15
- }
16
- }
17
- exports.default = HTMLOptionElementValueSanitizer;
18
- //# sourceMappingURL=HTMLOptionElementValueSanitizer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"HTMLOptionElementValueSanitizer.js","sourceRoot":"","sources":["../../../src/nodes/html-option-element/HTMLOptionElementValueSanitizer.ts"],"names":[],"mappings":";;AAAA,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAEpC;;GAEG;AACH,MAAqB,+BAA+B;IACnD;;;;OAIG;IACI,MAAM,CAAC,QAAQ,CAAC,KAAa;QACnC,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;IACnD,CAAC;CACD;AATD,kDASC"}
@@ -1,11 +0,0 @@
1
- /**
2
- * HTML select element value sanitizer.
3
- */
4
- export default class HTMLSelectElementValueSanitizer {
5
- /**
6
- * Sanitizes a value.
7
- *
8
- * @param value Value.
9
- */
10
- static sanitize(value: string): string;
11
- }
@@ -1,18 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const NEW_LINES_REGEXP = /[\n\r]/gm;
4
- /**
5
- * HTML select element value sanitizer.
6
- */
7
- class HTMLSelectElementValueSanitizer {
8
- /**
9
- * Sanitizes a value.
10
- *
11
- * @param value Value.
12
- */
13
- static sanitize(value) {
14
- return value.replace(NEW_LINES_REGEXP, '');
15
- }
16
- }
17
- exports.default = HTMLSelectElementValueSanitizer;
18
- //# sourceMappingURL=HTMLSelectElementValueSanitizer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"HTMLSelectElementValueSanitizer.js","sourceRoot":"","sources":["../../../src/nodes/html-select-element/HTMLSelectElementValueSanitizer.ts"],"names":[],"mappings":";;AAAA,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAEpC;;GAEG;AACH,MAAqB,+BAA+B;IACnD;;;;OAIG;IACI,MAAM,CAAC,QAAQ,CAAC,KAAa;QACnC,OAAO,KAAK,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;IAC5C,CAAC;CACD;AATD,kDASC"}
@@ -1,15 +0,0 @@
1
- const NEW_LINES_REGEXP = /[\n\r]/gm;
2
-
3
- /**
4
- * HTML select element value sanitizer.
5
- */
6
- export default class HTMLOptionElementValueSanitizer {
7
- /**
8
- * Sanitizes a value.
9
- *
10
- * @param value Value.
11
- */
12
- public static sanitize(value: string): string {
13
- return value.trim().replace(NEW_LINES_REGEXP, '');
14
- }
15
- }
@@ -1,15 +0,0 @@
1
- const NEW_LINES_REGEXP = /[\n\r]/gm;
2
-
3
- /**
4
- * HTML select element value sanitizer.
5
- */
6
- export default class HTMLSelectElementValueSanitizer {
7
- /**
8
- * Sanitizes a value.
9
- *
10
- * @param value Value.
11
- */
12
- public static sanitize(value: string): string {
13
- return value.replace(NEW_LINES_REGEXP, '');
14
- }
15
- }