parse5 2.2.3 → 3.0.3

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.
Files changed (33) hide show
  1. package/LICENSE +19 -19
  2. package/README.md +40 -40
  3. package/lib/common/doctype.js +156 -137
  4. package/lib/common/foreign_content.js +1 -1
  5. package/lib/common/html.js +272 -266
  6. package/lib/common/unicode.js +47 -47
  7. package/lib/extensions/location_info/open_element_stack_mixin.js +34 -0
  8. package/lib/extensions/location_info/parser_mixin.js +213 -0
  9. package/lib/extensions/location_info/tokenizer_mixin.js +117 -0
  10. package/lib/extensions/position_tracking/preprocessor_mixin.js +72 -0
  11. package/lib/index.d.ts +1077 -0
  12. package/lib/index.js +44 -108
  13. package/lib/parser/formatting_element_list.js +167 -167
  14. package/lib/parser/index.js +2819 -2817
  15. package/lib/parser/open_element_stack.js +395 -395
  16. package/lib/parser/parser_stream.js +76 -0
  17. package/lib/parser/plain_text_conversion_stream.js +20 -0
  18. package/lib/sax/dev_null_stream.js +14 -14
  19. package/lib/sax/index.js +7 -119
  20. package/lib/serializer/index.js +162 -180
  21. package/lib/serializer/{stream.js → serializer_stream.js} +28 -49
  22. package/lib/tokenizer/index.js +65 -22
  23. package/lib/tokenizer/named_entity_data.js +5 -0
  24. package/lib/tokenizer/preprocessor.js +0 -8
  25. package/lib/tree_adapters/default.js +209 -578
  26. package/lib/tree_adapters/htmlparser2.js +338 -327
  27. package/lib/{common → utils}/merge_options.js +13 -13
  28. package/lib/utils/mixin.js +18 -0
  29. package/package.json +13 -14
  30. package/lib/location_info/parser_mixin.js +0 -217
  31. package/lib/location_info/tokenizer_mixin.js +0 -169
  32. package/lib/parser/stream.js +0 -140
  33. package/lib/tokenizer/named_entity_trie.js +0 -6
