happy-dom 7.6.4 → 7.6.6
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/nodes/element/Element.d.ts +4 -2
- package/lib/nodes/element/Element.js +8 -1
- package/lib/nodes/element/Element.js.map +1 -1
- package/lib/nodes/element/IElement.d.ts +4 -2
- package/lib/nodes/html-element/HTMLElement.d.ts +1 -12
- package/lib/nodes/html-element/HTMLElement.js +1 -11
- package/lib/nodes/html-element/HTMLElement.js.map +1 -1
- package/lib/nodes/html-option-element/HTMLOptionElement.d.ts +17 -0
- package/lib/nodes/html-option-element/HTMLOptionElement.js +55 -32
- package/lib/nodes/html-option-element/HTMLOptionElement.js.map +1 -1
- package/lib/nodes/html-option-element/HTMLOptionsCollection.d.ts +0 -1
- package/lib/nodes/html-option-element/HTMLOptionsCollection.js +2 -10
- package/lib/nodes/html-option-element/HTMLOptionsCollection.js.map +1 -1
- package/lib/nodes/html-select-element/HTMLSelectElement.d.ts +18 -2
- package/lib/nodes/html-select-element/HTMLSelectElement.js +99 -22
- package/lib/nodes/html-select-element/HTMLSelectElement.js.map +1 -1
- package/lib/nodes/svg-element/SVGElement.d.ts +1 -8
- package/lib/nodes/svg-element/SVGElement.js +1 -7
- package/lib/nodes/svg-element/SVGElement.js.map +1 -1
- package/lib/xml-parser/XMLParser.js +57 -54
- package/lib/xml-parser/XMLParser.js.map +1 -1
- package/package.json +2 -2
- package/src/nodes/element/Element.ts +15 -3
- package/src/nodes/element/IElement.ts +4 -2
- package/src/nodes/html-element/HTMLElement.ts +3 -12
- package/src/nodes/html-option-element/HTMLOptionElement.ts +69 -35
- package/src/nodes/html-option-element/HTMLOptionsCollection.ts +2 -9
- package/src/nodes/html-select-element/HTMLSelectElement.ts +109 -27
- package/src/nodes/svg-element/SVGElement.ts +3 -8
- package/src/xml-parser/XMLParser.ts +62 -58
@@ -1,7 +1,8 @@
|
|
1
|
+
import IAttr from '../attr/IAttr';
|
1
2
|
import HTMLElement from '../html-element/HTMLElement';
|
2
3
|
import IHTMLElement from '../html-element/IHTMLElement';
|
3
4
|
import IHTMLFormElement from '../html-form-element/IHTMLFormElement';
|
4
|
-
import
|
5
|
+
import HTMLSelectElement from '../html-select-element/HTMLSelectElement';
|
5
6
|
import IHTMLOptionElement from './IHTMLOptionElement';
|
6
7
|
|
7
8
|
/**
|
@@ -12,6 +13,8 @@ import IHTMLOptionElement from './IHTMLOptionElement';
|
|
12
13
|
*/
|
13
14
|
export default class HTMLOptionElement extends HTMLElement implements IHTMLOptionElement {
|
14
15
|
public _index: number;
|
16
|
+
public _selectedness = false;
|
17
|
+
public _dirtyness = false;
|
15
18
|
|
16
19
|
/**
|
17
20
|
* Returns inner text, which is the rendered appearance of text.
|
@@ -59,20 +62,7 @@ export default class HTMLOptionElement extends HTMLElement implements IHTMLOptio
|
|
59
62
|
* @returns Selected.
|
60
63
|
*/
|
61
64
|
public get selected(): boolean {
|
62
|
-
|
63
|
-
|
64
|
-
if (parentNode?.tagName === 'SELECT') {
|
65
|
-
let index = -1;
|
66
|
-
for (let i = 0; i < parentNode.options.length; i++) {
|
67
|
-
if (parentNode.options[i] === this) {
|
68
|
-
index = i;
|
69
|
-
break;
|
70
|
-
}
|
71
|
-
}
|
72
|
-
return index !== -1 && parentNode.options.selectedIndex === index;
|
73
|
-
}
|
74
|
-
|
75
|
-
return false;
|
65
|
+
return this._selectedness;
|
76
66
|
}
|
77
67
|
|
78
68
|
/**
|
@@ -81,26 +71,13 @@ export default class HTMLOptionElement extends HTMLElement implements IHTMLOptio
|
|
81
71
|
* @param selected Selected.
|
82
72
|
*/
|
83
73
|
public set selected(selected: boolean) {
|
84
|
-
const
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
index = i;
|
92
|
-
break;
|
93
|
-
}
|
94
|
-
}
|
95
|
-
|
96
|
-
if (index !== -1) {
|
97
|
-
parentNode.options.selectedIndex = index;
|
98
|
-
}
|
99
|
-
} else if (parentNode.options.length) {
|
100
|
-
parentNode.options.selectedIndex = 0;
|
101
|
-
} else {
|
102
|
-
parentNode.options.selectedIndex = -1;
|
103
|
-
}
|
74
|
+
const selectElement = this._getSelectElement();
|
75
|
+
|
76
|
+
this._dirtyness = true;
|
77
|
+
this._selectedness = Boolean(selected);
|
78
|
+
|
79
|
+
if (selectElement) {
|
80
|
+
selectElement._resetOptionSelectednes(this._selectedness ? this : null);
|
104
81
|
}
|
105
82
|
}
|
106
83
|
|
@@ -143,4 +120,61 @@ export default class HTMLOptionElement extends HTMLElement implements IHTMLOptio
|
|
143
120
|
public set value(value: string) {
|
144
121
|
this.setAttributeNS(null, 'value', value);
|
145
122
|
}
|
123
|
+
|
124
|
+
/**
|
125
|
+
* @override
|
126
|
+
*/
|
127
|
+
public setAttributeNode(attribute: IAttr): IAttr {
|
128
|
+
const replacedAttribute = super.setAttributeNode(attribute);
|
129
|
+
|
130
|
+
if (
|
131
|
+
!this._dirtyness &&
|
132
|
+
attribute.name === 'selected' &&
|
133
|
+
replacedAttribute?.value !== attribute.value
|
134
|
+
) {
|
135
|
+
const selectElement = this._getSelectElement();
|
136
|
+
|
137
|
+
this._selectedness = true;
|
138
|
+
|
139
|
+
if (selectElement) {
|
140
|
+
selectElement._resetOptionSelectednes(this);
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
return replacedAttribute;
|
145
|
+
}
|
146
|
+
|
147
|
+
/**
|
148
|
+
* @override
|
149
|
+
*/
|
150
|
+
public removeAttributeNode(attribute: IAttr): IAttr {
|
151
|
+
super.removeAttributeNode(attribute);
|
152
|
+
|
153
|
+
if (!this._dirtyness && attribute.name === 'selected') {
|
154
|
+
const selectElement = this._getSelectElement();
|
155
|
+
|
156
|
+
this._selectedness = false;
|
157
|
+
|
158
|
+
if (selectElement) {
|
159
|
+
selectElement._resetOptionSelectednes();
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
return attribute;
|
164
|
+
}
|
165
|
+
|
166
|
+
/**
|
167
|
+
* Returns select element.
|
168
|
+
*
|
169
|
+
* @returns Select element.
|
170
|
+
*/
|
171
|
+
private _getSelectElement(): HTMLSelectElement {
|
172
|
+
const parentNode = <HTMLSelectElement>this.parentNode;
|
173
|
+
if (parentNode?.tagName === 'SELECT') {
|
174
|
+
return <HTMLSelectElement>parentNode;
|
175
|
+
}
|
176
|
+
if ((<HTMLSelectElement>parentNode?.parentNode)?.tagName === 'SELECT') {
|
177
|
+
return <HTMLSelectElement>parentNode.parentNode;
|
178
|
+
}
|
179
|
+
}
|
146
180
|
}
|
@@ -16,7 +16,6 @@ export default class HTMLOptionsCollection
|
|
16
16
|
implements IHTMLOptionsCollection
|
17
17
|
{
|
18
18
|
private _selectElement: IHTMLSelectElement;
|
19
|
-
private _selectedIndex = -1;
|
20
19
|
|
21
20
|
/**
|
22
21
|
*
|
@@ -34,7 +33,7 @@ export default class HTMLOptionsCollection
|
|
34
33
|
* @returns SelectedIndex.
|
35
34
|
*/
|
36
35
|
public get selectedIndex(): number {
|
37
|
-
return this.
|
36
|
+
return this._selectElement.selectedIndex;
|
38
37
|
}
|
39
38
|
|
40
39
|
/**
|
@@ -43,13 +42,7 @@ export default class HTMLOptionsCollection
|
|
43
42
|
* @param selectedIndex SelectedIndex.
|
44
43
|
*/
|
45
44
|
public set selectedIndex(selectedIndex: number) {
|
46
|
-
|
47
|
-
if (selectedIndex >= 0 && selectedIndex < this.length) {
|
48
|
-
this._selectedIndex = selectedIndex;
|
49
|
-
} else {
|
50
|
-
this._selectedIndex = -1;
|
51
|
-
}
|
52
|
-
}
|
45
|
+
this._selectElement.selectedIndex = selectedIndex;
|
53
46
|
}
|
54
47
|
|
55
48
|
/**
|
@@ -167,13 +167,14 @@ export default class HTMLSelectElement extends HTMLElement implements IHTMLSelec
|
|
167
167
|
* @returns Value.
|
168
168
|
*/
|
169
169
|
public get value(): string {
|
170
|
-
|
171
|
-
|
170
|
+
for (let i = 0, max = this.options.length; i < max; i++) {
|
171
|
+
const option = <HTMLOptionElement>this.options[i];
|
172
|
+
if (option._selectedness) {
|
173
|
+
return option.value;
|
174
|
+
}
|
172
175
|
}
|
173
176
|
|
174
|
-
|
175
|
-
|
176
|
-
return option instanceof HTMLOptionElement ? option.value : '';
|
177
|
+
return '';
|
177
178
|
}
|
178
179
|
|
179
180
|
/**
|
@@ -182,9 +183,15 @@ export default class HTMLSelectElement extends HTMLElement implements IHTMLSelec
|
|
182
183
|
* @param value Value.
|
183
184
|
*/
|
184
185
|
public set value(value: string) {
|
185
|
-
|
186
|
-
|
187
|
-
|
186
|
+
for (let i = 0, max = this.options.length; i < max; i++) {
|
187
|
+
const option = <HTMLOptionElement>this.options[i];
|
188
|
+
if (option.value === value) {
|
189
|
+
option._selectedness = true;
|
190
|
+
option._dirtyness = true;
|
191
|
+
} else {
|
192
|
+
option._selectedness = false;
|
193
|
+
}
|
194
|
+
}
|
188
195
|
}
|
189
196
|
|
190
197
|
/**
|
@@ -193,16 +200,31 @@ export default class HTMLSelectElement extends HTMLElement implements IHTMLSelec
|
|
193
200
|
* @returns Value.
|
194
201
|
*/
|
195
202
|
public get selectedIndex(): number {
|
196
|
-
|
203
|
+
for (let i = 0, max = this.options.length; i < max; i++) {
|
204
|
+
if ((<HTMLOptionElement>this.options[i])._selectedness) {
|
205
|
+
return i;
|
206
|
+
}
|
207
|
+
}
|
208
|
+
return -1;
|
197
209
|
}
|
198
210
|
|
199
211
|
/**
|
200
212
|
* Sets value.
|
201
213
|
*
|
202
|
-
* @param
|
214
|
+
* @param selectedIndex Selected index.
|
203
215
|
*/
|
204
|
-
public set selectedIndex(
|
205
|
-
|
216
|
+
public set selectedIndex(selectedIndex: number) {
|
217
|
+
if (typeof selectedIndex === 'number' && !isNaN(selectedIndex)) {
|
218
|
+
for (let i = 0, max = this.options.length; i < max; i++) {
|
219
|
+
(<HTMLOptionElement>this.options[i])._selectedness = false;
|
220
|
+
}
|
221
|
+
|
222
|
+
const selectedOption = <HTMLOptionElement>this.options[selectedIndex];
|
223
|
+
if (selectedOption) {
|
224
|
+
selectedOption._selectedness = true;
|
225
|
+
selectedOption._dirtyness = true;
|
226
|
+
}
|
227
|
+
}
|
206
228
|
}
|
207
229
|
|
208
230
|
/**
|
@@ -287,13 +309,10 @@ export default class HTMLSelectElement extends HTMLElement implements IHTMLSelec
|
|
287
309
|
|
288
310
|
if (element.tagName === 'OPTION' || element.tagName === 'OPTGROUP') {
|
289
311
|
this.options.push(<IHTMLOptionElement | IHTMLOptGroupElement>element);
|
290
|
-
|
291
|
-
if (this.options.length === 1) {
|
292
|
-
this.options.selectedIndex = 0;
|
293
|
-
}
|
294
312
|
}
|
295
313
|
|
296
314
|
this._updateIndexProperties(previousLength, this.options.length);
|
315
|
+
this._resetOptionSelectednes();
|
297
316
|
}
|
298
317
|
|
299
318
|
return super.appendChild(node);
|
@@ -332,15 +351,15 @@ export default class HTMLSelectElement extends HTMLElement implements IHTMLSelec
|
|
332
351
|
} else {
|
333
352
|
this.options.push(<IHTMLOptionElement | IHTMLOptGroupElement>newElement);
|
334
353
|
}
|
335
|
-
|
336
|
-
if (this.options.length === 1) {
|
337
|
-
this.options.selectedIndex = 0;
|
338
|
-
}
|
339
354
|
}
|
340
355
|
|
341
356
|
this._updateIndexProperties(previousLength, this.options.length);
|
342
357
|
}
|
343
358
|
|
359
|
+
if (newNode.nodeType === NodeTypeEnum.elementNode) {
|
360
|
+
this._resetOptionSelectednes();
|
361
|
+
}
|
362
|
+
|
344
363
|
return returnValue;
|
345
364
|
}
|
346
365
|
|
@@ -358,20 +377,83 @@ export default class HTMLSelectElement extends HTMLElement implements IHTMLSelec
|
|
358
377
|
if (index !== -1) {
|
359
378
|
this.options.splice(index, 1);
|
360
379
|
}
|
380
|
+
}
|
361
381
|
|
362
|
-
|
363
|
-
|
382
|
+
this._updateIndexProperties(previousLength, this.options.length);
|
383
|
+
this._resetOptionSelectednes();
|
384
|
+
}
|
385
|
+
|
386
|
+
return super.removeChild(node);
|
387
|
+
}
|
388
|
+
|
389
|
+
/**
|
390
|
+
* Resets the option selectedness.
|
391
|
+
*
|
392
|
+
* Based on:
|
393
|
+
* https://github.com/jsdom/jsdom/blob/master/lib/jsdom/living/nodes/HTMLSelectElement-impl.js
|
394
|
+
*
|
395
|
+
* @param [newOption] Optional new option element to be selected.
|
396
|
+
* @see https://html.spec.whatwg.org/multipage/form-elements.html#selectedness-setting-algorithm
|
397
|
+
*/
|
398
|
+
public _resetOptionSelectednes(newOption?: IHTMLOptionElement): void {
|
399
|
+
if (this.hasAttributeNS(null, 'multiple')) {
|
400
|
+
return;
|
401
|
+
}
|
402
|
+
|
403
|
+
const selected: HTMLOptionElement[] = [];
|
404
|
+
|
405
|
+
for (let i = 0, max = this.options.length; i < max; i++) {
|
406
|
+
if (newOption) {
|
407
|
+
(<HTMLOptionElement>this.options[i])._selectedness = this.options[i] === newOption;
|
408
|
+
}
|
409
|
+
|
410
|
+
if ((<HTMLOptionElement>this.options[i])._selectedness) {
|
411
|
+
selected.push(<HTMLOptionElement>this.options[i]);
|
412
|
+
}
|
413
|
+
}
|
414
|
+
|
415
|
+
const size = this._getDisplaySize();
|
416
|
+
|
417
|
+
if (size === 1 && !selected.length) {
|
418
|
+
for (let i = 0, max = this.options.length; i < max; i++) {
|
419
|
+
const option = <HTMLOptionElement>this.options[i];
|
420
|
+
|
421
|
+
let disabled = option.hasAttributeNS(null, 'disabled');
|
422
|
+
const parentNode = <IHTMLElement>option.parentNode;
|
423
|
+
if (
|
424
|
+
parentNode &&
|
425
|
+
parentNode.nodeType === NodeTypeEnum.elementNode &&
|
426
|
+
parentNode.tagName === 'OPTGROUP' &&
|
427
|
+
parentNode.hasAttributeNS(null, 'disabled')
|
428
|
+
) {
|
429
|
+
disabled = true;
|
364
430
|
}
|
365
431
|
|
366
|
-
if (!
|
367
|
-
|
432
|
+
if (!disabled) {
|
433
|
+
option._selectedness = true;
|
434
|
+
break;
|
368
435
|
}
|
369
436
|
}
|
370
|
-
|
371
|
-
|
437
|
+
} else if (selected.length >= 2) {
|
438
|
+
for (let i = 0, max = this.options.length; i < max; i++) {
|
439
|
+
(<HTMLOptionElement>this.options[i])._selectedness = i === selected.length - 1;
|
440
|
+
}
|
372
441
|
}
|
442
|
+
}
|
373
443
|
|
374
|
-
|
444
|
+
/**
|
445
|
+
* Returns display size.
|
446
|
+
*
|
447
|
+
* @returns Display size.
|
448
|
+
*/
|
449
|
+
protected _getDisplaySize(): number {
|
450
|
+
if (this.hasAttributeNS(null, 'size')) {
|
451
|
+
const size = parseInt(this.getAttributeNS(null, 'size'));
|
452
|
+
if (!isNaN(size) && size >= 0) {
|
453
|
+
return size;
|
454
|
+
}
|
455
|
+
}
|
456
|
+
return this.hasAttributeNS(null, 'multiple') ? 4 : 1;
|
375
457
|
}
|
376
458
|
|
377
459
|
/**
|
@@ -74,11 +74,7 @@ export default class SVGElement extends Element implements ISVGElement {
|
|
74
74
|
}
|
75
75
|
|
76
76
|
/**
|
77
|
-
* The setAttributeNode() method adds a new Attr node to the specified element.
|
78
|
-
*
|
79
77
|
* @override
|
80
|
-
* @param attribute Attribute.
|
81
|
-
* @returns Replaced attribute.
|
82
78
|
*/
|
83
79
|
public setAttributeNode(attribute: IAttr): IAttr {
|
84
80
|
const replacedAttribute = super.setAttributeNode(attribute);
|
@@ -91,16 +87,15 @@ export default class SVGElement extends Element implements ISVGElement {
|
|
91
87
|
}
|
92
88
|
|
93
89
|
/**
|
94
|
-
* Removes an Attr node.
|
95
|
-
*
|
96
90
|
* @override
|
97
|
-
* @param attribute Attribute.
|
98
91
|
*/
|
99
|
-
public removeAttributeNode(attribute: IAttr):
|
92
|
+
public removeAttributeNode(attribute: IAttr): IAttr {
|
100
93
|
super.removeAttributeNode(attribute);
|
101
94
|
|
102
95
|
if (attribute.name === 'style' && this._style) {
|
103
96
|
this._style.cssText = '';
|
104
97
|
}
|
98
|
+
|
99
|
+
return attribute;
|
105
100
|
}
|
106
101
|
}
|
@@ -42,76 +42,80 @@ export default class XMLParser {
|
|
42
42
|
let lastTextIndex = 0;
|
43
43
|
let match: RegExpExecArray;
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
const isStartTag = !match[1];
|
45
|
+
if (data !== null && data !== undefined) {
|
46
|
+
data = String(data);
|
48
47
|
|
49
|
-
|
50
|
-
const
|
51
|
-
|
52
|
-
}
|
53
|
-
|
54
|
-
if (isStartTag) {
|
55
|
-
const namespaceURI =
|
56
|
-
tagName === 'svg'
|
57
|
-
? NamespaceURI.svg
|
58
|
-
: (<IElement>parent).namespaceURI || NamespaceURI.html;
|
59
|
-
const newElement = document.createElementNS(namespaceURI, tagName);
|
60
|
-
|
61
|
-
// Scripts are not allowed to be executed when they are parsed using innerHTML, outerHTML, replaceWith() etc.
|
62
|
-
// However, they are allowed to be executed when document.write() is used.
|
63
|
-
// See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement
|
64
|
-
if (tagName === 'script') {
|
65
|
-
(<HTMLScriptElement>newElement)._evaluateScript = evaluateScripts;
|
66
|
-
}
|
48
|
+
while ((match = markupRegexp.exec(data))) {
|
49
|
+
const tagName = match[2].toLowerCase();
|
50
|
+
const isStartTag = !match[1];
|
67
51
|
|
68
|
-
|
69
|
-
|
70
|
-
(
|
52
|
+
if (parent && match.index !== lastTextIndex) {
|
53
|
+
const text = data.substring(lastTextIndex, match.index);
|
54
|
+
this.appendTextAndCommentNodes(document, parent, text);
|
71
55
|
}
|
72
56
|
|
73
|
-
|
57
|
+
if (isStartTag) {
|
58
|
+
const namespaceURI =
|
59
|
+
tagName === 'svg'
|
60
|
+
? NamespaceURI.svg
|
61
|
+
: (<IElement>parent).namespaceURI || NamespaceURI.html;
|
62
|
+
const newElement = document.createElementNS(namespaceURI, tagName);
|
63
|
+
|
64
|
+
// Scripts are not allowed to be executed when they are parsed using innerHTML, outerHTML, replaceWith() etc.
|
65
|
+
// However, they are allowed to be executed when document.write() is used.
|
66
|
+
// See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement
|
67
|
+
if (tagName === 'script') {
|
68
|
+
(<HTMLScriptElement>newElement)._evaluateScript = evaluateScripts;
|
69
|
+
}
|
74
70
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
if (parentUnnestableTagName === tagName) {
|
79
|
-
stack.pop();
|
80
|
-
parent = <Element>parent.parentNode || root;
|
71
|
+
// An assumption that the same rule should be applied for the HTMLLinkElement is made here.
|
72
|
+
if (tagName === 'link') {
|
73
|
+
(<HTMLLinkElement>newElement)._evaluateCSS = evaluateScripts;
|
81
74
|
}
|
82
75
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
76
|
+
this.setAttributes(newElement, match[3]);
|
77
|
+
|
78
|
+
if (!match[4] && !VoidElements.includes(tagName)) {
|
79
|
+
// Some elements are not allowed to be nested (e.g. "<a><a></a></a>" is not allowed.).
|
80
|
+
// Therefore we will auto-close the tag.
|
81
|
+
if (parentUnnestableTagName === tagName) {
|
82
|
+
stack.pop();
|
83
|
+
parent = <Element>parent.parentNode || root;
|
84
|
+
}
|
85
|
+
|
86
|
+
parent = <Element>parent.appendChild(newElement);
|
87
|
+
parentUnnestableTagName = this.getUnnestableTagName(parent);
|
88
|
+
stack.push(parent);
|
89
|
+
} else {
|
90
|
+
parent.appendChild(newElement);
|
91
|
+
}
|
92
|
+
lastTextIndex = markupRegexp.lastIndex;
|
93
|
+
|
94
|
+
// Tags which contain non-parsed content
|
95
|
+
// For example: <script> JavaScript should not be parsed
|
96
|
+
if (ChildLessElements.includes(tagName)) {
|
97
|
+
let childLessMatch = null;
|
98
|
+
while ((childLessMatch = markupRegexp.exec(data))) {
|
99
|
+
if (childLessMatch[2].toLowerCase() === tagName && childLessMatch[1]) {
|
100
|
+
markupRegexp.lastIndex -= childLessMatch[0].length;
|
101
|
+
break;
|
102
|
+
}
|
99
103
|
}
|
100
104
|
}
|
101
|
-
}
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
parentUnnestableTagName = this.getUnnestableTagName(parent);
|
105
|
+
} else {
|
106
|
+
stack.pop();
|
107
|
+
parent = stack[stack.length - 1] || root;
|
108
|
+
parentUnnestableTagName = this.getUnnestableTagName(parent);
|
106
109
|
|
107
|
-
|
110
|
+
lastTextIndex = markupRegexp.lastIndex;
|
111
|
+
}
|
108
112
|
}
|
109
|
-
}
|
110
113
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
114
|
+
// Text after last element
|
115
|
+
if ((!match && data.length > 0) || (match && lastTextIndex !== match.index)) {
|
116
|
+
const text = data.substring(lastTextIndex);
|
117
|
+
this.appendTextAndCommentNodes(document, parent || root, text);
|
118
|
+
}
|
115
119
|
}
|
116
120
|
|
117
121
|
return root;
|