"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Parser = void 0; const index_js_1 = require("../tokenizer/index.js"); const open_element_stack_js_1 = require("./open-element-stack.js"); const formatting_element_list_js_1 = require("./formatting-element-list.js"); const default_js_1 = require("../tree-adapters/default.js"); const doctype = require("../common/doctype.js"); const foreignContent = require("../common/foreign-content.js"); const error_codes_js_1 = require("../common/error-codes.js"); const unicode = require("../common/unicode.js"); const html_js_1 = require("../common/html.js"); const token_js_1 = require("../common/token.js"); //Misc constants const HIDDEN_INPUT_TYPE = 'hidden'; //Adoption agency loops iteration count const AA_OUTER_LOOP_ITER = 8; const AA_INNER_LOOP_ITER = 3; //Insertion modes var InsertionMode; (function (InsertionMode) { InsertionMode[InsertionMode["INITIAL"] = 0] = "INITIAL"; InsertionMode[InsertionMode["BEFORE_HTML"] = 1] = "BEFORE_HTML"; InsertionMode[InsertionMode["BEFORE_HEAD"] = 2] = "BEFORE_HEAD"; InsertionMode[InsertionMode["IN_HEAD"] = 3] = "IN_HEAD"; InsertionMode[InsertionMode["IN_HEAD_NO_SCRIPT"] = 4] = "IN_HEAD_NO_SCRIPT"; InsertionMode[InsertionMode["AFTER_HEAD"] = 5] = "AFTER_HEAD"; InsertionMode[InsertionMode["IN_BODY"] = 6] = "IN_BODY"; InsertionMode[InsertionMode["TEXT"] = 7] = "TEXT"; InsertionMode[InsertionMode["IN_TABLE"] = 8] = "IN_TABLE"; InsertionMode[InsertionMode["IN_TABLE_TEXT"] = 9] = "IN_TABLE_TEXT"; InsertionMode[InsertionMode["IN_CAPTION"] = 10] = "IN_CAPTION"; InsertionMode[InsertionMode["IN_COLUMN_GROUP"] = 11] = "IN_COLUMN_GROUP"; InsertionMode[InsertionMode["IN_TABLE_BODY"] = 12] = "IN_TABLE_BODY"; InsertionMode[InsertionMode["IN_ROW"] = 13] = "IN_ROW"; InsertionMode[InsertionMode["IN_CELL"] = 14] = "IN_CELL"; InsertionMode[InsertionMode["IN_SELECT"] = 15] = "IN_SELECT"; InsertionMode[InsertionMode["IN_SELECT_IN_TABLE"] = 16] = "IN_SELECT_IN_TABLE"; InsertionMode[InsertionMode["IN_TEMPLATE"] = 17] = "IN_TEMPLATE"; InsertionMode[InsertionMode["AFTER_BODY"] = 18] = "AFTER_BODY"; InsertionMode[InsertionMode["IN_FRAMESET"] = 19] = "IN_FRAMESET"; InsertionMode[InsertionMode["AFTER_FRAMESET"] = 20] = "AFTER_FRAMESET"; InsertionMode[InsertionMode["AFTER_AFTER_BODY"] = 21] = "AFTER_AFTER_BODY"; InsertionMode[InsertionMode["AFTER_AFTER_FRAMESET"] = 22] = "AFTER_AFTER_FRAMESET"; })(InsertionMode || (InsertionMode = {})); const BASE_LOC = { startLine: -1, startCol: -1, startOffset: -1, endLine: -1, endCol: -1, endOffset: -1, }; const TABLE_STRUCTURE_TAGS = new Set([html_js_1.TAG_ID.TABLE, html_js_1.TAG_ID.TBODY, html_js_1.TAG_ID.TFOOT, html_js_1.TAG_ID.THEAD, html_js_1.TAG_ID.TR]); const defaultParserOptions = { scriptingEnabled: true, sourceCodeLocationInfo: false, treeAdapter: default_js_1.defaultTreeAdapter, onParseError: null, }; //Parser class Parser { constructor(options, document, fragmentContext = null, scriptHandler = null) { this.fragmentContext = fragmentContext; this.scriptHandler = scriptHandler; this.currentToken = null; this.stopped = false; this.insertionMode = InsertionMode.INITIAL; this.originalInsertionMode = InsertionMode.INITIAL; this.headElement = null; this.formElement = null; /** Indicates that the current node is not an element in the HTML namespace */ this.currentNotInHTML = false; /** * The template insertion mode stack is maintained from the left. * Ie. the topmost element will always have index 0. */ this.tmplInsertionModeStack = []; this.pendingCharacterTokens = []; this.hasNonWhitespacePendingCharacterToken = false; this.framesetOk = true; this.skipNextNewLine = false; this.fosterParentingEnabled = false; this.options = Object.assign(Object.assign({}, defaultParserOptions), options); this.treeAdapter = this.options.treeAdapter; this.onParseError = this.options.onParseError; // Always enable location info if we report parse errors. if (this.onParseError) { this.options.sourceCodeLocationInfo = true; } this.document = document !== null && document !== void 0 ? document : this.treeAdapter.createDocument(); this.tokenizer = new index_js_1.Tokenizer(this.options, this); this.activeFormattingElements = new formatting_element_list_js_1.FormattingElementList(this.treeAdapter); this.fragmentContextID = fragmentContext ? (0, html_js_1.getTagID)(this.treeAdapter.getTagName(fragmentContext)) : html_js_1.TAG_ID.UNKNOWN; this._setContextModes(fragmentContext !== null && fragmentContext !== void 0 ? fragmentContext : this.document, this.fragmentContextID); this.openElements = new open_element_stack_js_1.OpenElementStack(this.document, this.treeAdapter, this); } // API static parse(html, options) { const parser = new this(options); parser.tokenizer.write(html, true); return parser.document; } static getFragmentParser(fragmentContext, options) { const opts = Object.assign(Object.assign({}, defaultParserOptions), options); //NOTE: use a <template> element as the fragment context if no context element was provided, //so we will parse in a "forgiving" manner fragmentContext !== null && fragmentContext !== void 0 ? fragmentContext : (fragmentContext = opts.treeAdapter.createElement(html_js_1.TAG_NAMES.TEMPLATE, html_js_1.NS.HTML, [])); //NOTE: create a fake element which will be used as the `document` for fragment parsing. //This is important for jsdom, where a new `document` cannot be created. This led to //fragment parsing messing with the main `document`. const documentMock = opts.treeAdapter.createElement('documentmock', html_js_1.NS.HTML, []); const parser = new this(opts, documentMock, fragmentContext); if (parser.fragmentContextID === html_js_1.TAG_ID.TEMPLATE) { parser.tmplInsertionModeStack.unshift(InsertionMode.IN_TEMPLATE); } parser._initTokenizerForFragmentParsing(); parser._insertFakeRootElement(); parser._resetInsertionMode(); parser._findFormInFragmentContext(); return parser; } getFragment() { const rootElement = this.treeAdapter.getFirstChild(this.document); const fragment = this.treeAdapter.createDocumentFragment(); this._adoptNodes(rootElement, fragment); return fragment; } //Errors _err(token, code, beforeToken) { var _a; if (!this.onParseError) return; const loc = (_a = token.location) !== null && _a !== void 0 ? _a : BASE_LOC; const err = { code, startLine: loc.startLine, startCol: loc.startCol, startOffset: loc.startOffset, endLine: beforeToken ? loc.startLine : loc.endLine, endCol: beforeToken ? loc.startCol : loc.endCol, endOffset: beforeToken ? loc.startOffset : loc.endOffset, }; this.onParseError(err); } //Stack events onItemPush(node, tid, isTop) { var _a, _b; (_b = (_a = this.treeAdapter).onItemPush) === null || _b === void 0 ? void 0 : _b.call(_a, node); if (isTop && this.openElements.stackTop > 0) this._setContextModes(node, tid); } onItemPop(node, isTop) { var _a, _b; if (this.options.sourceCodeLocationInfo) { this._setEndLocation(node, this.currentToken); } (_b = (_a = this.treeAdapter).onItemPop) === null || _b === void 0 ? void 0 : _b.call(_a, node, this.openElements.current); if (isTop) { let current; let currentTagId; if (this.openElements.stackTop === 0 && this.fragmentContext) { current = this.fragmentContext; currentTagId = this.fragmentContextID; } else { ({ current, currentTagId } = this.openElements); } this._setContextModes(current, currentTagId); } } _setContextModes(current, tid) { const isHTML = current === this.document || this.treeAdapter.getNamespaceURI(current) === html_js_1.NS.HTML; this.currentNotInHTML = !isHTML; this.tokenizer.inForeignNode = !isHTML && !this._isIntegrationPoint(tid, current); } _switchToTextParsing(currentToken, nextTokenizerState) { this._insertElement(currentToken, html_js_1.NS.HTML); this.tokenizer.state = nextTokenizerState; this.originalInsertionMode = this.insertionMode; this.insertionMode = InsertionMode.TEXT; } switchToPlaintextParsing() { this.insertionMode = InsertionMode.TEXT; this.originalInsertionMode = InsertionMode.IN_BODY; this.tokenizer.state = index_js_1.TokenizerMode.PLAINTEXT; } //Fragment parsing _getAdjustedCurrentElement() { return this.openElements.stackTop === 0 && this.fragmentContext ? this.fragmentContext : this.openElements.current; } _findFormInFragmentContext() { let node = this.fragmentContext; while (node) { if (this.treeAdapter.getTagName(node) === html_js_1.TAG_NAMES.FORM) { this.formElement = node; break; } node = this.treeAdapter.getParentNode(node); } } _initTokenizerForFragmentParsing() { if (!this.fragmentContext || this.treeAdapter.getNamespaceURI(this.fragmentContext) !== html_js_1.NS.HTML) { return; } switch (this.fragmentContextID) { case html_js_1.TAG_ID.TITLE: case html_js_1.TAG_ID.TEXTAREA: { this.tokenizer.state = index_js_1.TokenizerMode.RCDATA; break; } case html_js_1.TAG_ID.STYLE: case html_js_1.TAG_ID.XMP: case html_js_1.TAG_ID.IFRAME: case html_js_1.TAG_ID.NOEMBED: case html_js_1.TAG_ID.NOFRAMES: case html_js_1.TAG_ID.NOSCRIPT: { this.tokenizer.state = index_js_1.TokenizerMode.RAWTEXT; break; } case html_js_1.TAG_ID.SCRIPT: { this.tokenizer.state = index_js_1.TokenizerMode.SCRIPT_DATA; break; } case html_js_1.TAG_ID.PLAINTEXT: { this.tokenizer.state = index_js_1.TokenizerMode.PLAINTEXT; break; } default: // Do nothing } } //Tree mutation _setDocumentType(token) { const name = token.name || ''; const publicId = token.publicId || ''; const systemId = token.systemId || ''; this.treeAdapter.setDocumentType(this.document, name, publicId, systemId); if (token.location) { const documentChildren = this.treeAdapter.getChildNodes(this.document); const docTypeNode = documentChildren.find((node) => this.treeAdapter.isDocumentTypeNode(node)); if (docTypeNode) { this.treeAdapter.setNodeSourceCodeLocation(docTypeNode, token.location); } } } _attachElementToTree(element, location) { if (this.options.sourceCodeLocationInfo) { const loc = location && Object.assign(Object.assign({}, location), { startTag: location }); this.treeAdapter.setNodeSourceCodeLocation(element, loc); } if (this._shouldFosterParentOnInsertion()) { this._fosterParentElement(element); } else { const parent = this.openElements.currentTmplContentOrNode; this.treeAdapter.appendChild(parent, element); } } _appendElement(token, namespaceURI) { const element = this.treeAdapter.createElement(token.tagName, namespaceURI, token.attrs); this._attachElementToTree(element, token.location); } _insertElement(token, namespaceURI) { const element = this.treeAdapter.createElement(token.tagName, namespaceURI, token.attrs); this._attachElementToTree(element, token.location); this.openElements.push(element, token.tagID); } _insertFakeElement(tagName, tagID) { const element = this.treeAdapter.createElement(tagName, html_js_1.NS.HTML, []); this._attachElementToTree(element, null); this.openElements.push(element, tagID); } _insertTemplate(token) { const tmpl = this.treeAdapter.createElement(token.tagName, html_js_1.NS.HTML, token.attrs); const content = this.treeAdapter.createDocumentFragment(); this.treeAdapter.setTemplateContent(tmpl, content); this._attachElementToTree(tmpl, token.location); this.openElements.push(tmpl, token.tagID); if (this.options.sourceCodeLocationInfo) this.treeAdapter.setNodeSourceCodeLocation(content, null); } _insertFakeRootElement() { const element = this.treeAdapter.createElement(html_js_1.TAG_NAMES.HTML, html_js_1.NS.HTML, []); if (this.options.sourceCodeLocationInfo) this.treeAdapter.setNodeSourceCodeLocation(element, null); this.treeAdapter.appendChild(this.openElements.current, element); this.openElements.push(element, html_js_1.TAG_ID.HTML); } _appendCommentNode(token, parent) { const commentNode = this.treeAdapter.createCommentNode(token.data); this.treeAdapter.appendChild(parent, commentNode); if (this.options.sourceCodeLocationInfo) { this.treeAdapter.setNodeSourceCodeLocation(commentNode, token.location); } } _insertCharacters(token) { let parent; let beforeElement; if (this._shouldFosterParentOnInsertion()) { ({ parent, beforeElement } = this._findFosterParentingLocation()); if (beforeElement) { this.treeAdapter.insertTextBefore(parent, token.chars, beforeElement); } else { this.treeAdapter.insertText(parent, token.chars); } } else { parent = this.openElements.currentTmplContentOrNode; this.treeAdapter.insertText(parent, token.chars); } if (!token.location) return; const siblings = this.treeAdapter.getChildNodes(parent); const textNodeIdx = beforeElement ? siblings.lastIndexOf(beforeElement) : siblings.length; const textNode = siblings[textNodeIdx - 1]; //NOTE: if we have a location assigned by another token, then just update the end position const tnLoc = this.treeAdapter.getNodeSourceCodeLocation(textNode); if (tnLoc) { const { endLine, endCol, endOffset } = token.location; this.treeAdapter.updateNodeSourceCodeLocation(textNode, { endLine, endCol, endOffset }); } else if (this.options.sourceCodeLocationInfo) { this.treeAdapter.setNodeSourceCodeLocation(textNode, token.location); } } _adoptNodes(donor, recipient) { for (let child = this.treeAdapter.getFirstChild(donor); child; child = this.treeAdapter.getFirstChild(donor)) { this.treeAdapter.detachNode(child); this.treeAdapter.appendChild(recipient, child); } } _setEndLocation(element, closingToken) { if (this.treeAdapter.getNodeSourceCodeLocation(element) && closingToken.location) { const ctLoc = closingToken.location; const tn = this.treeAdapter.getTagName(element); const endLoc = // NOTE: For cases like <p> <p> </p> - First 'p' closes without a closing // tag and for cases like <td> <p> </td> - 'p' closes without a closing tag. closingToken.type === token_js_1.TokenType.END_TAG && tn === closingToken.tagName ? { endTag: Object.assign({}, ctLoc), endLine: ctLoc.endLine, endCol: ctLoc.endCol, endOffset: ctLoc.endOffset, } : { endLine: ctLoc.startLine, endCol: ctLoc.startCol, endOffset: ctLoc.startOffset, }; this.treeAdapter.updateNodeSourceCodeLocation(element, endLoc); } } //Token processing shouldProcessStartTagTokenInForeignContent(token) { // Check that neither current === document, or ns === NS.HTML if (!this.currentNotInHTML) return false; let current; let currentTagId; if (this.openElements.stackTop === 0 && this.fragmentContext) { current = this.fragmentContext; currentTagId = this.fragmentContextID; } else { ({ current, currentTagId } = this.openElements); } if (token.tagID === html_js_1.TAG_ID.SVG && this.treeAdapter.getTagName(current) === html_js_1.TAG_NAMES.ANNOTATION_XML && this.treeAdapter.getNamespaceURI(current) === html_js_1.NS.MATHML) { return false; } return ( // Check that `current` is not an integration point for HTML or MathML elements. this.tokenizer.inForeignNode || // If it _is_ an integration point, then we might have to check that it is not an HTML // integration point. ((token.tagID === html_js_1.TAG_ID.MGLYPH || token.tagID === html_js_1.TAG_ID.MALIGNMARK) && !this._isIntegrationPoint(currentTagId, current, html_js_1.NS.HTML))); } _processToken(token) { switch (token.type) { case token_js_1.TokenType.CHARACTER: { this.onCharacter(token); break; } case token_js_1.TokenType.NULL_CHARACTER: { this.onNullCharacter(token); break; } case token_js_1.TokenType.COMMENT: { this.onComment(token); break; } case token_js_1.TokenType.DOCTYPE: { this.onDoctype(token); break; } case token_js_1.TokenType.START_TAG: { this._processStartTag(token); break; } case token_js_1.TokenType.END_TAG: { this.onEndTag(token); break; } case token_js_1.TokenType.EOF: { this.onEof(token); break; } case token_js_1.TokenType.WHITESPACE_CHARACTER: { this.onWhitespaceCharacter(token); break; } } } //Integration points _isIntegrationPoint(tid, element, foreignNS) { const ns = this.treeAdapter.getNamespaceURI(element); const attrs = this.treeAdapter.getAttrList(element); return foreignContent.isIntegrationPoint(tid, ns, attrs, foreignNS); } //Active formatting elements reconstruction _reconstructActiveFormattingElements() { const listLength = this.activeFormattingElements.entries.length; if (listLength) { const endIndex = this.activeFormattingElements.entries.findIndex((entry) => entry.type === formatting_element_list_js_1.EntryType.Marker || this.openElements.contains(entry.element)); const unopenIdx = endIndex < 0 ? listLength - 1 : endIndex - 1; for (let i = unopenIdx; i >= 0; i--) { const entry = this.activeFormattingElements.entries[i]; this._insertElement(entry.token, this.treeAdapter.getNamespaceURI(entry.element)); entry.element = this.openElements.current; } } } //Close elements _closeTableCell() { this.openElements.generateImpliedEndTags(); this.openElements.popUntilTableCellPopped(); this.activeFormattingElements.clearToLastMarker(); this.insertionMode = InsertionMode.IN_ROW; } _closePElement() { this.openElements.generateImpliedEndTagsWithExclusion(html_js_1.TAG_ID.P); this.openElements.popUntilTagNamePopped(html_js_1.TAG_ID.P); } //Insertion modes _resetInsertionMode() { for (let i = this.openElements.stackTop; i >= 0; i--) { //Insertion mode reset map switch (i === 0 && this.fragmentContext ? this.fragmentContextID : this.openElements.tagIDs[i]) { case html_js_1.TAG_ID.TR: this.insertionMode = InsertionMode.IN_ROW; return; case html_js_1.TAG_ID.TBODY: case html_js_1.TAG_ID.THEAD: case html_js_1.TAG_ID.TFOOT: this.insertionMode = InsertionMode.IN_TABLE_BODY; return; case html_js_1.TAG_ID.CAPTION: this.insertionMode = InsertionMode.IN_CAPTION; return; case html_js_1.TAG_ID.COLGROUP: this.insertionMode = InsertionMode.IN_COLUMN_GROUP; return; case html_js_1.TAG_ID.TABLE: this.insertionMode = InsertionMode.IN_TABLE; return; case html_js_1.TAG_ID.BODY: this.insertionMode = InsertionMode.IN_BODY; return; case html_js_1.TAG_ID.FRAMESET: this.insertionMode = InsertionMode.IN_FRAMESET; return; case html_js_1.TAG_ID.SELECT: this._resetInsertionModeForSelect(i); return; case html_js_1.TAG_ID.TEMPLATE: this.insertionMode = this.tmplInsertionModeStack[0]; return; case html_js_1.TAG_ID.HTML: this.insertionMode = this.headElement ? InsertionMode.AFTER_HEAD : InsertionMode.BEFORE_HEAD; return; case html_js_1.TAG_ID.TD: case html_js_1.TAG_ID.TH: if (i > 0) { this.insertionMode = InsertionMode.IN_CELL; return; } break; case html_js_1.TAG_ID.HEAD: if (i > 0) { this.insertionMode = InsertionMode.IN_HEAD; return; } break; } } this.insertionMode = InsertionMode.IN_BODY; } _resetInsertionModeForSelect(selectIdx) { if (selectIdx > 0) { for (let i = selectIdx - 1; i > 0; i--) { const tn = this.openElements.tagIDs[i]; if (tn === html_js_1.TAG_ID.TEMPLATE) { break; } else if (tn === html_js_1.TAG_ID.TABLE) { this.insertionMode = InsertionMode.IN_SELECT_IN_TABLE; return; } } } this.insertionMode = InsertionMode.IN_SELECT; } //Foster parenting _isElementCausesFosterParenting(tn) { return TABLE_STRUCTURE_TAGS.has(tn); } _shouldFosterParentOnInsertion() { return this.fosterParentingEnabled && this._isElementCausesFosterParenting(this.openElements.currentTagId); } _findFosterParentingLocation() { for (let i = this.openElements.stackTop; i >= 0; i--) { const openElement = this.openElements.items[i]; switch (this.openElements.tagIDs[i]) { case html_js_1.TAG_ID.TEMPLATE: if (this.treeAdapter.getNamespaceURI(openElement) === html_js_1.NS.HTML) { return { parent: this.treeAdapter.getTemplateContent(openElement), beforeElement: null }; } break; case html_js_1.TAG_ID.TABLE: { const parent = this.treeAdapter.getParentNode(openElement); if (parent) { return { parent, beforeElement: openElement }; } return { parent: this.openElements.items[i - 1], beforeElement: null }; } default: // Do nothing } } return { parent: this.openElements.items[0], beforeElement: null }; } _fosterParentElement(element) { const location = this._findFosterParentingLocation(); if (location.beforeElement) { this.treeAdapter.insertBefore(location.parent, element, location.beforeElement); } else { this.treeAdapter.appendChild(location.parent, element); } } //Special elements _isSpecialElement(element, id) { const ns = this.treeAdapter.getNamespaceURI(element); return html_js_1.SPECIAL_ELEMENTS[ns].has(id); } onCharacter(token) { this.skipNextNewLine = false; if (this.tokenizer.inForeignNode) { characterInForeignContent(this, token); return; } switch (this.insertionMode) { case InsertionMode.INITIAL: tokenInInitialMode(this, token); break; case InsertionMode.BEFORE_HTML: tokenBeforeHtml(this, token); break; case InsertionMode.BEFORE_HEAD: tokenBeforeHead(this, token); break; case InsertionMode.IN_HEAD: tokenInHead(this, token); break; case InsertionMode.IN_HEAD_NO_SCRIPT: tokenInHeadNoScript(this, token); break; case InsertionMode.AFTER_HEAD: tokenAfterHead(this, token); break; case InsertionMode.IN_BODY: case InsertionMode.IN_CAPTION: case InsertionMode.IN_CELL: case InsertionMode.IN_TEMPLATE: characterInBody(this, token); break; case InsertionMode.TEXT: case InsertionMode.IN_SELECT: case InsertionMode.IN_SELECT_IN_TABLE: this._insertCharacters(token); break; case InsertionMode.IN_TABLE: case InsertionMode.IN_TABLE_BODY: case InsertionMode.IN_ROW: characterInTable(this, token); break; case InsertionMode.IN_TABLE_TEXT: characterInTableText(this, token); break; case InsertionMode.IN_COLUMN_GROUP: tokenInColumnGroup(this, token); break; case InsertionMode.AFTER_BODY: tokenAfterBody(this, token); break; case InsertionMode.AFTER_AFTER_BODY: tokenAfterAfterBody(this, token); break; default: // Do nothing } } onNullCharacter(token) { this.skipNextNewLine = false; if (this.tokenizer.inForeignNode) { nullCharacterInForeignContent(this, token); return; } switch (this.insertionMode) { case InsertionMode.INITIAL: tokenInInitialMode(this, token); break; case InsertionMode.BEFORE_HTML: tokenBeforeHtml(this, token); break; case InsertionMode.BEFORE_HEAD: tokenBeforeHead(this, token); break; case InsertionMode.IN_HEAD: tokenInHead(this, token); break; case InsertionMode.IN_HEAD_NO_SCRIPT: tokenInHeadNoScript(this, token); break; case InsertionMode.AFTER_HEAD: tokenAfterHead(this, token); break; case InsertionMode.TEXT: this._insertCharacters(token); break; case InsertionMode.IN_TABLE: case InsertionMode.IN_TABLE_BODY: case InsertionMode.IN_ROW: characterInTable(this, token); break; case InsertionMode.IN_COLUMN_GROUP: tokenInColumnGroup(this, token); break; case InsertionMode.AFTER_BODY: tokenAfterBody(this, token); break; case InsertionMode.AFTER_AFTER_BODY: tokenAfterAfterBody(this, token); break; default: // Do nothing } } onComment(token) { this.skipNextNewLine = false; if (this.currentNotInHTML) { appendComment(this, token); return; } switch (this.insertionMode) { case InsertionMode.INITIAL: case InsertionMode.BEFORE_HTML: case InsertionMode.BEFORE_HEAD: case InsertionMode.IN_HEAD: case InsertionMode.IN_HEAD_NO_SCRIPT: case InsertionMode.AFTER_HEAD: case InsertionMode.IN_BODY: case InsertionMode.IN_TABLE: case InsertionMode.IN_CAPTION: case InsertionMode.IN_COLUMN_GROUP: case InsertionMode.IN_TABLE_BODY: case InsertionMode.IN_ROW: case InsertionMode.IN_CELL: case InsertionMode.IN_SELECT: case InsertionMode.IN_SELECT_IN_TABLE: case InsertionMode.IN_TEMPLATE: case InsertionMode.IN_FRAMESET: case InsertionMode.AFTER_FRAMESET: appendComment(this, token); break; case InsertionMode.IN_TABLE_TEXT: tokenInTableText(this, token); break; case InsertionMode.AFTER_BODY: appendCommentToRootHtmlElement(this, token); break; case InsertionMode.AFTER_AFTER_BODY: case InsertionMode.AFTER_AFTER_FRAMESET: appendCommentToDocument(this, token); break; default: // Do nothing } } onDoctype(token) { this.skipNextNewLine = false; switch (this.insertionMode) { case InsertionMode.INITIAL: doctypeInInitialMode(this, token); break; case InsertionMode.BEFORE_HEAD: case InsertionMode.IN_HEAD: case InsertionMode.IN_HEAD_NO_SCRIPT: case InsertionMode.AFTER_HEAD: this._err(token, error_codes_js_1.ERR.misplacedDoctype); break; case InsertionMode.IN_TABLE_TEXT: tokenInTableText(this, token); break; default: // Do nothing } } onStartTag(token) { this.skipNextNewLine = false; this.currentToken = token; this._processStartTag(token); if (token.selfClosing && !token.ackSelfClosing) { this._err(token, error_codes_js_1.ERR.nonVoidHtmlElementStartTagWithTrailingSolidus); } } /** * Processes a given start tag. * * `onStartTag` checks if a self-closing tag was recognized. When a token * is moved inbetween multiple insertion modes, this check for self-closing * could lead to false positives. To avoid this, `_processStartTag` is used * for nested calls. * * @param token The token to process. */ _processStartTag(token) { if (this.shouldProcessStartTagTokenInForeignContent(token)) { startTagInForeignContent(this, token); } else { this._startTagOutsideForeignContent(token); } } _startTagOutsideForeignContent(token) { switch (this.insertionMode) { case InsertionMode.INITIAL: tokenInInitialMode(this, token); break; case InsertionMode.BEFORE_HTML: startTagBeforeHtml(this, token); break; case InsertionMode.BEFORE_HEAD: startTagBeforeHead(this, token); break; case InsertionMode.IN_HEAD: startTagInHead(this, token); break; case InsertionMode.IN_HEAD_NO_SCRIPT: startTagInHeadNoScript(this, token); break; case InsertionMode.AFTER_HEAD: startTagAfterHead(this, token); break; case InsertionMode.IN_BODY: startTagInBody(this, token); break; case InsertionMode.IN_TABLE: startTagInTable(this, token); break; case InsertionMode.IN_TABLE_TEXT: tokenInTableText(this, token); break; case InsertionMode.IN_CAPTION: startTagInCaption(this, token); break; case InsertionMode.IN_COLUMN_GROUP: startTagInColumnGroup(this, token); break; case InsertionMode.IN_TABLE_BODY: startTagInTableBody(this, token); break; case InsertionMode.IN_ROW: startTagInRow(this, token); break; case InsertionMode.IN_CELL: startTagInCell(this, token); break; case InsertionMode.IN_SELECT: startTagInSelect(this, token); break; case InsertionMode.IN_SELECT_IN_TABLE: startTagInSelectInTable(this, token); break; case InsertionMode.IN_TEMPLATE: startTagInTemplate(this, token); break; case InsertionMode.AFTER_BODY: startTagAfterBody(this, token); break; case InsertionMode.IN_FRAMESET: startTagInFrameset(this, token); break; case InsertionMode.AFTER_FRAMESET: startTagAfterFrameset(this, token); break; case InsertionMode.AFTER_AFTER_BODY: startTagAfterAfterBody(this, token); break; case InsertionMode.AFTER_AFTER_FRAMESET: startTagAfterAfterFrameset(this, token); break; default: // Do nothing } } onEndTag(token) { this.skipNextNewLine = false; this.currentToken = token; if (this.currentNotInHTML) { endTagInForeignContent(this, token); } else { this._endTagOutsideForeignContent(token); } } _endTagOutsideForeignContent(token) { switch (this.insertionMode) { case InsertionMode.INITIAL: tokenInInitialMode(this, token); break; case InsertionMode.BEFORE_HTML: endTagBeforeHtml(this, token); break; case InsertionMode.BEFORE_HEAD: endTagBeforeHead(this, token); break; case InsertionMode.IN_HEAD: endTagInHead(this, token); break; case InsertionMode.IN_HEAD_NO_SCRIPT: endTagInHeadNoScript(this, token); break; case InsertionMode.AFTER_HEAD: endTagAfterHead(this, token); break; case InsertionMode.IN_BODY: endTagInBody(this, token); break; case InsertionMode.TEXT: endTagInText(this, token); break; case InsertionMode.IN_TABLE: endTagInTable(this, token); break; case InsertionMode.IN_TABLE_TEXT: tokenInTableText(this, token); break; case InsertionMode.IN_CAPTION: endTagInCaption(this, token); break; case InsertionMode.IN_COLUMN_GROUP: endTagInColumnGroup(this, token); break; case InsertionMode.IN_TABLE_BODY: endTagInTableBody(this, token); break; case InsertionMode.IN_ROW: endTagInRow(this, token); break; case InsertionMode.IN_CELL: endTagInCell(this, token); break; case InsertionMode.IN_SELECT: endTagInSelect(this, token); break; case InsertionMode.IN_SELECT_IN_TABLE: endTagInSelectInTable(this, token); break; case InsertionMode.IN_TEMPLATE: endTagInTemplate(this, token); break; case InsertionMode.AFTER_BODY: endTagAfterBody(this, token); break; case InsertionMode.IN_FRAMESET: endTagInFrameset(this, token); break; case InsertionMode.AFTER_FRAMESET: endTagAfterFrameset(this, token); break; case InsertionMode.AFTER_AFTER_BODY: tokenAfterAfterBody(this, token); break; default: // Do nothing } } onEof(token) { switch (this.insertionMode) { case InsertionMode.INITIAL: tokenInInitialMode(this, token); break; case InsertionMode.BEFORE_HTML: tokenBeforeHtml(this, token); break; case InsertionMode.BEFORE_HEAD: tokenBeforeHead(this, token); break; case InsertionMode.IN_HEAD: tokenInHead(this, token); break; case InsertionMode.IN_HEAD_NO_SCRIPT: tokenInHeadNoScript(this, token); break; case InsertionMode.AFTER_HEAD: tokenAfterHead(this, token); break; case InsertionMode.IN_BODY: case InsertionMode.IN_TABLE: case InsertionMode.IN_CAPTION: case InsertionMode.IN_COLUMN_GROUP: case InsertionMode.IN_TABLE_BODY: case InsertionMode.IN_ROW: case InsertionMode.IN_CELL: case InsertionMode.IN_SELECT: case InsertionMode.IN_SELECT_IN_TABLE: eofInBody(this, token); break; case InsertionMode.TEXT: eofInText(this, token); break; case InsertionMode.IN_TABLE_TEXT: tokenInTableText(this, token); break; case InsertionMode.IN_TEMPLATE: eofInTemplate(this, token); break; case InsertionMode.AFTER_BODY: case InsertionMode.IN_FRAMESET: case InsertionMode.AFTER_FRAMESET: case InsertionMode.AFTER_AFTER_BODY: case InsertionMode.AFTER_AFTER_FRAMESET: stopParsing(this, token); break; default: // Do nothing } } onWhitespaceCharacter(token) { if (this.skipNextNewLine) { this.skipNextNewLine = false; if (token.chars.charCodeAt(0) === unicode.CODE_POINTS.LINE_FEED) { if (token.chars.length === 1) { return; } token.chars = token.chars.substr(1); } } if (this.tokenizer.inForeignNode) { this._insertCharacters(token); return; } switch (this.insertionMode) { case InsertionMode.IN_HEAD: case InsertionMode.IN_HEAD_NO_SCRIPT: case InsertionMode.AFTER_HEAD: case InsertionMode.TEXT: case InsertionMode.IN_COLUMN_GROUP: case InsertionMode.IN_SELECT: case InsertionMode.IN_SELECT_IN_TABLE: case InsertionMode.IN_FRAMESET: case InsertionMode.AFTER_FRAMESET: this._insertCharacters(token); break; case InsertionMode.IN_BODY: case InsertionMode.IN_CAPTION: case InsertionMode.IN_CELL: case InsertionMode.IN_TEMPLATE: case InsertionMode.AFTER_BODY: case InsertionMode.AFTER_AFTER_BODY: case InsertionMode.AFTER_AFTER_FRAMESET: whitespaceCharacterInBody(this, token); break; case InsertionMode.IN_TABLE: case InsertionMode.IN_TABLE_BODY: case InsertionMode.IN_ROW: characterInTable(this, token); break; case InsertionMode.IN_TABLE_TEXT: whitespaceCharacterInTableText(this, token); break; default: // Do nothing } } } exports.Parser = Parser; //Adoption agency algorithm //(see: http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#adoptionAgency) //------------------------------------------------------------------ //Steps 5-8 of the algorithm function aaObtainFormattingElementEntry(p, token) { let formattingElementEntry = p.activeFormattingElements.getElementEntryInScopeWithTagName(token.tagName); if (formattingElementEntry) { if (!p.openElements.contains(formattingElementEntry.element)) { p.activeFormattingElements.removeEntry(formattingElementEntry); formattingElementEntry = null; } else if (!p.openElements.hasInScope(token.tagID)) { formattingElementEntry = null; } } else { genericEndTagInBody(p, token); } return formattingElementEntry; } //Steps 9 and 10 of the algorithm function aaObtainFurthestBlock(p, formattingElementEntry) { let furthestBlock = null; let idx = p.openElements.stackTop; for (; idx >= 0; idx--) { const element = p.openElements.items[idx]; if (element === formattingElementEntry.element) { break; } if (p._isSpecialElement(element, p.openElements.tagIDs[idx])) { furthestBlock = element; } } if (!furthestBlock) { p.openElements.shortenToLength(idx < 0 ? 0 : idx); p.activeFormattingElements.removeEntry(formattingElementEntry); } return furthestBlock; } //Step 13 of the algorithm function aaInnerLoop(p, furthestBlock, formattingElement) { let lastElement = furthestBlock; let nextElement = p.openElements.getCommonAncestor(furthestBlock); for (let i = 0, element = nextElement; element !== formattingElement; i++, element = nextElement) { //NOTE: store the next element for the next loop iteration (it may be deleted from the stack by step 9.5) nextElement = p.openElements.getCommonAncestor(element); const elementEntry = p.activeFormattingElements.getElementEntry(element); const counterOverflow = elementEntry && i >= AA_INNER_LOOP_ITER; const shouldRemoveFromOpenElements = !elementEntry || counterOverflow; if (shouldRemoveFromOpenElements) { if (counterOverflow) { p.activeFormattingElements.removeEntry(elementEntry); } p.openElements.remove(element); } else { element = aaRecreateElementFromEntry(p, elementEntry); if (lastElement === furthestBlock) { p.activeFormattingElements.bookmark = elementEntry; } p.treeAdapter.detachNode(lastElement); p.treeAdapter.appendChild(element, lastElement); lastElement = element; } } return lastElement; } //Step 13.7 of the algorithm function aaRecreateElementFromEntry(p, elementEntry) { const ns = p.treeAdapter.getNamespaceURI(elementEntry.element); const newElement = p.treeAdapter.createElement(elementEntry.token.tagName, ns, elementEntry.token.attrs); p.openElements.replace(elementEntry.element, newElement); elementEntry.element = newElement; return newElement; } //Step 14 of the algorithm function aaInsertLastNodeInCommonAncestor(p, commonAncestor, lastElement) { const tn = p.treeAdapter.getTagName(commonAncestor); const tid = (0, html_js_1.getTagID)(tn); if (p._isElementCausesFosterParenting(tid)) { p._fosterParentElement(lastElement); } else { const ns = p.treeAdapter.getNamespaceURI(commonAncestor); if (tid === html_js_1.TAG_ID.TEMPLATE && ns === html_js_1.NS.HTML) { commonAncestor = p.treeAdapter.getTemplateContent(commonAncestor); } p.treeAdapter.appendChild(commonAncestor, lastElement); } } //Steps 15-19 of the algorithm function aaReplaceFormattingElement(p, furthestBlock, formattingElementEntry) { const ns = p.treeAdapter.getNamespaceURI(formattingElementEntry.element); const { token } = formattingElementEntry; const newElement = p.treeAdapter.createElement(token.tagName, ns, token.attrs); p._adoptNodes(furthestBlock, newElement); p.treeAdapter.appendChild(furthestBlock, newElement); p.activeFormattingElements.insertElementAfterBookmark(newElement, token); p.activeFormattingElements.removeEntry(formattingElementEntry); p.openElements.remove(formattingElementEntry.element); p.openElements.insertAfter(furthestBlock, newElement, token.tagID); } //Algorithm entry point function callAdoptionAgency(p, token) { for (let i = 0; i < AA_OUTER_LOOP_ITER; i++) { const formattingElementEntry = aaObtainFormattingElementEntry(p, token); if (!formattingElementEntry) { break; } const furthestBlock = aaObtainFurthestBlock(p, formattingElementEntry); if (!furthestBlock) { break; } p.activeFormattingElements.bookmark = formattingElementEntry; const lastElement = aaInnerLoop(p, furthestBlock, formattingElementEntry.element); const commonAncestor = p.openElements.getCommonAncestor(formattingElementEntry.element); p.treeAdapter.detachNode(lastElement); if (commonAncestor) aaInsertLastNodeInCommonAncestor(p, commonAncestor, lastElement); aaReplaceFormattingElement(p, furthestBlock, formattingElementEntry); } } //Generic token handlers //------------------------------------------------------------------ function appendComment(p, token) { p._appendCommentNode(token, p.openElements.currentTmplContentOrNode); } function appendCommentToRootHtmlElement(p, token) { p._appendCommentNode(token, p.openElements.items[0]); } function appendCommentToDocument(p, token) { p._appendCommentNode(token, p.document); } function stopParsing(p, token) { p.stopped = true; // NOTE: Set end locations for elements that remain on the open element stack. if (token.location) { // NOTE: If we are not in a fragment, `html` and `body` will stay on the stack. // This is a problem, as we might overwrite their end position here. const target = p.fragmentContext ? 0 : 2; for (let i = p.openElements.stackTop; i >= target; i--) { p._setEndLocation(p.openElements.items[i], token); } // Handle `html` and `body` if (!p.fragmentContext && p.openElements.stackTop >= 0) { const htmlElement = p.openElements.items[0]; const htmlLocation = p.treeAdapter.getNodeSourceCodeLocation(htmlElement); if (htmlLocation && !htmlLocation.endTag) { p._setEndLocation(htmlElement, token); if (p.openElements.stackTop >= 1) { const bodyElement = p.openElements.items[1]; const bodyLocation = p.treeAdapter.getNodeSourceCodeLocation(bodyElement); if (bodyLocation && !bodyLocation.endTag) { p._setEndLocation(bodyElement, token); } } } } } } // The "initial" insertion mode //------------------------------------------------------------------ function doctypeInInitialMode(p, token) { p._setDocumentType(token); const mode = token.forceQuirks ? html_js_1.DOCUMENT_MODE.QUIRKS : doctype.getDocumentMode(token); if (!doctype.isConforming(token)) { p._err(token, error_codes_js_1.ERR.nonConformingDoctype); } p.treeAdapter.setDocumentMode(p.document, mode); p.insertionMode = InsertionMode.BEFORE_HTML; } function tokenInInitialMode(p, token) { p._err(token, error_codes_js_1.ERR.missingDoctype, true); p.treeAdapter.setDocumentMode(p.document, html_js_1.DOCUMENT_MODE.QUIRKS); p.insertionMode = InsertionMode.BEFORE_HTML; p._processToken(token); } // The "before html" insertion mode //------------------------------------------------------------------ function startTagBeforeHtml(p, token) { if (token.tagID === html_js_1.TAG_ID.HTML) { p._insertElement(token, html_js_1.NS.HTML); p.insertionMode = InsertionMode.BEFORE_HEAD; } else { tokenBeforeHtml(p, token); } } function endTagBeforeHtml(p, token) { const tn = token.tagID; if (tn === html_js_1.TAG_ID.HTML || tn === html_js_1.TAG_ID.HEAD || tn === html_js_1.TAG_ID.BODY || tn === html_js_1.TAG_ID.BR) { tokenBeforeHtml(p, token); } } function tokenBeforeHtml(p, token) { p._insertFakeRootElement(); p.insertionMode = InsertionMode.BEFORE_HEAD; p._processToken(token); } // The "before head" insertion mode //------------------------------------------------------------------ function startTagBeforeHead(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.HTML: { startTagInBody(p, token); break; } case html_js_1.TAG_ID.HEAD: { p._insertElement(token, html_js_1.NS.HTML); p.headElement = p.openElements.current; p.insertionMode = InsertionMode.IN_HEAD; break; } default: { tokenBeforeHead(p, token); } } } function endTagBeforeHead(p, token) { const tn = token.tagID; if (tn === html_js_1.TAG_ID.HEAD || tn === html_js_1.TAG_ID.BODY || tn === html_js_1.TAG_ID.HTML || tn === html_js_1.TAG_ID.BR) { tokenBeforeHead(p, token); } else { p._err(token, error_codes_js_1.ERR.endTagWithoutMatchingOpenElement); } } function tokenBeforeHead(p, token) { p._insertFakeElement(html_js_1.TAG_NAMES.HEAD, html_js_1.TAG_ID.HEAD); p.headElement = p.openElements.current; p.insertionMode = InsertionMode.IN_HEAD; p._processToken(token); } // The "in head" insertion mode //------------------------------------------------------------------ function startTagInHead(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.HTML: { startTagInBody(p, token); break; } case html_js_1.TAG_ID.BASE: case html_js_1.TAG_ID.BASEFONT: case html_js_1.TAG_ID.BGSOUND: case html_js_1.TAG_ID.LINK: case html_js_1.TAG_ID.META: { p._appendElement(token, html_js_1.NS.HTML); token.ackSelfClosing = true; break; } case html_js_1.TAG_ID.TITLE: { p._switchToTextParsing(token, index_js_1.TokenizerMode.RCDATA); break; } case html_js_1.TAG_ID.NOSCRIPT: { if (p.options.scriptingEnabled) { p._switchToTextParsing(token, index_js_1.TokenizerMode.RAWTEXT); } else { p._insertElement(token, html_js_1.NS.HTML); p.insertionMode = InsertionMode.IN_HEAD_NO_SCRIPT; } break; } case html_js_1.TAG_ID.NOFRAMES: case html_js_1.TAG_ID.STYLE: { p._switchToTextParsing(token, index_js_1.TokenizerMode.RAWTEXT); break; } case html_js_1.TAG_ID.SCRIPT: { p._switchToTextParsing(token, index_js_1.TokenizerMode.SCRIPT_DATA); break; } case html_js_1.TAG_ID.TEMPLATE: { p._insertTemplate(token); p.activeFormattingElements.insertMarker(); p.framesetOk = false; p.insertionMode = InsertionMode.IN_TEMPLATE; p.tmplInsertionModeStack.unshift(InsertionMode.IN_TEMPLATE); break; } case html_js_1.TAG_ID.HEAD: { p._err(token, error_codes_js_1.ERR.misplacedStartTagForHeadElement); break; } default: { tokenInHead(p, token); } } } function endTagInHead(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.HEAD: { p.openElements.pop(); p.insertionMode = InsertionMode.AFTER_HEAD; break; } case html_js_1.TAG_ID.BODY: case html_js_1.TAG_ID.BR: case html_js_1.TAG_ID.HTML: { tokenInHead(p, token); break; } case html_js_1.TAG_ID.TEMPLATE: { if (p.openElements.tmplCount > 0) { p.openElements.generateImpliedEndTagsThoroughly(); if (p.openElements.currentTagId !== html_js_1.TAG_ID.TEMPLATE) { p._err(token, error_codes_js_1.ERR.closingOfElementWithOpenChildElements); } p.openElements.popUntilTagNamePopped(html_js_1.TAG_ID.TEMPLATE); p.activeFormattingElements.clearToLastMarker(); p.tmplInsertionModeStack.shift(); p._resetInsertionMode(); } else { p._err(token, error_codes_js_1.ERR.endTagWithoutMatchingOpenElement); } break; } default: { p._err(token, error_codes_js_1.ERR.endTagWithoutMatchingOpenElement); } } } function tokenInHead(p, token) { p.openElements.pop(); p.insertionMode = InsertionMode.AFTER_HEAD; p._processToken(token); } // The "in head no script" insertion mode //------------------------------------------------------------------ function startTagInHeadNoScript(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.HTML: { startTagInBody(p, token); break; } case html_js_1.TAG_ID.BASEFONT: case html_js_1.TAG_ID.BGSOUND: case html_js_1.TAG_ID.HEAD: case html_js_1.TAG_ID.LINK: case html_js_1.TAG_ID.META: case html_js_1.TAG_ID.NOFRAMES: case html_js_1.TAG_ID.STYLE: { startTagInHead(p, token); break; } case html_js_1.TAG_ID.NOSCRIPT: { p._err(token, error_codes_js_1.ERR.nestedNoscriptInHead); break; } default: { tokenInHeadNoScript(p, token); } } } function endTagInHeadNoScript(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.NOSCRIPT: { p.openElements.pop(); p.insertionMode = InsertionMode.IN_HEAD; break; } case html_js_1.TAG_ID.BR: { tokenInHeadNoScript(p, token); break; } default: { p._err(token, error_codes_js_1.ERR.endTagWithoutMatchingOpenElement); } } } function tokenInHeadNoScript(p, token) { const errCode = token.type === token_js_1.TokenType.EOF ? error_codes_js_1.ERR.openElementsLeftAfterEof : error_codes_js_1.ERR.disallowedContentInNoscriptInHead; p._err(token, errCode); p.openElements.pop(); p.insertionMode = InsertionMode.IN_HEAD; p._processToken(token); } // The "after head" insertion mode //------------------------------------------------------------------ function startTagAfterHead(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.HTML: { startTagInBody(p, token); break; } case html_js_1.TAG_ID.BODY: { p._insertElement(token, html_js_1.NS.HTML); p.framesetOk = false; p.insertionMode = InsertionMode.IN_BODY; break; } case html_js_1.TAG_ID.FRAMESET: { p._insertElement(token, html_js_1.NS.HTML); p.insertionMode = InsertionMode.IN_FRAMESET; break; } case html_js_1.TAG_ID.BASE: case html_js_1.TAG_ID.BASEFONT: case html_js_1.TAG_ID.BGSOUND: case html_js_1.TAG_ID.LINK: case html_js_1.TAG_ID.META: case html_js_1.TAG_ID.NOFRAMES: case html_js_1.TAG_ID.SCRIPT: case html_js_1.TAG_ID.STYLE: case html_js_1.TAG_ID.TEMPLATE: case html_js_1.TAG_ID.TITLE: { p._err(token, error_codes_js_1.ERR.abandonedHeadElementChild); p.openElements.push(p.headElement, html_js_1.TAG_ID.HEAD); startTagInHead(p, token); p.openElements.remove(p.headElement); break; } case html_js_1.TAG_ID.HEAD: { p._err(token, error_codes_js_1.ERR.misplacedStartTagForHeadElement); break; } default: { tokenAfterHead(p, token); } } } function endTagAfterHead(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.BODY: case html_js_1.TAG_ID.HTML: case html_js_1.TAG_ID.BR: { tokenAfterHead(p, token); break; } case html_js_1.TAG_ID.TEMPLATE: { endTagInHead(p, token); break; } default: { p._err(token, error_codes_js_1.ERR.endTagWithoutMatchingOpenElement); } } } function tokenAfterHead(p, token) { p._insertFakeElement(html_js_1.TAG_NAMES.BODY, html_js_1.TAG_ID.BODY); p.insertionMode = InsertionMode.IN_BODY; modeInBody(p, token); } // The "in body" insertion mode //------------------------------------------------------------------ function modeInBody(p, token) { switch (token.type) { case token_js_1.TokenType.CHARACTER: { characterInBody(p, token); break; } case token_js_1.TokenType.WHITESPACE_CHARACTER: { whitespaceCharacterInBody(p, token); break; } case token_js_1.TokenType.COMMENT: { appendComment(p, token); break; } case token_js_1.TokenType.START_TAG: { startTagInBody(p, token); break; } case token_js_1.TokenType.END_TAG: { endTagInBody(p, token); break; } case token_js_1.TokenType.EOF: { eofInBody(p, token); break; } default: // Do nothing } } function whitespaceCharacterInBody(p, token) { p._reconstructActiveFormattingElements(); p._insertCharacters(token); } function characterInBody(p, token) { p._reconstructActiveFormattingElements(); p._insertCharacters(token); p.framesetOk = false; } function htmlStartTagInBody(p, token) { if (p.openElements.tmplCount === 0) { p.treeAdapter.adoptAttributes(p.openElements.items[0], token.attrs); } } function bodyStartTagInBody(p, token) { const bodyElement = p.openElements.tryPeekProperlyNestedBodyElement(); if (bodyElement && p.openElements.tmplCount === 0) { p.framesetOk = false; p.treeAdapter.adoptAttributes(bodyElement, token.attrs); } } function framesetStartTagInBody(p, token) { const bodyElement = p.openElements.tryPeekProperlyNestedBodyElement(); if (p.framesetOk && bodyElement) { p.treeAdapter.detachNode(bodyElement); p.openElements.popAllUpToHtmlElement(); p._insertElement(token, html_js_1.NS.HTML); p.insertionMode = InsertionMode.IN_FRAMESET; } } function addressStartTagInBody(p, token) { if (p.openElements.hasInButtonScope(html_js_1.TAG_ID.P)) { p._closePElement(); } p._insertElement(token, html_js_1.NS.HTML); } function numberedHeaderStartTagInBody(p, token) { if (p.openElements.hasInButtonScope(html_js_1.TAG_ID.P)) { p._closePElement(); } if ((0, html_js_1.isNumberedHeader)(p.openElements.currentTagId)) { p.openElements.pop(); } p._insertElement(token, html_js_1.NS.HTML); } function preStartTagInBody(p, token) { if (p.openElements.hasInButtonScope(html_js_1.TAG_ID.P)) { p._closePElement(); } p._insertElement(token, html_js_1.NS.HTML); //NOTE: If the next token is a U+000A LINE FEED (LF) character token, then ignore that token and move //on to the next one. (Newlines at the start of pre blocks are ignored as an authoring convenience.) p.skipNextNewLine = true; p.framesetOk = false; } function formStartTagInBody(p, token) { const inTemplate = p.openElements.tmplCount > 0; if (!p.formElement || inTemplate) { if (p.openElements.hasInButtonScope(html_js_1.TAG_ID.P)) { p._closePElement(); } p._insertElement(token, html_js_1.NS.HTML); if (!inTemplate) { p.formElement = p.openElements.current; } } } function listItemStartTagInBody(p, token) { p.framesetOk = false; const tn = token.tagID; for (let i = p.openElements.stackTop; i >= 0; i--) { const elementId = p.openElements.tagIDs[i]; if ((tn === html_js_1.TAG_ID.LI && elementId === html_js_1.TAG_ID.LI) || ((tn === html_js_1.TAG_ID.DD || tn === html_js_1.TAG_ID.DT) && (elementId === html_js_1.TAG_ID.DD || elementId === html_js_1.TAG_ID.DT))) { p.openElements.generateImpliedEndTagsWithExclusion(elementId); p.openElements.popUntilTagNamePopped(elementId); break; } if (elementId !== html_js_1.TAG_ID.ADDRESS && elementId !== html_js_1.TAG_ID.DIV && elementId !== html_js_1.TAG_ID.P && p._isSpecialElement(p.openElements.items[i], elementId)) { break; } } if (p.openElements.hasInButtonScope(html_js_1.TAG_ID.P)) { p._closePElement(); } p._insertElement(token, html_js_1.NS.HTML); } function plaintextStartTagInBody(p, token) { if (p.openElements.hasInButtonScope(html_js_1.TAG_ID.P)) { p._closePElement(); } p._insertElement(token, html_js_1.NS.HTML); p.tokenizer.state = index_js_1.TokenizerMode.PLAINTEXT; } function buttonStartTagInBody(p, token) { if (p.openElements.hasInScope(html_js_1.TAG_ID.BUTTON)) { p.openElements.generateImpliedEndTags(); p.openElements.popUntilTagNamePopped(html_js_1.TAG_ID.BUTTON); } p._reconstructActiveFormattingElements(); p._insertElement(token, html_js_1.NS.HTML); p.framesetOk = false; } function aStartTagInBody(p, token) { const activeElementEntry = p.activeFormattingElements.getElementEntryInScopeWithTagName(html_js_1.TAG_NAMES.A); if (activeElementEntry) { callAdoptionAgency(p, token); p.openElements.remove(activeElementEntry.element); p.activeFormattingElements.removeEntry(activeElementEntry); } p._reconstructActiveFormattingElements(); p._insertElement(token, html_js_1.NS.HTML); p.activeFormattingElements.pushElement(p.openElements.current, token); } function bStartTagInBody(p, token) { p._reconstructActiveFormattingElements(); p._insertElement(token, html_js_1.NS.HTML); p.activeFormattingElements.pushElement(p.openElements.current, token); } function nobrStartTagInBody(p, token) { p._reconstructActiveFormattingElements(); if (p.openElements.hasInScope(html_js_1.TAG_ID.NOBR)) { callAdoptionAgency(p, token); p._reconstructActiveFormattingElements(); } p._insertElement(token, html_js_1.NS.HTML); p.activeFormattingElements.pushElement(p.openElements.current, token); } function appletStartTagInBody(p, token) { p._reconstructActiveFormattingElements(); p._insertElement(token, html_js_1.NS.HTML); p.activeFormattingElements.insertMarker(); p.framesetOk = false; } function tableStartTagInBody(p, token) { if (p.treeAdapter.getDocumentMode(p.document) !== html_js_1.DOCUMENT_MODE.QUIRKS && p.openElements.hasInButtonScope(html_js_1.TAG_ID.P)) { p._closePElement(); } p._insertElement(token, html_js_1.NS.HTML); p.framesetOk = false; p.insertionMode = InsertionMode.IN_TABLE; } function areaStartTagInBody(p, token) { p._reconstructActiveFormattingElements(); p._appendElement(token, html_js_1.NS.HTML); p.framesetOk = false; token.ackSelfClosing = true; } function isHiddenInput(token) { const inputType = (0, token_js_1.getTokenAttr)(token, html_js_1.ATTRS.TYPE); return inputType != null && inputType.toLowerCase() === HIDDEN_INPUT_TYPE; } function inputStartTagInBody(p, token) { p._reconstructActiveFormattingElements(); p._appendElement(token, html_js_1.NS.HTML); if (!isHiddenInput(token)) { p.framesetOk = false; } token.ackSelfClosing = true; } function paramStartTagInBody(p, token) { p._appendElement(token, html_js_1.NS.HTML); token.ackSelfClosing = true; } function hrStartTagInBody(p, token) { if (p.openElements.hasInButtonScope(html_js_1.TAG_ID.P)) { p._closePElement(); } p._appendElement(token, html_js_1.NS.HTML); p.framesetOk = false; token.ackSelfClosing = true; } function imageStartTagInBody(p, token) { token.tagName = html_js_1.TAG_NAMES.IMG; token.tagID = html_js_1.TAG_ID.IMG; areaStartTagInBody(p, token); } function textareaStartTagInBody(p, token) { p._insertElement(token, html_js_1.NS.HTML); //NOTE: If the next token is a U+000A LINE FEED (LF) character token, then ignore that token and move //on to the next one. (Newlines at the start of textarea elements are ignored as an authoring convenience.) p.skipNextNewLine = true; p.tokenizer.state = index_js_1.TokenizerMode.RCDATA; p.originalInsertionMode = p.insertionMode; p.framesetOk = false; p.insertionMode = InsertionMode.TEXT; } function xmpStartTagInBody(p, token) { if (p.openElements.hasInButtonScope(html_js_1.TAG_ID.P)) { p._closePElement(); } p._reconstructActiveFormattingElements(); p.framesetOk = false; p._switchToTextParsing(token, index_js_1.TokenizerMode.RAWTEXT); } function iframeStartTagInBody(p, token) { p.framesetOk = false; p._switchToTextParsing(token, index_js_1.TokenizerMode.RAWTEXT); } //NOTE: here we assume that we always act as an user agent with enabled plugins, so we parse //<noembed> as rawtext. function noembedStartTagInBody(p, token) { p._switchToTextParsing(token, index_js_1.TokenizerMode.RAWTEXT); } function selectStartTagInBody(p, token) { p._reconstructActiveFormattingElements(); p._insertElement(token, html_js_1.NS.HTML); p.framesetOk = false; p.insertionMode = p.insertionMode === InsertionMode.IN_TABLE || p.insertionMode === InsertionMode.IN_CAPTION || p.insertionMode === InsertionMode.IN_TABLE_BODY || p.insertionMode === InsertionMode.IN_ROW || p.insertionMode === InsertionMode.IN_CELL ? InsertionMode.IN_SELECT_IN_TABLE : InsertionMode.IN_SELECT; } function optgroupStartTagInBody(p, token) { if (p.openElements.currentTagId === html_js_1.TAG_ID.OPTION) { p.openElements.pop(); } p._reconstructActiveFormattingElements(); p._insertElement(token, html_js_1.NS.HTML); } function rbStartTagInBody(p, token) { if (p.openElements.hasInScope(html_js_1.TAG_ID.RUBY)) { p.openElements.generateImpliedEndTags(); } p._insertElement(token, html_js_1.NS.HTML); } function rtStartTagInBody(p, token) { if (p.openElements.hasInScope(html_js_1.TAG_ID.RUBY)) { p.openElements.generateImpliedEndTagsWithExclusion(html_js_1.TAG_ID.RTC); } p._insertElement(token, html_js_1.NS.HTML); } function mathStartTagInBody(p, token) { p._reconstructActiveFormattingElements(); foreignContent.adjustTokenMathMLAttrs(token); foreignContent.adjustTokenXMLAttrs(token); if (token.selfClosing) { p._appendElement(token, html_js_1.NS.MATHML); } else { p._insertElement(token, html_js_1.NS.MATHML); } token.ackSelfClosing = true; } function svgStartTagInBody(p, token) { p._reconstructActiveFormattingElements(); foreignContent.adjustTokenSVGAttrs(token); foreignContent.adjustTokenXMLAttrs(token); if (token.selfClosing) { p._appendElement(token, html_js_1.NS.SVG); } else { p._insertElement(token, html_js_1.NS.SVG); } token.ackSelfClosing = true; } function genericStartTagInBody(p, token) { p._reconstructActiveFormattingElements(); p._insertElement(token, html_js_1.NS.HTML); } function startTagInBody(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.I: case html_js_1.TAG_ID.S: case html_js_1.TAG_ID.B: case html_js_1.TAG_ID.U: case html_js_1.TAG_ID.EM: case html_js_1.TAG_ID.TT: case html_js_1.TAG_ID.BIG: case html_js_1.TAG_ID.CODE: case html_js_1.TAG_ID.FONT: case html_js_1.TAG_ID.SMALL: case html_js_1.TAG_ID.STRIKE: case html_js_1.TAG_ID.STRONG: { bStartTagInBody(p, token); break; } case html_js_1.TAG_ID.A: { aStartTagInBody(p, token); break; } case html_js_1.TAG_ID.H1: case html_js_1.TAG_ID.H2: case html_js_1.TAG_ID.H3: case html_js_1.TAG_ID.H4: case html_js_1.TAG_ID.H5: case html_js_1.TAG_ID.H6: { numberedHeaderStartTagInBody(p, token); break; } case html_js_1.TAG_ID.P: case html_js_1.TAG_ID.DL: case html_js_1.TAG_ID.OL: case html_js_1.TAG_ID.UL: case html_js_1.TAG_ID.DIV: case html_js_1.TAG_ID.DIR: case html_js_1.TAG_ID.NAV: case html_js_1.TAG_ID.MAIN: case html_js_1.TAG_ID.MENU: case html_js_1.TAG_ID.ASIDE: case html_js_1.TAG_ID.CENTER: case html_js_1.TAG_ID.FIGURE: case html_js_1.TAG_ID.FOOTER: case html_js_1.TAG_ID.HEADER: case html_js_1.TAG_ID.HGROUP: case html_js_1.TAG_ID.DIALOG: case html_js_1.TAG_ID.DETAILS: case html_js_1.TAG_ID.ADDRESS: case html_js_1.TAG_ID.ARTICLE: case html_js_1.TAG_ID.SECTION: case html_js_1.TAG_ID.SUMMARY: case html_js_1.TAG_ID.FIELDSET: case html_js_1.TAG_ID.BLOCKQUOTE: case html_js_1.TAG_ID.FIGCAPTION: { addressStartTagInBody(p, token); break; } case html_js_1.TAG_ID.LI: case html_js_1.TAG_ID.DD: case html_js_1.TAG_ID.DT: { listItemStartTagInBody(p, token); break; } case html_js_1.TAG_ID.BR: case html_js_1.TAG_ID.IMG: case html_js_1.TAG_ID.WBR: case html_js_1.TAG_ID.AREA: case html_js_1.TAG_ID.EMBED: case html_js_1.TAG_ID.KEYGEN: { areaStartTagInBody(p, token); break; } case html_js_1.TAG_ID.HR: { hrStartTagInBody(p, token); break; } case html_js_1.TAG_ID.RB: case html_js_1.TAG_ID.RTC: { rbStartTagInBody(p, token); break; } case html_js_1.TAG_ID.RT: case html_js_1.TAG_ID.RP: { rtStartTagInBody(p, token); break; } case html_js_1.TAG_ID.PRE: case html_js_1.TAG_ID.LISTING: { preStartTagInBody(p, token); break; } case html_js_1.TAG_ID.XMP: { xmpStartTagInBody(p, token); break; } case html_js_1.TAG_ID.SVG: { svgStartTagInBody(p, token); break; } case html_js_1.TAG_ID.HTML: { htmlStartTagInBody(p, token); break; } case html_js_1.TAG_ID.BASE: case html_js_1.TAG_ID.LINK: case html_js_1.TAG_ID.META: case html_js_1.TAG_ID.STYLE: case html_js_1.TAG_ID.TITLE: case html_js_1.TAG_ID.SCRIPT: case html_js_1.TAG_ID.BGSOUND: case html_js_1.TAG_ID.BASEFONT: case html_js_1.TAG_ID.TEMPLATE: { startTagInHead(p, token); break; } case html_js_1.TAG_ID.BODY: { bodyStartTagInBody(p, token); break; } case html_js_1.TAG_ID.FORM: { formStartTagInBody(p, token); break; } case html_js_1.TAG_ID.NOBR: { nobrStartTagInBody(p, token); break; } case html_js_1.TAG_ID.MATH: { mathStartTagInBody(p, token); break; } case html_js_1.TAG_ID.TABLE: { tableStartTagInBody(p, token); break; } case html_js_1.TAG_ID.INPUT: { inputStartTagInBody(p, token); break; } case html_js_1.TAG_ID.PARAM: case html_js_1.TAG_ID.TRACK: case html_js_1.TAG_ID.SOURCE: { paramStartTagInBody(p, token); break; } case html_js_1.TAG_ID.IMAGE: { imageStartTagInBody(p, token); break; } case html_js_1.TAG_ID.BUTTON: { buttonStartTagInBody(p, token); break; } case html_js_1.TAG_ID.APPLET: case html_js_1.TAG_ID.OBJECT: case html_js_1.TAG_ID.MARQUEE: { appletStartTagInBody(p, token); break; } case html_js_1.TAG_ID.IFRAME: { iframeStartTagInBody(p, token); break; } case html_js_1.TAG_ID.SELECT: { selectStartTagInBody(p, token); break; } case html_js_1.TAG_ID.OPTION: case html_js_1.TAG_ID.OPTGROUP: { optgroupStartTagInBody(p, token); break; } case html_js_1.TAG_ID.NOEMBED: { noembedStartTagInBody(p, token); break; } case html_js_1.TAG_ID.FRAMESET: { framesetStartTagInBody(p, token); break; } case html_js_1.TAG_ID.TEXTAREA: { textareaStartTagInBody(p, token); break; } case html_js_1.TAG_ID.NOSCRIPT: { if (p.options.scriptingEnabled) { noembedStartTagInBody(p, token); } else { genericStartTagInBody(p, token); } break; } case html_js_1.TAG_ID.PLAINTEXT: { plaintextStartTagInBody(p, token); break; } case html_js_1.TAG_ID.COL: case html_js_1.TAG_ID.TH: case html_js_1.TAG_ID.TD: case html_js_1.TAG_ID.TR: case html_js_1.TAG_ID.HEAD: case html_js_1.TAG_ID.FRAME: case html_js_1.TAG_ID.TBODY: case html_js_1.TAG_ID.TFOOT: case html_js_1.TAG_ID.THEAD: case html_js_1.TAG_ID.CAPTION: case html_js_1.TAG_ID.COLGROUP: { // Ignore token break; } default: { genericStartTagInBody(p, token); } } } function bodyEndTagInBody(p, token) { if (p.openElements.hasInScope(html_js_1.TAG_ID.BODY)) { p.insertionMode = InsertionMode.AFTER_BODY; //NOTE: <body> is never popped from the stack, so we need to updated //the end location explicitly. if (p.options.sourceCodeLocationInfo) { const bodyElement = p.openElements.tryPeekProperlyNestedBodyElement(); if (bodyElement) { p._setEndLocation(bodyElement, token); } } } } function htmlEndTagInBody(p, token) { if (p.openElements.hasInScope(html_js_1.TAG_ID.BODY)) { p.insertionMode = InsertionMode.AFTER_BODY; endTagAfterBody(p, token); } } function addressEndTagInBody(p, token) { const tn = token.tagID; if (p.openElements.hasInScope(tn)) { p.openElements.generateImpliedEndTags(); p.openElements.popUntilTagNamePopped(tn); } } function formEndTagInBody(p) { const inTemplate = p.openElements.tmplCount > 0; const { formElement } = p; if (!inTemplate) { p.formElement = null; } if ((formElement || inTemplate) && p.openElements.hasInScope(html_js_1.TAG_ID.FORM)) { p.openElements.generateImpliedEndTags(); if (inTemplate) { p.openElements.popUntilTagNamePopped(html_js_1.TAG_ID.FORM); } else if (formElement) { p.openElements.remove(formElement); } } } function pEndTagInBody(p) { if (!p.openElements.hasInButtonScope(html_js_1.TAG_ID.P)) { p._insertFakeElement(html_js_1.TAG_NAMES.P, html_js_1.TAG_ID.P); } p._closePElement(); } function liEndTagInBody(p) { if (p.openElements.hasInListItemScope(html_js_1.TAG_ID.LI)) { p.openElements.generateImpliedEndTagsWithExclusion(html_js_1.TAG_ID.LI); p.openElements.popUntilTagNamePopped(html_js_1.TAG_ID.LI); } } function ddEndTagInBody(p, token) { const tn = token.tagID; if (p.openElements.hasInScope(tn)) { p.openElements.generateImpliedEndTagsWithExclusion(tn); p.openElements.popUntilTagNamePopped(tn); } } function numberedHeaderEndTagInBody(p) { if (p.openElements.hasNumberedHeaderInScope()) { p.openElements.generateImpliedEndTags(); p.openElements.popUntilNumberedHeaderPopped(); } } function appletEndTagInBody(p, token) { const tn = token.tagID; if (p.openElements.hasInScope(tn)) { p.openElements.generateImpliedEndTags(); p.openElements.popUntilTagNamePopped(tn); p.activeFormattingElements.clearToLastMarker(); } } function brEndTagInBody(p) { p._reconstructActiveFormattingElements(); p._insertFakeElement(html_js_1.TAG_NAMES.BR, html_js_1.TAG_ID.BR); p.openElements.pop(); p.framesetOk = false; } function genericEndTagInBody(p, token) { const tn = token.tagName; const tid = token.tagID; for (let i = p.openElements.stackTop; i > 0; i--) { const element = p.openElements.items[i]; const elementId = p.openElements.tagIDs[i]; // Compare the tag name here, as the tag might not be a known tag with an ID. if (tid === elementId && (tid !== html_js_1.TAG_ID.UNKNOWN || p.treeAdapter.getTagName(element) === tn)) { p.openElements.generateImpliedEndTagsWithExclusion(tid); if (p.openElements.stackTop >= i) p.openElements.shortenToLength(i); break; } if (p._isSpecialElement(element, elementId)) { break; } } } function endTagInBody(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.A: case html_js_1.TAG_ID.B: case html_js_1.TAG_ID.I: case html_js_1.TAG_ID.S: case html_js_1.TAG_ID.U: case html_js_1.TAG_ID.EM: case html_js_1.TAG_ID.TT: case html_js_1.TAG_ID.BIG: case html_js_1.TAG_ID.CODE: case html_js_1.TAG_ID.FONT: case html_js_1.TAG_ID.NOBR: case html_js_1.TAG_ID.SMALL: case html_js_1.TAG_ID.STRIKE: case html_js_1.TAG_ID.STRONG: { callAdoptionAgency(p, token); break; } case html_js_1.TAG_ID.P: { pEndTagInBody(p); break; } case html_js_1.TAG_ID.DL: case html_js_1.TAG_ID.UL: case html_js_1.TAG_ID.OL: case html_js_1.TAG_ID.DIR: case html_js_1.TAG_ID.DIV: case html_js_1.TAG_ID.NAV: case html_js_1.TAG_ID.PRE: case html_js_1.TAG_ID.MAIN: case html_js_1.TAG_ID.MENU: case html_js_1.TAG_ID.ASIDE: case html_js_1.TAG_ID.CENTER: case html_js_1.TAG_ID.FIGURE: case html_js_1.TAG_ID.FOOTER: case html_js_1.TAG_ID.HEADER: case html_js_1.TAG_ID.HGROUP: case html_js_1.TAG_ID.DIALOG: case html_js_1.TAG_ID.ADDRESS: case html_js_1.TAG_ID.ARTICLE: case html_js_1.TAG_ID.DETAILS: case html_js_1.TAG_ID.SECTION: case html_js_1.TAG_ID.SUMMARY: case html_js_1.TAG_ID.LISTING: case html_js_1.TAG_ID.FIELDSET: case html_js_1.TAG_ID.BLOCKQUOTE: case html_js_1.TAG_ID.FIGCAPTION: { addressEndTagInBody(p, token); break; } case html_js_1.TAG_ID.LI: { liEndTagInBody(p); break; } case html_js_1.TAG_ID.DD: case html_js_1.TAG_ID.DT: { ddEndTagInBody(p, token); break; } case html_js_1.TAG_ID.H1: case html_js_1.TAG_ID.H2: case html_js_1.TAG_ID.H3: case html_js_1.TAG_ID.H4: case html_js_1.TAG_ID.H5: case html_js_1.TAG_ID.H6: { numberedHeaderEndTagInBody(p); break; } case html_js_1.TAG_ID.BR: { brEndTagInBody(p); break; } case html_js_1.TAG_ID.BODY: { bodyEndTagInBody(p, token); break; } case html_js_1.TAG_ID.HTML: { htmlEndTagInBody(p, token); break; } case html_js_1.TAG_ID.FORM: { formEndTagInBody(p); break; } case html_js_1.TAG_ID.APPLET: case html_js_1.TAG_ID.OBJECT: case html_js_1.TAG_ID.MARQUEE: { appletEndTagInBody(p, token); break; } case html_js_1.TAG_ID.TEMPLATE: { endTagInHead(p, token); break; } default: { genericEndTagInBody(p, token); } } } function eofInBody(p, token) { if (p.tmplInsertionModeStack.length > 0) { eofInTemplate(p, token); } else { stopParsing(p, token); } } // The "text" insertion mode //------------------------------------------------------------------ function endTagInText(p, token) { var _a; if (token.tagID === html_js_1.TAG_ID.SCRIPT) { (_a = p.scriptHandler) === null || _a === void 0 ? void 0 : _a.call(p, p.openElements.current); } p.openElements.pop(); p.insertionMode = p.originalInsertionMode; } function eofInText(p, token) { p._err(token, error_codes_js_1.ERR.eofInElementThatCanContainOnlyText); p.openElements.pop(); p.insertionMode = p.originalInsertionMode; p.onEof(token); } // The "in table" insertion mode //------------------------------------------------------------------ function characterInTable(p, token) { if (TABLE_STRUCTURE_TAGS.has(p.openElements.currentTagId)) { p.pendingCharacterTokens.length = 0; p.hasNonWhitespacePendingCharacterToken = false; p.originalInsertionMode = p.insertionMode; p.insertionMode = InsertionMode.IN_TABLE_TEXT; switch (token.type) { case token_js_1.TokenType.CHARACTER: { characterInTableText(p, token); break; } case token_js_1.TokenType.WHITESPACE_CHARACTER: { whitespaceCharacterInTableText(p, token); break; } // Ignore null } } else { tokenInTable(p, token); } } function captionStartTagInTable(p, token) { p.openElements.clearBackToTableContext(); p.activeFormattingElements.insertMarker(); p._insertElement(token, html_js_1.NS.HTML); p.insertionMode = InsertionMode.IN_CAPTION; } function colgroupStartTagInTable(p, token) { p.openElements.clearBackToTableContext(); p._insertElement(token, html_js_1.NS.HTML); p.insertionMode = InsertionMode.IN_COLUMN_GROUP; } function colStartTagInTable(p, token) { p.openElements.clearBackToTableContext(); p._insertFakeElement(html_js_1.TAG_NAMES.COLGROUP, html_js_1.TAG_ID.COLGROUP); p.insertionMode = InsertionMode.IN_COLUMN_GROUP; startTagInColumnGroup(p, token); } function tbodyStartTagInTable(p, token) { p.openElements.clearBackToTableContext(); p._insertElement(token, html_js_1.NS.HTML); p.insertionMode = InsertionMode.IN_TABLE_BODY; } function tdStartTagInTable(p, token) { p.openElements.clearBackToTableContext(); p._insertFakeElement(html_js_1.TAG_NAMES.TBODY, html_js_1.TAG_ID.TBODY); p.insertionMode = InsertionMode.IN_TABLE_BODY; startTagInTableBody(p, token); } function tableStartTagInTable(p, token) { if (p.openElements.hasInTableScope(html_js_1.TAG_ID.TABLE)) { p.openElements.popUntilTagNamePopped(html_js_1.TAG_ID.TABLE); p._resetInsertionMode(); p._processStartTag(token); } } function inputStartTagInTable(p, token) { if (isHiddenInput(token)) { p._appendElement(token, html_js_1.NS.HTML); } else { tokenInTable(p, token); } token.ackSelfClosing = true; } function formStartTagInTable(p, token) { if (!p.formElement && p.openElements.tmplCount === 0) { p._insertElement(token, html_js_1.NS.HTML); p.formElement = p.openElements.current; p.openElements.pop(); } } function startTagInTable(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.TD: case html_js_1.TAG_ID.TH: case html_js_1.TAG_ID.TR: { tdStartTagInTable(p, token); break; } case html_js_1.TAG_ID.STYLE: case html_js_1.TAG_ID.SCRIPT: case html_js_1.TAG_ID.TEMPLATE: { startTagInHead(p, token); break; } case html_js_1.TAG_ID.COL: { colStartTagInTable(p, token); break; } case html_js_1.TAG_ID.FORM: { formStartTagInTable(p, token); break; } case html_js_1.TAG_ID.TABLE: { tableStartTagInTable(p, token); break; } case html_js_1.TAG_ID.TBODY: case html_js_1.TAG_ID.TFOOT: case html_js_1.TAG_ID.THEAD: { tbodyStartTagInTable(p, token); break; } case html_js_1.TAG_ID.INPUT: { inputStartTagInTable(p, token); break; } case html_js_1.TAG_ID.CAPTION: { captionStartTagInTable(p, token); break; } case html_js_1.TAG_ID.COLGROUP: { colgroupStartTagInTable(p, token); break; } default: { tokenInTable(p, token); } } } function endTagInTable(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.TABLE: { if (p.openElements.hasInTableScope(html_js_1.TAG_ID.TABLE)) { p.openElements.popUntilTagNamePopped(html_js_1.TAG_ID.TABLE); p._resetInsertionMode(); } break; } case html_js_1.TAG_ID.TEMPLATE: { endTagInHead(p, token); break; } case html_js_1.TAG_ID.BODY: case html_js_1.TAG_ID.CAPTION: case html_js_1.TAG_ID.COL: case html_js_1.TAG_ID.COLGROUP: case html_js_1.TAG_ID.HTML: case html_js_1.TAG_ID.TBODY: case html_js_1.TAG_ID.TD: case html_js_1.TAG_ID.TFOOT: case html_js_1.TAG_ID.TH: case html_js_1.TAG_ID.THEAD: case html_js_1.TAG_ID.TR: { // Ignore token break; } default: { tokenInTable(p, token); } } } function tokenInTable(p, token) { const savedFosterParentingState = p.fosterParentingEnabled; p.fosterParentingEnabled = true; // Process token in `In Body` mode modeInBody(p, token); p.fosterParentingEnabled = savedFosterParentingState; } // The "in table text" insertion mode //------------------------------------------------------------------ function whitespaceCharacterInTableText(p, token) { p.pendingCharacterTokens.push(token); } function characterInTableText(p, token) { p.pendingCharacterTokens.push(token); p.hasNonWhitespacePendingCharacterToken = true; } function tokenInTableText(p, token) { let i = 0; if (p.hasNonWhitespacePendingCharacterToken) { for (; i < p.pendingCharacterTokens.length; i++) { tokenInTable(p, p.pendingCharacterTokens[i]); } } else { for (; i < p.pendingCharacterTokens.length; i++) { p._insertCharacters(p.pendingCharacterTokens[i]); } } p.insertionMode = p.originalInsertionMode; p._processToken(token); } // The "in caption" insertion mode //------------------------------------------------------------------ const TABLE_VOID_ELEMENTS = new Set([html_js_1.TAG_ID.CAPTION, html_js_1.TAG_ID.COL, html_js_1.TAG_ID.COLGROUP, html_js_1.TAG_ID.TBODY, html_js_1.TAG_ID.TD, html_js_1.TAG_ID.TFOOT, html_js_1.TAG_ID.TH, html_js_1.TAG_ID.THEAD, html_js_1.TAG_ID.TR]); function startTagInCaption(p, token) { const tn = token.tagID; if (TABLE_VOID_ELEMENTS.has(tn)) { if (p.openElements.hasInTableScope(html_js_1.TAG_ID.CAPTION)) { p.openElements.generateImpliedEndTags(); p.openElements.popUntilTagNamePopped(html_js_1.TAG_ID.CAPTION); p.activeFormattingElements.clearToLastMarker(); p.insertionMode = InsertionMode.IN_TABLE; startTagInTable(p, token); } } else { startTagInBody(p, token); } } function endTagInCaption(p, token) { const tn = token.tagID; switch (tn) { case html_js_1.TAG_ID.CAPTION: case html_js_1.TAG_ID.TABLE: { if (p.openElements.hasInTableScope(html_js_1.TAG_ID.CAPTION)) { p.openElements.generateImpliedEndTags(); p.openElements.popUntilTagNamePopped(html_js_1.TAG_ID.CAPTION); p.activeFormattingElements.clearToLastMarker(); p.insertionMode = InsertionMode.IN_TABLE; if (tn === html_js_1.TAG_ID.TABLE) { endTagInTable(p, token); } } break; } case html_js_1.TAG_ID.BODY: case html_js_1.TAG_ID.COL: case html_js_1.TAG_ID.COLGROUP: case html_js_1.TAG_ID.HTML: case html_js_1.TAG_ID.TBODY: case html_js_1.TAG_ID.TD: case html_js_1.TAG_ID.TFOOT: case html_js_1.TAG_ID.TH: case html_js_1.TAG_ID.THEAD: case html_js_1.TAG_ID.TR: { // Ignore token break; } default: { endTagInBody(p, token); } } } // The "in column group" insertion mode //------------------------------------------------------------------ function startTagInColumnGroup(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.HTML: { startTagInBody(p, token); break; } case html_js_1.TAG_ID.COL: { p._appendElement(token, html_js_1.NS.HTML); token.ackSelfClosing = true; break; } case html_js_1.TAG_ID.TEMPLATE: { startTagInHead(p, token); break; } default: { tokenInColumnGroup(p, token); } } } function endTagInColumnGroup(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.COLGROUP: { if (p.openElements.currentTagId === html_js_1.TAG_ID.COLGROUP) { p.openElements.pop(); p.insertionMode = InsertionMode.IN_TABLE; } break; } case html_js_1.TAG_ID.TEMPLATE: { endTagInHead(p, token); break; } case html_js_1.TAG_ID.COL: { // Ignore token break; } default: { tokenInColumnGroup(p, token); } } } function tokenInColumnGroup(p, token) { if (p.openElements.currentTagId === html_js_1.TAG_ID.COLGROUP) { p.openElements.pop(); p.insertionMode = InsertionMode.IN_TABLE; p._processToken(token); } } // The "in table body" insertion mode //------------------------------------------------------------------ function startTagInTableBody(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.TR: { p.openElements.clearBackToTableBodyContext(); p._insertElement(token, html_js_1.NS.HTML); p.insertionMode = InsertionMode.IN_ROW; break; } case html_js_1.TAG_ID.TH: case html_js_1.TAG_ID.TD: { p.openElements.clearBackToTableBodyContext(); p._insertFakeElement(html_js_1.TAG_NAMES.TR, html_js_1.TAG_ID.TR); p.insertionMode = InsertionMode.IN_ROW; startTagInRow(p, token); break; } case html_js_1.TAG_ID.CAPTION: case html_js_1.TAG_ID.COL: case html_js_1.TAG_ID.COLGROUP: case html_js_1.TAG_ID.TBODY: case html_js_1.TAG_ID.TFOOT: case html_js_1.TAG_ID.THEAD: { if (p.openElements.hasTableBodyContextInTableScope()) { p.openElements.clearBackToTableBodyContext(); p.openElements.pop(); p.insertionMode = InsertionMode.IN_TABLE; startTagInTable(p, token); } break; } default: { startTagInTable(p, token); } } } function endTagInTableBody(p, token) { const tn = token.tagID; switch (token.tagID) { case html_js_1.TAG_ID.TBODY: case html_js_1.TAG_ID.TFOOT: case html_js_1.TAG_ID.THEAD: { if (p.openElements.hasInTableScope(tn)) { p.openElements.clearBackToTableBodyContext(); p.openElements.pop(); p.insertionMode = InsertionMode.IN_TABLE; } break; } case html_js_1.TAG_ID.TABLE: { if (p.openElements.hasTableBodyContextInTableScope()) { p.openElements.clearBackToTableBodyContext(); p.openElements.pop(); p.insertionMode = InsertionMode.IN_TABLE; endTagInTable(p, token); } break; } case html_js_1.TAG_ID.BODY: case html_js_1.TAG_ID.CAPTION: case html_js_1.TAG_ID.COL: case html_js_1.TAG_ID.COLGROUP: case html_js_1.TAG_ID.HTML: case html_js_1.TAG_ID.TD: case html_js_1.TAG_ID.TH: case html_js_1.TAG_ID.TR: { // Ignore token break; } default: { endTagInTable(p, token); } } } // The "in row" insertion mode //------------------------------------------------------------------ function startTagInRow(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.TH: case html_js_1.TAG_ID.TD: { p.openElements.clearBackToTableRowContext(); p._insertElement(token, html_js_1.NS.HTML); p.insertionMode = InsertionMode.IN_CELL; p.activeFormattingElements.insertMarker(); break; } case html_js_1.TAG_ID.CAPTION: case html_js_1.TAG_ID.COL: case html_js_1.TAG_ID.COLGROUP: case html_js_1.TAG_ID.TBODY: case html_js_1.TAG_ID.TFOOT: case html_js_1.TAG_ID.THEAD: case html_js_1.TAG_ID.TR: { if (p.openElements.hasInTableScope(html_js_1.TAG_ID.TR)) { p.openElements.clearBackToTableRowContext(); p.openElements.pop(); p.insertionMode = InsertionMode.IN_TABLE_BODY; startTagInTableBody(p, token); } break; } default: { startTagInTable(p, token); } } } function endTagInRow(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.TR: { if (p.openElements.hasInTableScope(html_js_1.TAG_ID.TR)) { p.openElements.clearBackToTableRowContext(); p.openElements.pop(); p.insertionMode = InsertionMode.IN_TABLE_BODY; } break; } case html_js_1.TAG_ID.TABLE: { if (p.openElements.hasInTableScope(html_js_1.TAG_ID.TR)) { p.openElements.clearBackToTableRowContext(); p.openElements.pop(); p.insertionMode = InsertionMode.IN_TABLE_BODY; endTagInTableBody(p, token); } break; } case html_js_1.TAG_ID.TBODY: case html_js_1.TAG_ID.TFOOT: case html_js_1.TAG_ID.THEAD: { if (p.openElements.hasInTableScope(token.tagID) || p.openElements.hasInTableScope(html_js_1.TAG_ID.TR)) { p.openElements.clearBackToTableRowContext(); p.openElements.pop(); p.insertionMode = InsertionMode.IN_TABLE_BODY; endTagInTableBody(p, token); } break; } case html_js_1.TAG_ID.BODY: case html_js_1.TAG_ID.CAPTION: case html_js_1.TAG_ID.COL: case html_js_1.TAG_ID.COLGROUP: case html_js_1.TAG_ID.HTML: case html_js_1.TAG_ID.TD: case html_js_1.TAG_ID.TH: { // Ignore end tag break; } default: endTagInTable(p, token); } } // The "in cell" insertion mode //------------------------------------------------------------------ function startTagInCell(p, token) { const tn = token.tagID; if (TABLE_VOID_ELEMENTS.has(tn)) { if (p.openElements.hasInTableScope(html_js_1.TAG_ID.TD) || p.openElements.hasInTableScope(html_js_1.TAG_ID.TH)) { p._closeTableCell(); startTagInRow(p, token); } } else { startTagInBody(p, token); } } function endTagInCell(p, token) { const tn = token.tagID; switch (tn) { case html_js_1.TAG_ID.TD: case html_js_1.TAG_ID.TH: { if (p.openElements.hasInTableScope(tn)) { p.openElements.generateImpliedEndTags(); p.openElements.popUntilTagNamePopped(tn); p.activeFormattingElements.clearToLastMarker(); p.insertionMode = InsertionMode.IN_ROW; } break; } case html_js_1.TAG_ID.TABLE: case html_js_1.TAG_ID.TBODY: case html_js_1.TAG_ID.TFOOT: case html_js_1.TAG_ID.THEAD: case html_js_1.TAG_ID.TR: { if (p.openElements.hasInTableScope(tn)) { p._closeTableCell(); endTagInRow(p, token); } break; } case html_js_1.TAG_ID.BODY: case html_js_1.TAG_ID.CAPTION: case html_js_1.TAG_ID.COL: case html_js_1.TAG_ID.COLGROUP: case html_js_1.TAG_ID.HTML: { // Ignore token break; } default: { endTagInBody(p, token); } } } // The "in select" insertion mode //------------------------------------------------------------------ function startTagInSelect(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.HTML: { startTagInBody(p, token); break; } case html_js_1.TAG_ID.OPTION: { if (p.openElements.currentTagId === html_js_1.TAG_ID.OPTION) { p.openElements.pop(); } p._insertElement(token, html_js_1.NS.HTML); break; } case html_js_1.TAG_ID.OPTGROUP: { if (p.openElements.currentTagId === html_js_1.TAG_ID.OPTION) { p.openElements.pop(); } if (p.openElements.currentTagId === html_js_1.TAG_ID.OPTGROUP) { p.openElements.pop(); } p._insertElement(token, html_js_1.NS.HTML); break; } case html_js_1.TAG_ID.INPUT: case html_js_1.TAG_ID.KEYGEN: case html_js_1.TAG_ID.TEXTAREA: case html_js_1.TAG_ID.SELECT: { if (p.openElements.hasInSelectScope(html_js_1.TAG_ID.SELECT)) { p.openElements.popUntilTagNamePopped(html_js_1.TAG_ID.SELECT); p._resetInsertionMode(); if (token.tagID !== html_js_1.TAG_ID.SELECT) { p._processStartTag(token); } } break; } case html_js_1.TAG_ID.SCRIPT: case html_js_1.TAG_ID.TEMPLATE: { startTagInHead(p, token); break; } default: // Do nothing } } function endTagInSelect(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.OPTGROUP: { if (p.openElements.stackTop > 0 && p.openElements.currentTagId === html_js_1.TAG_ID.OPTION && p.openElements.tagIDs[p.openElements.stackTop - 1] === html_js_1.TAG_ID.OPTGROUP) { p.openElements.pop(); } if (p.openElements.currentTagId === html_js_1.TAG_ID.OPTGROUP) { p.openElements.pop(); } break; } case html_js_1.TAG_ID.OPTION: { if (p.openElements.currentTagId === html_js_1.TAG_ID.OPTION) { p.openElements.pop(); } break; } case html_js_1.TAG_ID.SELECT: { if (p.openElements.hasInSelectScope(html_js_1.TAG_ID.SELECT)) { p.openElements.popUntilTagNamePopped(html_js_1.TAG_ID.SELECT); p._resetInsertionMode(); } break; } case html_js_1.TAG_ID.TEMPLATE: { endTagInHead(p, token); break; } default: // Do nothing } } // The "in select in table" insertion mode //------------------------------------------------------------------ function startTagInSelectInTable(p, token) { const tn = token.tagID; if (tn === html_js_1.TAG_ID.CAPTION || tn === html_js_1.TAG_ID.TABLE || tn === html_js_1.TAG_ID.TBODY || tn === html_js_1.TAG_ID.TFOOT || tn === html_js_1.TAG_ID.THEAD || tn === html_js_1.TAG_ID.TR || tn === html_js_1.TAG_ID.TD || tn === html_js_1.TAG_ID.TH) { p.openElements.popUntilTagNamePopped(html_js_1.TAG_ID.SELECT); p._resetInsertionMode(); p._processStartTag(token); } else { startTagInSelect(p, token); } } function endTagInSelectInTable(p, token) { const tn = token.tagID; if (tn === html_js_1.TAG_ID.CAPTION || tn === html_js_1.TAG_ID.TABLE || tn === html_js_1.TAG_ID.TBODY || tn === html_js_1.TAG_ID.TFOOT || tn === html_js_1.TAG_ID.THEAD || tn === html_js_1.TAG_ID.TR || tn === html_js_1.TAG_ID.TD || tn === html_js_1.TAG_ID.TH) { if (p.openElements.hasInTableScope(tn)) { p.openElements.popUntilTagNamePopped(html_js_1.TAG_ID.SELECT); p._resetInsertionMode(); p.onEndTag(token); } } else { endTagInSelect(p, token); } } // The "in template" insertion mode //------------------------------------------------------------------ function startTagInTemplate(p, token) { switch (token.tagID) { // First, handle tags that can start without a mode change case html_js_1.TAG_ID.BASE: case html_js_1.TAG_ID.BASEFONT: case html_js_1.TAG_ID.BGSOUND: case html_js_1.TAG_ID.LINK: case html_js_1.TAG_ID.META: case html_js_1.TAG_ID.NOFRAMES: case html_js_1.TAG_ID.SCRIPT: case html_js_1.TAG_ID.STYLE: case html_js_1.TAG_ID.TEMPLATE: case html_js_1.TAG_ID.TITLE: startTagInHead(p, token); break; // Re-process the token in the appropriate mode case html_js_1.TAG_ID.CAPTION: case html_js_1.TAG_ID.COLGROUP: case html_js_1.TAG_ID.TBODY: case html_js_1.TAG_ID.TFOOT: case html_js_1.TAG_ID.THEAD: p.tmplInsertionModeStack[0] = InsertionMode.IN_TABLE; p.insertionMode = InsertionMode.IN_TABLE; startTagInTable(p, token); break; case html_js_1.TAG_ID.COL: p.tmplInsertionModeStack[0] = InsertionMode.IN_COLUMN_GROUP; p.insertionMode = InsertionMode.IN_COLUMN_GROUP; startTagInColumnGroup(p, token); break; case html_js_1.TAG_ID.TR: p.tmplInsertionModeStack[0] = InsertionMode.IN_TABLE_BODY; p.insertionMode = InsertionMode.IN_TABLE_BODY; startTagInTableBody(p, token); break; case html_js_1.TAG_ID.TD: case html_js_1.TAG_ID.TH: p.tmplInsertionModeStack[0] = InsertionMode.IN_ROW; p.insertionMode = InsertionMode.IN_ROW; startTagInRow(p, token); break; default: p.tmplInsertionModeStack[0] = InsertionMode.IN_BODY; p.insertionMode = InsertionMode.IN_BODY; startTagInBody(p, token); } } function endTagInTemplate(p, token) { if (token.tagID === html_js_1.TAG_ID.TEMPLATE) { endTagInHead(p, token); } } function eofInTemplate(p, token) { if (p.openElements.tmplCount > 0) { p.openElements.popUntilTagNamePopped(html_js_1.TAG_ID.TEMPLATE); p.activeFormattingElements.clearToLastMarker(); p.tmplInsertionModeStack.shift(); p._resetInsertionMode(); p.onEof(token); } else { stopParsing(p, token); } } // The "after body" insertion mode //------------------------------------------------------------------ function startTagAfterBody(p, token) { if (token.tagID === html_js_1.TAG_ID.HTML) { startTagInBody(p, token); } else { tokenAfterBody(p, token); } } function endTagAfterBody(p, token) { var _a; if (token.tagID === html_js_1.TAG_ID.HTML) { if (!p.fragmentContext) { p.insertionMode = InsertionMode.AFTER_AFTER_BODY; } //NOTE: <html> is never popped from the stack, so we need to updated //the end location explicitly. if (p.options.sourceCodeLocationInfo && p.openElements.tagIDs[0] === html_js_1.TAG_ID.HTML) { p._setEndLocation(p.openElements.items[0], token); // Update the body element, if it doesn't have an end tag const bodyElement = p.openElements.items[1]; if (bodyElement && !((_a = p.treeAdapter.getNodeSourceCodeLocation(bodyElement)) === null || _a === void 0 ? void 0 : _a.endTag)) { p._setEndLocation(bodyElement, token); } } } else { tokenAfterBody(p, token); } } function tokenAfterBody(p, token) { p.insertionMode = InsertionMode.IN_BODY; modeInBody(p, token); } // The "in frameset" insertion mode //------------------------------------------------------------------ function startTagInFrameset(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.HTML: { startTagInBody(p, token); break; } case html_js_1.TAG_ID.FRAMESET: { p._insertElement(token, html_js_1.NS.HTML); break; } case html_js_1.TAG_ID.FRAME: { p._appendElement(token, html_js_1.NS.HTML); token.ackSelfClosing = true; break; } case html_js_1.TAG_ID.NOFRAMES: { startTagInHead(p, token); break; } default: // Do nothing } } function endTagInFrameset(p, token) { if (token.tagID === html_js_1.TAG_ID.FRAMESET && !p.openElements.isRootHtmlElementCurrent()) { p.openElements.pop(); if (!p.fragmentContext && p.openElements.currentTagId !== html_js_1.TAG_ID.FRAMESET) { p.insertionMode = InsertionMode.AFTER_FRAMESET; } } } // The "after frameset" insertion mode //------------------------------------------------------------------ function startTagAfterFrameset(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.HTML: { startTagInBody(p, token); break; } case html_js_1.TAG_ID.NOFRAMES: { startTagInHead(p, token); break; } default: // Do nothing } } function endTagAfterFrameset(p, token) { if (token.tagID === html_js_1.TAG_ID.HTML) { p.insertionMode = InsertionMode.AFTER_AFTER_FRAMESET; } } // The "after after body" insertion mode //------------------------------------------------------------------ function startTagAfterAfterBody(p, token) { if (token.tagID === html_js_1.TAG_ID.HTML) { startTagInBody(p, token); } else { tokenAfterAfterBody(p, token); } } function tokenAfterAfterBody(p, token) { p.insertionMode = InsertionMode.IN_BODY; modeInBody(p, token); } // The "after after frameset" insertion mode //------------------------------------------------------------------ function startTagAfterAfterFrameset(p, token) { switch (token.tagID) { case html_js_1.TAG_ID.HTML: { startTagInBody(p, token); break; } case html_js_1.TAG_ID.NOFRAMES: { startTagInHead(p, token); break; } default: // Do nothing } } // The rules for parsing tokens in foreign content //------------------------------------------------------------------ function nullCharacterInForeignContent(p, token) { token.chars = unicode.REPLACEMENT_CHARACTER; p._insertCharacters(token); } function characterInForeignContent(p, token) { p._insertCharacters(token); p.framesetOk = false; } function popUntilHtmlOrIntegrationPoint(p) { while (p.treeAdapter.getNamespaceURI(p.openElements.current) !== html_js_1.NS.HTML && !p._isIntegrationPoint(p.openElements.currentTagId, p.openElements.current)) { p.openElements.pop(); } } function startTagInForeignContent(p, token) { if (foreignContent.causesExit(token)) { popUntilHtmlOrIntegrationPoint(p); p._startTagOutsideForeignContent(token); } else { const current = p._getAdjustedCurrentElement(); const currentNs = p.treeAdapter.getNamespaceURI(current); if (currentNs === html_js_1.NS.MATHML) { foreignContent.adjustTokenMathMLAttrs(token); } else if (currentNs === html_js_1.NS.SVG) { foreignContent.adjustTokenSVGTagName(token); foreignContent.adjustTokenSVGAttrs(token); } foreignContent.adjustTokenXMLAttrs(token); if (token.selfClosing) { p._appendElement(token, currentNs); } else { p._insertElement(token, currentNs); } token.ackSelfClosing = true; } } function endTagInForeignContent(p, token) { if (token.tagID === html_js_1.TAG_ID.P || token.tagID === html_js_1.TAG_ID.BR) { popUntilHtmlOrIntegrationPoint(p); p._endTagOutsideForeignContent(token); return; } for (let i = p.openElements.stackTop; i > 0; i--) { const element = p.openElements.items[i]; if (p.treeAdapter.getNamespaceURI(element) === html_js_1.NS.HTML) { p._endTagOutsideForeignContent(token); break; } const tagName = p.treeAdapter.getTagName(element); if (tagName.toLowerCase() === token.tagName) { //NOTE: update the token tag name for `_setEndLocation`. token.tagName = tagName; p.openElements.shortenToLength(i); break; } } } //# sourceMappingURL=index.js.map