@@ -1,395 +1,395 @@
1
- 'use strict';
2
-
3
- var HTML = require('../common/html');
4
-
5
- //Aliases
6
- var $ = HTML.TAG_NAMES,
7
- NS = HTML.NAMESPACES;
8
-
9
- //Element utils
10
-
11
- //OPTIMIZATION: Integer comparisons are low-cost, so we can use very fast tag name length filters here.
12
- //It's faster than using dictionary.
13
- function isImpliedEndTagRequired(tn) {
14
- switch (tn.length) {
15
- case 1:
16
- return tn === $.P;
17
-
18
- case 2:
19
- return tn === $.RB || tn === $.RP || tn === $.RT || tn === $.DD || tn === $.DT || tn === $.LI;
20
-
21
- case 3:
22
- return tn === $.RTC;
23
-
24
- case 6:
25
- return tn === $.OPTION;
26
-
27
- case 8:
28
- return tn === $.OPTGROUP || tn === $.MENUITEM;
29
- }
30
-
31
- return false;
32
- }
33
-
34
- function isScopingElement(tn, ns) {
35
- switch (tn.length) {
36
- case 2:
37
- if (tn === $.TD || tn === $.TH)
38
- return ns === NS.HTML;
39
-
40
- else if (tn === $.MI || tn === $.MO || tn === $.MN || tn === $.MS)
41
- return ns === NS.MATHML;
42
-
43
- break;
44
-
45
- case 4:
46
- if (tn === $.HTML)
47
- return ns === NS.HTML;
48
-
49
- else if (tn === $.DESC)
50
- return ns === NS.SVG;
51
-
52
- break;
53
-
54
- case 5:
55
- if (tn === $.TABLE)
56
- return ns === NS.HTML;
57
-
58
- else if (tn === $.MTEXT)
59
- return ns === NS.MATHML;
60
-
61
- else if (tn === $.TITLE)
62
- return ns === NS.SVG;
63
-
64
- break;
65
-
66
- case 6:
67
- return (tn === $.APPLET || tn === $.OBJECT) && ns === NS.HTML;
68
-
69
- case 7:
70
- return (tn === $.CAPTION || tn === $.MARQUEE) && ns === NS.HTML;
71
-
72
- case 8:
73
- return tn === $.TEMPLATE && ns === NS.HTML;
74
-
75
- case 13:
76
- return tn === $.FOREIGN_OBJECT && ns === NS.SVG;
77
-
78
- case 14:
79
- return tn === $.ANNOTATION_XML && ns === NS.MATHML;
80
- }
81
-
82
- return false;
83
- }
84
-
85
- //Stack of open elements
86
- var OpenElementStack = module.exports = function (document, treeAdapter) {
87
- this.stackTop = -1;
88
- this.items = [];
89
- this.current = document;
90
- this.currentTagName = null;
91
- this.currentTmplContent = null;
92
- this.tmplCount = 0;
93
- this.treeAdapter = treeAdapter;
94
- };
95
-
96
- //Index of element
97
- OpenElementStack.prototype._indexOf = function (element) {
98
- var idx = -1;
99
-
100
- for (var i = this.stackTop; i >= 0; i--) {
101
- if (this.items[i] === element) {
102
- idx = i;
103
- break;
104
- }
105
- }
106
- return idx;
107
- };
108
-
109
- //Update current element
110
- OpenElementStack.prototype._isInTemplate = function () {
111
- return this.currentTagName === $.TEMPLATE && this.treeAdapter.getNamespaceURI(this.current) === NS.HTML;
112
- };
113
-
114
- OpenElementStack.prototype._updateCurrentElement = function () {
115
- this.current = this.items[this.stackTop];
116
- this.currentTagName = this.current && this.treeAdapter.getTagName(this.current);
117
-
118
- this.currentTmplContent = this._isInTemplate() ? this.treeAdapter.getTemplateContent(this.current) : null;
119
- };
120
-
121
- //Mutations
122
- OpenElementStack.prototype.push = function (element) {
123
- this.items[++this.stackTop] = element;
124
- this._updateCurrentElement();
125
-
126
- if (this._isInTemplate())
127
- this.tmplCount++;
128
-
129
- };
130
-
131
- OpenElementStack.prototype.pop = function () {
132
- this.stackTop--;
133
-
134
- if (this.tmplCount > 0 && this._isInTemplate())
135
- this.tmplCount--;
136
-
137
- this._updateCurrentElement();
138
- };
139
-
140
- OpenElementStack.prototype.replace = function (oldElement, newElement) {
141
- var idx = this._indexOf(oldElement);
142
-
143
- this.items[idx] = newElement;
144
-
145
- if (idx === this.stackTop)
146
- this._updateCurrentElement();
147
- };
148
-
149
- OpenElementStack.prototype.insertAfter = function (referenceElement, newElement) {
150
- var insertionIdx = this._indexOf(referenceElement) + 1;
151
-
152
- this.items.splice(insertionIdx, 0, newElement);
153
-
154
- if (insertionIdx === ++this.stackTop)
155
- this._updateCurrentElement();
156
- };
157
-
158
- OpenElementStack.prototype.popUntilTagNamePopped = function (tagName) {
159
- while (this.stackTop > -1) {
160
- var tn = this.currentTagName,
161
- ns = this.treeAdapter.getNamespaceURI(this.current);
162
-
163
- this.pop();
164
-
165
- if (tn === tagName && ns === NS.HTML)
166
- break;
167
- }
168
- };
169
-
170
- OpenElementStack.prototype.popUntilElementPopped = function (element) {
171
- while (this.stackTop > -1) {
172
- var poppedElement = this.current;
173
-
174
- this.pop();
175
-
176
- if (poppedElement === element)
177
- break;
178
- }
179
- };
180
-
181
- OpenElementStack.prototype.popUntilNumberedHeaderPopped = function () {
182
- while (this.stackTop > -1) {
183
- var tn = this.currentTagName,
184
- ns = this.treeAdapter.getNamespaceURI(this.current);
185
-
186
- this.pop();
187
-
188
- if (tn === $.H1 || tn === $.H2 || tn === $.H3 || tn === $.H4 || tn === $.H5 || tn === $.H6 && ns === NS.HTML)
189
- break;
190
- }
191
- };
192
-
193
- OpenElementStack.prototype.popUntilTableCellPopped = function () {
194
- while (this.stackTop > -1) {
195
- var tn = this.currentTagName,
196
- ns = this.treeAdapter.getNamespaceURI(this.current);
197
-
198
- this.pop();
199
-
200
- if (tn === $.TD || tn === $.TH && ns === NS.HTML)
201
- break;
202
- }
203
- };
204
-
205
- OpenElementStack.prototype.popAllUpToHtmlElement = function () {
206
- //NOTE: here we assume that root <html> element is always first in the open element stack, so
207
- //we perform this fast stack clean up.
208
- this.stackTop = 0;
209
- this._updateCurrentElement();
210
- };
211
-
212
- OpenElementStack.prototype.clearBackToTableContext = function () {
213
- while (this.currentTagName !== $.TABLE &&
214
- this.currentTagName !== $.TEMPLATE &&
215
- this.currentTagName !== $.HTML ||
216
- this.treeAdapter.getNamespaceURI(this.current) !== NS.HTML)
217
- this.pop();
218
- };
219
-
220
- OpenElementStack.prototype.clearBackToTableBodyContext = function () {
221
- while (this.currentTagName !== $.TBODY &&
222
- this.currentTagName !== $.TFOOT &&
223
- this.currentTagName !== $.THEAD &&
224
- this.currentTagName !== $.TEMPLATE &&
225
- this.currentTagName !== $.HTML ||
226
- this.treeAdapter.getNamespaceURI(this.current) !== NS.HTML)
227
- this.pop();
228
- };
229
-
230
- OpenElementStack.prototype.clearBackToTableRowContext = function () {
231
- while (this.currentTagName !== $.TR &&
232
- this.currentTagName !== $.TEMPLATE &&
233
- this.currentTagName !== $.HTML ||
234
- this.treeAdapter.getNamespaceURI(this.current) !== NS.HTML)
235
- this.pop();
236
- };
237
-
238
- OpenElementStack.prototype.remove = function (element) {
239
- for (var i = this.stackTop; i >= 0; i--) {
240
- if (this.items[i] === element) {
241
- this.items.splice(i, 1);
242
- this.stackTop--;
243
- this._updateCurrentElement();
244
- break;
245
- }
246
- }
247
- };
248
-
249
- //Search
250
- OpenElementStack.prototype.tryPeekProperlyNestedBodyElement = function () {
251
- //Properly nested <body> element (should be second element in stack).
252
- var element = this.items[1];
253
-
254
- return element && this.treeAdapter.getTagName(element) === $.BODY ? element : null;
255
- };
256
-
257
- OpenElementStack.prototype.contains = function (element) {
258
- return this._indexOf(element) > -1;
259
- };
260
-
261
- OpenElementStack.prototype.getCommonAncestor = function (element) {
262
- var elementIdx = this._indexOf(element);
263
-
264
- return --elementIdx >= 0 ? this.items[elementIdx] : null;
265
- };
266
-
267
- OpenElementStack.prototype.isRootHtmlElementCurrent = function () {
268
- return this.stackTop === 0 && this.currentTagName === $.HTML;
269
- };
270
-
271
- //Element in scope
272
- OpenElementStack.prototype.hasInScope = function (tagName) {
273
- for (var i = this.stackTop; i >= 0; i--) {
274
- var tn = this.treeAdapter.getTagName(this.items[i]),
275
- ns = this.treeAdapter.getNamespaceURI(this.items[i]);
276
-
277
- if (tn === tagName && ns === NS.HTML)
278
- return true;
279
-
280
- if (isScopingElement(tn, ns))
281
- return false;
282
- }
283
-
284
- return true;
285
- };
286
-
287
- OpenElementStack.prototype.hasNumberedHeaderInScope = function () {
288
- for (var i = this.stackTop; i >= 0; i--) {
289
- var tn = this.treeAdapter.getTagName(this.items[i]),
290
- ns = this.treeAdapter.getNamespaceURI(this.items[i]);
291
-
292
- if ((tn === $.H1 || tn === $.H2 || tn === $.H3 || tn === $.H4 || tn === $.H5 || tn === $.H6) && ns === NS.HTML)
293
- return true;
294
-
295
- if (isScopingElement(tn, ns))
296
- return false;
297
- }
298
-
299
- return true;
300
- };
301
-
302
- OpenElementStack.prototype.hasInListItemScope = function (tagName) {
303
- for (var i = this.stackTop; i >= 0; i--) {
304
- var tn = this.treeAdapter.getTagName(this.items[i]),
305
- ns = this.treeAdapter.getNamespaceURI(this.items[i]);
306
-
307
- if (tn === tagName && ns === NS.HTML)
308
- return true;
309
-
310
- if ((tn === $.UL || tn === $.OL) && ns === NS.HTML || isScopingElement(tn, ns))
311
- return false;
312
- }
313
-
314
- return true;
315
- };
316
-
317
- OpenElementStack.prototype.hasInButtonScope = function (tagName) {
318
- for (var i = this.stackTop; i >= 0; i--) {
319
- var tn = this.treeAdapter.getTagName(this.items[i]),
320
- ns = this.treeAdapter.getNamespaceURI(this.items[i]);
321
-
322
- if (tn === tagName && ns === NS.HTML)
323
- return true;
324
-
325
- if (tn === $.BUTTON && ns === NS.HTML || isScopingElement(tn, ns))
326
- return false;
327
- }
328
-
329
- return true;
330
- };
331
-
332
- OpenElementStack.prototype.hasInTableScope = function (tagName) {
333
- for (var i = this.stackTop; i >= 0; i--) {
334
- var tn = this.treeAdapter.getTagName(this.items[i]),
335
- ns = this.treeAdapter.getNamespaceURI(this.items[i]);
336
-
337
- if (ns !== NS.HTML)
338
- continue;
339
-
340
- if (tn === tagName)
341
- return true;
342
-
343
- if (tn === $.TABLE || tn === $.TEMPLATE || tn === $.HTML)
344
- return false;
345
- }
346
-
347
- return true;
348
- };
349
-
350
- OpenElementStack.prototype.hasTableBodyContextInTableScope = function () {
351
- for (var i = this.stackTop; i >= 0; i--) {
352
- var tn = this.treeAdapter.getTagName(this.items[i]),
353
- ns = this.treeAdapter.getNamespaceURI(this.items[i]);
354
-
355
- if (ns !== NS.HTML)
356
- continue;
357
-
358
- if (tn === $.TBODY || tn === $.THEAD || tn === $.TFOOT)
359
- return true;
360
-
361
- if (tn === $.TABLE || tn === $.HTML)
362
- return false;
363
- }
364
-
365
- return true;
366
- };
367
-
368
- OpenElementStack.prototype.hasInSelectScope = function (tagName) {
369
- for (var i = this.stackTop; i >= 0; i--) {
370
- var tn = this.treeAdapter.getTagName(this.items[i]),
371
- ns = this.treeAdapter.getNamespaceURI(this.items[i]);
372
-
373
- if (ns !== NS.HTML)
374
- continue;
375
-
376
- if (tn === tagName)
377
- return true;
378
-
379
- if (tn !== $.OPTION && tn !== $.OPTGROUP)
380
- return false;
381
- }
382
-
383
- return true;
384
- };
385
-
386
- //Implied end tags
387
- OpenElementStack.prototype.generateImpliedEndTags = function () {
388
- while (isImpliedEndTagRequired(this.currentTagName))
389
- this.pop();
390
- };
391
-
392
- OpenElementStack.prototype.generateImpliedEndTagsWithExclusion = function (exclusionTagName) {
393
- while (isImpliedEndTagRequired(this.currentTagName) && this.currentTagName !== exclusionTagName)
394
- this.pop();
395
- };
1
+ 'use strict';
2
+
3
+ var HTML = require('../common/html');
4
+
5
+ //Aliases
6
+ var $ = HTML.TAG_NAMES,
7
+ NS = HTML.NAMESPACES;
8
+
9
+ //Element utils
10
+
11
+ //OPTIMIZATION: Integer comparisons are low-cost, so we can use very fast tag name length filters here.
12
+ //It's faster than using dictionary.
13
+ function isImpliedEndTagRequired(tn) {
14
+ switch (tn.length) {
15
+ case 1:
16
+ return tn === $.P;
17
+
18
+ case 2:
19
+ return tn === $.RB || tn === $.RP || tn === $.RT || tn === $.DD || tn === $.DT || tn === $.LI;
20
+
21
+ case 3:
22
+ return tn === $.RTC;
23
+
24
+ case 6:
25
+ return tn === $.OPTION;
26
+
27
+ case 8:
28
+ return tn === $.OPTGROUP || tn === $.MENUITEM;
29
+ }
30
+
31
+ return false;
32
+ }
33
+
34
+ function isScopingElement(tn, ns) {
35
+ switch (tn.length) {
36
+ case 2:
37
+ if (tn === $.TD || tn === $.TH)
38
+ return ns === NS.HTML;
39
+
40
+ else if (tn === $.MI || tn === $.MO || tn === $.MN || tn === $.MS)
41
+ return ns === NS.MATHML;
42
+
43
+ break;
44
+
45
+ case 4:
46
+ if (tn === $.HTML)
47
+ return ns === NS.HTML;
48
+
49
+ else if (tn === $.DESC)
50
+ return ns === NS.SVG;
51
+
52
+ break;
53
+
54
+ case 5:
55
+ if (tn === $.TABLE)
56
+ return ns === NS.HTML;
57
+
58
+ else if (tn === $.MTEXT)
59
+ return ns === NS.MATHML;
60
+
61
+ else if (tn === $.TITLE)
62
+ return ns === NS.SVG;
63
+
64
+ break;
65
+
66
+ case 6:
67
+ return (tn === $.APPLET || tn === $.OBJECT) && ns === NS.HTML;
68
+
69
+ case 7:
70
+ return (tn === $.CAPTION || tn === $.MARQUEE) && ns === NS.HTML;
71
+
72
+ case 8:
73
+ return tn === $.TEMPLATE && ns === NS.HTML;
74
+
75
+ case 13:
76
+ return tn === $.FOREIGN_OBJECT && ns === NS.SVG;
77
+
78
+ case 14:
79
+ return tn === $.ANNOTATION_XML && ns === NS.MATHML;
80
+ }
81
+
82
+ return false;
83
+ }
84
+
85
+ //Stack of open elements
86
+ var OpenElementStack = module.exports = function (document, treeAdapter) {
87
+ this.stackTop = -1;
88
+ this.items = [];
89
+ this.current = document;
90
+ this.currentTagName = null;
91
+ this.currentTmplContent = null;
92
+ this.tmplCount = 0;
93
+ this.treeAdapter = treeAdapter;
94
+ };
95
+
96
+ //Index of element
97
+ OpenElementStack.prototype._indexOf = function (element) {
98
+ var idx = -1;
99
+
100
+ for (var i = this.stackTop; i >= 0; i--) {
101
+ if (this.items[i] === element) {
102
+ idx = i;
103
+ break;
104
+ }
105
+ }
106
+ return idx;
107
+ };
108
+
109
+ //Update current element
110
+ OpenElementStack.prototype._isInTemplate = function () {
111
+ return this.currentTagName === $.TEMPLATE && this.treeAdapter.getNamespaceURI(this.current) === NS.HTML;
112
+ };
113
+
114
+ OpenElementStack.prototype._updateCurrentElement = function () {
115
+ this.current = this.items[this.stackTop];
116
+ this.currentTagName = this.current && this.treeAdapter.getTagName(this.current);
117
+
118
+ this.currentTmplContent = this._isInTemplate() ? this.treeAdapter.getTemplateContent(this.current) : null;
119
+ };
120
+
121
+ //Mutations
122
+ OpenElementStack.prototype.push = function (element) {
123
+ this.items[++this.stackTop] = element;
124
+ this._updateCurrentElement();
125
+
126
+ if (this._isInTemplate())
127
+ this.tmplCount++;
128
+
129
+ };
130
+
131
+ OpenElementStack.prototype.pop = function () {
132
+ this.stackTop--;
133
+
134
+ if (this.tmplCount > 0 && this._isInTemplate())
135
+ this.tmplCount--;
136
+
137
+ this._updateCurrentElement();
138
+ };
139
+
140
+ OpenElementStack.prototype.replace = function (oldElement, newElement) {
141
+ var idx = this._indexOf(oldElement);
142
+
143
+ this.items[idx] = newElement;
144
+
145
+ if (idx === this.stackTop)
146
+ this._updateCurrentElement();
147
+ };
148
+
149
+ OpenElementStack.prototype.insertAfter = function (referenceElement, newElement) {
150
+ var insertionIdx = this._indexOf(referenceElement) + 1;
151
+
152
+ this.items.splice(insertionIdx, 0, newElement);
153
+
154
+ if (insertionIdx === ++this.stackTop)
155
+ this._updateCurrentElement();
156
+ };
157
+
158
+ OpenElementStack.prototype.popUntilTagNamePopped = function (tagName) {
159
+ while (this.stackTop > -1) {
160
+ var tn = this.currentTagName,
161
+ ns = this.treeAdapter.getNamespaceURI(this.current);
162
+
163
+ this.pop();
164
+
165
+ if (tn === tagName && ns === NS.HTML)
166
+ break;
167
+ }
168
+ };
169
+
170
+ OpenElementStack.prototype.popUntilElementPopped = function (element) {
171
+ while (this.stackTop > -1) {
172
+ var poppedElement = this.current;
173
+
174
+ this.pop();
175
+
176
+ if (poppedElement === element)
177
+ break;
178
+ }
179
+ };
180
+
181
+ OpenElementStack.prototype.popUntilNumberedHeaderPopped = function () {
182
+ while (this.stackTop > -1) {
183
+ var tn = this.currentTagName,
184
+ ns = this.treeAdapter.getNamespaceURI(this.current);
185
+
186
+ this.pop();
187
+
188
+ if (tn === $.H1 || tn === $.H2 || tn === $.H3 || tn === $.H4 || tn === $.H5 || tn === $.H6 && ns === NS.HTML)
189
+ break;
190
+ }
191
+ };
192
+
193
+ OpenElementStack.prototype.popUntilTableCellPopped = function () {
194
+ while (this.stackTop > -1) {
195
+ var tn = this.currentTagName,
196
+ ns = this.treeAdapter.getNamespaceURI(this.current);
197
+
198
+ this.pop();
199
+
200
+ if (tn === $.TD || tn === $.TH && ns === NS.HTML)
201
+ break;
202
+ }
203
+ };
204
+
205
+ OpenElementStack.prototype.popAllUpToHtmlElement = function () {
206
+ //NOTE: here we assume that root <html> element is always first in the open element stack, so
207
+ //we perform this fast stack clean up.
208
+ this.stackTop = 0;
209
+ this._updateCurrentElement();
210
+ };
211
+
212
+ OpenElementStack.prototype.clearBackToTableContext = function () {
213
+ while (this.currentTagName !== $.TABLE &&
214
+ this.currentTagName !== $.TEMPLATE &&
215
+ this.currentTagName !== $.HTML ||
216
+ this.treeAdapter.getNamespaceURI(this.current) !== NS.HTML)
217
+ this.pop();
218
+ };
219
+
220
+ OpenElementStack.prototype.clearBackToTableBodyContext = function () {
221
+ while (this.currentTagName !== $.TBODY &&
222
+ this.currentTagName !== $.TFOOT &&
223
+ this.currentTagName !== $.THEAD &&
224
+ this.currentTagName !== $.TEMPLATE &&
225
+ this.currentTagName !== $.HTML ||
226
+ this.treeAdapter.getNamespaceURI(this.current) !== NS.HTML)
227
+ this.pop();
228
+ };
229
+
230
+ OpenElementStack.prototype.clearBackToTableRowContext = function () {
231
+ while (this.currentTagName !== $.TR &&
232
+ this.currentTagName !== $.TEMPLATE &&
233
+ this.currentTagName !== $.HTML ||
234
+ this.treeAdapter.getNamespaceURI(this.current) !== NS.HTML)
235
+ this.pop();
236
+ };
237
+
238
+ OpenElementStack.prototype.remove = function (element) {
239
+ for (var i = this.stackTop; i >= 0; i--) {
240
+ if (this.items[i] === element) {
241
+ this.items.splice(i, 1);
242
+ this.stackTop--;
243
+ this._updateCurrentElement();
244
+ break;
245
+ }
246
+ }
247
+ };
248
+
249
+ //Search
250
+ OpenElementStack.prototype.tryPeekProperlyNestedBodyElement = function () {
251
+ //Properly nested <body> element (should be second element in stack).
252
+ var element = this.items[1];
253
+
254
+ return element && this.treeAdapter.getTagName(element) === $.BODY ? element : null;
255
+ };
256
+
257
+ OpenElementStack.prototype.contains = function (element) {
258
+ return this._indexOf(element) > -1;
259
+ };
260
+
261
+ OpenElementStack.prototype.getCommonAncestor = function (element) {
262
+ var elementIdx = this._indexOf(element);
263
+
264
+ return --elementIdx >= 0 ? this.items[elementIdx] : null;
265
+ };
266
+
267
+ OpenElementStack.prototype.isRootHtmlElementCurrent = function () {
268
+ return this.stackTop === 0 && this.currentTagName === $.HTML;
269
+ };
270
+
271
+ //Element in scope
272
+ OpenElementStack.prototype.hasInScope = function (tagName) {
273
+ for (var i = this.stackTop; i >= 0; i--) {
274
+ var tn = this.treeAdapter.getTagName(this.items[i]),
275
+ ns = this.treeAdapter.getNamespaceURI(this.items[i]);
276
+
277
+ if (tn === tagName && ns === NS.HTML)
278
+ return true;
279
+
280
+ if (isScopingElement(tn, ns))
281
+ return false;
282
+ }
283
+
284
+ return true;
285
+ };
286
+
287
+ OpenElementStack.prototype.hasNumberedHeaderInScope = function () {
288
+ for (var i = this.stackTop; i >= 0; i--) {
289
+ var tn = this.treeAdapter.getTagName(this.items[i]),
290
+ ns = this.treeAdapter.getNamespaceURI(this.items[i]);
291
+
292
+ if ((tn === $.H1 || tn === $.H2 || tn === $.H3 || tn === $.H4 || tn === $.H5 || tn === $.H6) && ns === NS.HTML)
293
+ return true;
294
+
295
+ if (isScopingElement(tn, ns))
296
+ return false;
297
+ }
298
+
299
+ return true;
300
+ };
301
+
302
+ OpenElementStack.prototype.hasInListItemScope = function (tagName) {
303
+ for (var i = this.stackTop; i >= 0; i--) {
304
+ var tn = this.treeAdapter.getTagName(this.items[i]),
305
+ ns = this.treeAdapter.getNamespaceURI(this.items[i]);
306
+
307
+ if (tn === tagName && ns === NS.HTML)
308
+ return true;
309
+
310
+ if ((tn === $.UL || tn === $.OL) && ns === NS.HTML || isScopingElement(tn, ns))
311
+ return false;
312
+ }
313
+
314
+ return true;
315
+ };
316
+
317
+ OpenElementStack.prototype.hasInButtonScope = function (tagName) {
318
+ for (var i = this.stackTop; i >= 0; i--) {
319
+ var tn = this.treeAdapter.getTagName(this.items[i]),
320
+ ns = this.treeAdapter.getNamespaceURI(this.items[i]);
321
+
322
+ if (tn === tagName && ns === NS.HTML)
323
+ return true;
324
+
325
+ if (tn === $.BUTTON && ns === NS.HTML || isScopingElement(tn, ns))
326
+ return false;
327
+ }
328
+
329
+ return true;
330
+ };
331
+
332
+ OpenElementStack.prototype.hasInTableScope = function (tagName) {
333
+ for (var i = this.stackTop; i >= 0; i--) {
334
+ var tn = this.treeAdapter.getTagName(this.items[i]),
335
+ ns = this.treeAdapter.getNamespaceURI(this.items[i]);
336
+
337
+ if (ns !== NS.HTML)
338
+ continue;
339
+
340
+ if (tn === tagName)
341
+ return true;
342
+
343
+ if (tn === $.TABLE || tn === $.TEMPLATE || tn === $.HTML)
344
+ return false;
345
+ }
346
+
347
+ return true;
348
+ };
349
+
350
+ OpenElementStack.prototype.hasTableBodyContextInTableScope = function () {
351
+ for (var i = this.stackTop; i >= 0; i--) {
352
+ var tn = this.treeAdapter.getTagName(this.items[i]),
353
+ ns = this.treeAdapter.getNamespaceURI(this.items[i]);
354
+
355
+ if (ns !== NS.HTML)
356
+ continue;
357
+
358
+ if (tn === $.TBODY || tn === $.THEAD || tn === $.TFOOT)
359
+ return true;
360
+
361
+ if (tn === $.TABLE || tn === $.HTML)
362
+ return false;
363
+ }
364
+
365
+ return true;
366
+ };
367
+
368
+ OpenElementStack.prototype.hasInSelectScope = function (tagName) {
369
+ for (var i = this.stackTop; i >= 0; i--) {
370
+ var tn = this.treeAdapter.getTagName(this.items[i]),
371
+ ns = this.treeAdapter.getNamespaceURI(this.items[i]);
372
+
373
+ if (ns !== NS.HTML)
374
+ continue;
375
+
376
+ if (tn === tagName)
377
+ return true;
378
+
379
+ if (tn !== $.OPTION && tn !== $.OPTGROUP)
380
+ return false;
381
+ }
382
+
383
+ return true;
384
+ };
385
+
386
+ //Implied end tags
387
+ OpenElementStack.prototype.generateImpliedEndTags = function () {
388
+ while (isImpliedEndTagRequired(this.currentTagName))
389
+ this.pop();
390
+ };
391
+
392
+ OpenElementStack.prototype.generateImpliedEndTagsWithExclusion = function (exclusionTagName) {
393
+ while (isImpliedEndTagRequired(this.currentTagName) && this.currentTagName !== exclusionTagName)
394
+ this.pop();
395
+ };