summaryrefslogtreecommitdiff
path: root/bin/wiki/ImportarDesdeURL/node_modules/parse5/lib/parser/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'bin/wiki/ImportarDesdeURL/node_modules/parse5/lib/parser/index.js')
-rw-r--r--bin/wiki/ImportarDesdeURL/node_modules/parse5/lib/parser/index.js2819
1 files changed, 2819 insertions, 0 deletions
diff --git a/bin/wiki/ImportarDesdeURL/node_modules/parse5/lib/parser/index.js b/bin/wiki/ImportarDesdeURL/node_modules/parse5/lib/parser/index.js
new file mode 100644
index 00000000..5fc067f1
--- /dev/null
+++ b/bin/wiki/ImportarDesdeURL/node_modules/parse5/lib/parser/index.js
@@ -0,0 +1,2819 @@
+'use strict';
+
+var Tokenizer = require('../tokenizer'),
+ OpenElementStack = require('./open_element_stack'),
+ FormattingElementList = require('./formatting_element_list'),
+ LocationInfoParserMixin = require('../extensions/location_info/parser_mixin'),
+ defaultTreeAdapter = require('../tree_adapters/default'),
+ mergeOptions = require('../utils/merge_options'),
+ doctype = require('../common/doctype'),
+ foreignContent = require('../common/foreign_content'),
+ UNICODE = require('../common/unicode'),
+ HTML = require('../common/html');
+
+//Aliases
+var $ = HTML.TAG_NAMES,
+ NS = HTML.NAMESPACES,
+ ATTRS = HTML.ATTRS;
+
+var DEFAULT_OPTIONS = {
+ locationInfo: false,
+ treeAdapter: defaultTreeAdapter
+};
+
+//Misc constants
+var HIDDEN_INPUT_TYPE = 'hidden';
+
+//Adoption agency loops iteration count
+var AA_OUTER_LOOP_ITER = 8,
+ AA_INNER_LOOP_ITER = 3;
+
+//Insertion modes
+var INITIAL_MODE = 'INITIAL_MODE',
+ BEFORE_HTML_MODE = 'BEFORE_HTML_MODE',
+ BEFORE_HEAD_MODE = 'BEFORE_HEAD_MODE',
+ IN_HEAD_MODE = 'IN_HEAD_MODE',
+ AFTER_HEAD_MODE = 'AFTER_HEAD_MODE',
+ IN_BODY_MODE = 'IN_BODY_MODE',
+ TEXT_MODE = 'TEXT_MODE',
+ IN_TABLE_MODE = 'IN_TABLE_MODE',
+ IN_TABLE_TEXT_MODE = 'IN_TABLE_TEXT_MODE',
+ IN_CAPTION_MODE = 'IN_CAPTION_MODE',
+ IN_COLUMN_GROUP_MODE = 'IN_COLUMN_GROUP_MODE',
+ IN_TABLE_BODY_MODE = 'IN_TABLE_BODY_MODE',
+ IN_ROW_MODE = 'IN_ROW_MODE',
+ IN_CELL_MODE = 'IN_CELL_MODE',
+ IN_SELECT_MODE = 'IN_SELECT_MODE',
+ IN_SELECT_IN_TABLE_MODE = 'IN_SELECT_IN_TABLE_MODE',
+ IN_TEMPLATE_MODE = 'IN_TEMPLATE_MODE',
+ AFTER_BODY_MODE = 'AFTER_BODY_MODE',
+ IN_FRAMESET_MODE = 'IN_FRAMESET_MODE',
+ AFTER_FRAMESET_MODE = 'AFTER_FRAMESET_MODE',
+ AFTER_AFTER_BODY_MODE = 'AFTER_AFTER_BODY_MODE',
+ AFTER_AFTER_FRAMESET_MODE = 'AFTER_AFTER_FRAMESET_MODE';
+
+//Insertion mode reset map
+var INSERTION_MODE_RESET_MAP = Object.create(null);
+
+INSERTION_MODE_RESET_MAP[$.TR] = IN_ROW_MODE;
+INSERTION_MODE_RESET_MAP[$.TBODY] =
+INSERTION_MODE_RESET_MAP[$.THEAD] =
+INSERTION_MODE_RESET_MAP[$.TFOOT] = IN_TABLE_BODY_MODE;
+INSERTION_MODE_RESET_MAP[$.CAPTION] = IN_CAPTION_MODE;
+INSERTION_MODE_RESET_MAP[$.COLGROUP] = IN_COLUMN_GROUP_MODE;
+INSERTION_MODE_RESET_MAP[$.TABLE] = IN_TABLE_MODE;
+INSERTION_MODE_RESET_MAP[$.BODY] = IN_BODY_MODE;
+INSERTION_MODE_RESET_MAP[$.FRAMESET] = IN_FRAMESET_MODE;
+
+//Template insertion mode switch map
+var TEMPLATE_INSERTION_MODE_SWITCH_MAP = Object.create(null);
+
+TEMPLATE_INSERTION_MODE_SWITCH_MAP[$.CAPTION] =
+TEMPLATE_INSERTION_MODE_SWITCH_MAP[$.COLGROUP] =
+TEMPLATE_INSERTION_MODE_SWITCH_MAP[$.TBODY] =
+TEMPLATE_INSERTION_MODE_SWITCH_MAP[$.TFOOT] =
+TEMPLATE_INSERTION_MODE_SWITCH_MAP[$.THEAD] = IN_TABLE_MODE;
+TEMPLATE_INSERTION_MODE_SWITCH_MAP[$.COL] = IN_COLUMN_GROUP_MODE;
+TEMPLATE_INSERTION_MODE_SWITCH_MAP[$.TR] = IN_TABLE_BODY_MODE;
+TEMPLATE_INSERTION_MODE_SWITCH_MAP[$.TD] =
+TEMPLATE_INSERTION_MODE_SWITCH_MAP[$.TH] = IN_ROW_MODE;
+
+//Token handlers map for insertion modes
+var _ = Object.create(null);
+
+_[INITIAL_MODE] = Object.create(null);
+_[INITIAL_MODE][Tokenizer.CHARACTER_TOKEN] =
+_[INITIAL_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = tokenInInitialMode;
+_[INITIAL_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = ignoreToken;
+_[INITIAL_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[INITIAL_MODE][Tokenizer.DOCTYPE_TOKEN] = doctypeInInitialMode;
+_[INITIAL_MODE][Tokenizer.START_TAG_TOKEN] =
+_[INITIAL_MODE][Tokenizer.END_TAG_TOKEN] =
+_[INITIAL_MODE][Tokenizer.EOF_TOKEN] = tokenInInitialMode;
+
+_[BEFORE_HTML_MODE] = Object.create(null);
+_[BEFORE_HTML_MODE][Tokenizer.CHARACTER_TOKEN] =
+_[BEFORE_HTML_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = tokenBeforeHtml;
+_[BEFORE_HTML_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = ignoreToken;
+_[BEFORE_HTML_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[BEFORE_HTML_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[BEFORE_HTML_MODE][Tokenizer.START_TAG_TOKEN] = startTagBeforeHtml;
+_[BEFORE_HTML_MODE][Tokenizer.END_TAG_TOKEN] = endTagBeforeHtml;
+_[BEFORE_HTML_MODE][Tokenizer.EOF_TOKEN] = tokenBeforeHtml;
+
+_[BEFORE_HEAD_MODE] = Object.create(null);
+_[BEFORE_HEAD_MODE][Tokenizer.CHARACTER_TOKEN] =
+_[BEFORE_HEAD_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = tokenBeforeHead;
+_[BEFORE_HEAD_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = ignoreToken;
+_[BEFORE_HEAD_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[BEFORE_HEAD_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[BEFORE_HEAD_MODE][Tokenizer.START_TAG_TOKEN] = startTagBeforeHead;
+_[BEFORE_HEAD_MODE][Tokenizer.END_TAG_TOKEN] = endTagBeforeHead;
+_[BEFORE_HEAD_MODE][Tokenizer.EOF_TOKEN] = tokenBeforeHead;
+
+_[IN_HEAD_MODE] = Object.create(null);
+_[IN_HEAD_MODE][Tokenizer.CHARACTER_TOKEN] =
+_[IN_HEAD_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = tokenInHead;
+_[IN_HEAD_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = insertCharacters;
+_[IN_HEAD_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[IN_HEAD_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[IN_HEAD_MODE][Tokenizer.START_TAG_TOKEN] = startTagInHead;
+_[IN_HEAD_MODE][Tokenizer.END_TAG_TOKEN] = endTagInHead;
+_[IN_HEAD_MODE][Tokenizer.EOF_TOKEN] = tokenInHead;
+
+_[AFTER_HEAD_MODE] = Object.create(null);
+_[AFTER_HEAD_MODE][Tokenizer.CHARACTER_TOKEN] =
+_[AFTER_HEAD_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = tokenAfterHead;
+_[AFTER_HEAD_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = insertCharacters;
+_[AFTER_HEAD_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[AFTER_HEAD_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[AFTER_HEAD_MODE][Tokenizer.START_TAG_TOKEN] = startTagAfterHead;
+_[AFTER_HEAD_MODE][Tokenizer.END_TAG_TOKEN] = endTagAfterHead;
+_[AFTER_HEAD_MODE][Tokenizer.EOF_TOKEN] = tokenAfterHead;
+
+_[IN_BODY_MODE] = Object.create(null);
+_[IN_BODY_MODE][Tokenizer.CHARACTER_TOKEN] = characterInBody;
+_[IN_BODY_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = ignoreToken;
+_[IN_BODY_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = whitespaceCharacterInBody;
+_[IN_BODY_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[IN_BODY_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[IN_BODY_MODE][Tokenizer.START_TAG_TOKEN] = startTagInBody;
+_[IN_BODY_MODE][Tokenizer.END_TAG_TOKEN] = endTagInBody;
+_[IN_BODY_MODE][Tokenizer.EOF_TOKEN] = eofInBody;
+
+_[TEXT_MODE] = Object.create(null);
+_[TEXT_MODE][Tokenizer.CHARACTER_TOKEN] =
+_[TEXT_MODE][Tokenizer.NULL_CHARACTER_TOKEN] =
+_[TEXT_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = insertCharacters;
+_[TEXT_MODE][Tokenizer.COMMENT_TOKEN] =
+_[TEXT_MODE][Tokenizer.DOCTYPE_TOKEN] =
+_[TEXT_MODE][Tokenizer.START_TAG_TOKEN] = ignoreToken;
+_[TEXT_MODE][Tokenizer.END_TAG_TOKEN] = endTagInText;
+_[TEXT_MODE][Tokenizer.EOF_TOKEN] = eofInText;
+
+_[IN_TABLE_MODE] = Object.create(null);
+_[IN_TABLE_MODE][Tokenizer.CHARACTER_TOKEN] =
+_[IN_TABLE_MODE][Tokenizer.NULL_CHARACTER_TOKEN] =
+_[IN_TABLE_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = characterInTable;
+_[IN_TABLE_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[IN_TABLE_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[IN_TABLE_MODE][Tokenizer.START_TAG_TOKEN] = startTagInTable;
+_[IN_TABLE_MODE][Tokenizer.END_TAG_TOKEN] = endTagInTable;
+_[IN_TABLE_MODE][Tokenizer.EOF_TOKEN] = eofInBody;
+
+_[IN_TABLE_TEXT_MODE] = Object.create(null);
+_[IN_TABLE_TEXT_MODE][Tokenizer.CHARACTER_TOKEN] = characterInTableText;
+_[IN_TABLE_TEXT_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = ignoreToken;
+_[IN_TABLE_TEXT_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = whitespaceCharacterInTableText;
+_[IN_TABLE_TEXT_MODE][Tokenizer.COMMENT_TOKEN] =
+_[IN_TABLE_TEXT_MODE][Tokenizer.DOCTYPE_TOKEN] =
+_[IN_TABLE_TEXT_MODE][Tokenizer.START_TAG_TOKEN] =
+_[IN_TABLE_TEXT_MODE][Tokenizer.END_TAG_TOKEN] =
+_[IN_TABLE_TEXT_MODE][Tokenizer.EOF_TOKEN] = tokenInTableText;
+
+_[IN_CAPTION_MODE] = Object.create(null);
+_[IN_CAPTION_MODE][Tokenizer.CHARACTER_TOKEN] = characterInBody;
+_[IN_CAPTION_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = ignoreToken;
+_[IN_CAPTION_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = whitespaceCharacterInBody;
+_[IN_CAPTION_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[IN_CAPTION_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[IN_CAPTION_MODE][Tokenizer.START_TAG_TOKEN] = startTagInCaption;
+_[IN_CAPTION_MODE][Tokenizer.END_TAG_TOKEN] = endTagInCaption;
+_[IN_CAPTION_MODE][Tokenizer.EOF_TOKEN] = eofInBody;
+
+_[IN_COLUMN_GROUP_MODE] = Object.create(null);
+_[IN_COLUMN_GROUP_MODE][Tokenizer.CHARACTER_TOKEN] =
+_[IN_COLUMN_GROUP_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = tokenInColumnGroup;
+_[IN_COLUMN_GROUP_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = insertCharacters;
+_[IN_COLUMN_GROUP_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[IN_COLUMN_GROUP_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[IN_COLUMN_GROUP_MODE][Tokenizer.START_TAG_TOKEN] = startTagInColumnGroup;
+_[IN_COLUMN_GROUP_MODE][Tokenizer.END_TAG_TOKEN] = endTagInColumnGroup;
+_[IN_COLUMN_GROUP_MODE][Tokenizer.EOF_TOKEN] = eofInBody;
+
+_[IN_TABLE_BODY_MODE] = Object.create(null);
+_[IN_TABLE_BODY_MODE][Tokenizer.CHARACTER_TOKEN] =
+_[IN_TABLE_BODY_MODE][Tokenizer.NULL_CHARACTER_TOKEN] =
+_[IN_TABLE_BODY_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = characterInTable;
+_[IN_TABLE_BODY_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[IN_TABLE_BODY_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[IN_TABLE_BODY_MODE][Tokenizer.START_TAG_TOKEN] = startTagInTableBody;
+_[IN_TABLE_BODY_MODE][Tokenizer.END_TAG_TOKEN] = endTagInTableBody;
+_[IN_TABLE_BODY_MODE][Tokenizer.EOF_TOKEN] = eofInBody;
+
+_[IN_ROW_MODE] = Object.create(null);
+_[IN_ROW_MODE][Tokenizer.CHARACTER_TOKEN] =
+_[IN_ROW_MODE][Tokenizer.NULL_CHARACTER_TOKEN] =
+_[IN_ROW_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = characterInTable;
+_[IN_ROW_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[IN_ROW_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[IN_ROW_MODE][Tokenizer.START_TAG_TOKEN] = startTagInRow;
+_[IN_ROW_MODE][Tokenizer.END_TAG_TOKEN] = endTagInRow;
+_[IN_ROW_MODE][Tokenizer.EOF_TOKEN] = eofInBody;
+
+_[IN_CELL_MODE] = Object.create(null);
+_[IN_CELL_MODE][Tokenizer.CHARACTER_TOKEN] = characterInBody;
+_[IN_CELL_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = ignoreToken;
+_[IN_CELL_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = whitespaceCharacterInBody;
+_[IN_CELL_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[IN_CELL_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[IN_CELL_MODE][Tokenizer.START_TAG_TOKEN] = startTagInCell;
+_[IN_CELL_MODE][Tokenizer.END_TAG_TOKEN] = endTagInCell;
+_[IN_CELL_MODE][Tokenizer.EOF_TOKEN] = eofInBody;
+
+_[IN_SELECT_MODE] = Object.create(null);
+_[IN_SELECT_MODE][Tokenizer.CHARACTER_TOKEN] = insertCharacters;
+_[IN_SELECT_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = ignoreToken;
+_[IN_SELECT_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = insertCharacters;
+_[IN_SELECT_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[IN_SELECT_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[IN_SELECT_MODE][Tokenizer.START_TAG_TOKEN] = startTagInSelect;
+_[IN_SELECT_MODE][Tokenizer.END_TAG_TOKEN] = endTagInSelect;
+_[IN_SELECT_MODE][Tokenizer.EOF_TOKEN] = eofInBody;
+
+_[IN_SELECT_IN_TABLE_MODE] = Object.create(null);
+_[IN_SELECT_IN_TABLE_MODE][Tokenizer.CHARACTER_TOKEN] = insertCharacters;
+_[IN_SELECT_IN_TABLE_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = ignoreToken;
+_[IN_SELECT_IN_TABLE_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = insertCharacters;
+_[IN_SELECT_IN_TABLE_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[IN_SELECT_IN_TABLE_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[IN_SELECT_IN_TABLE_MODE][Tokenizer.START_TAG_TOKEN] = startTagInSelectInTable;
+_[IN_SELECT_IN_TABLE_MODE][Tokenizer.END_TAG_TOKEN] = endTagInSelectInTable;
+_[IN_SELECT_IN_TABLE_MODE][Tokenizer.EOF_TOKEN] = eofInBody;
+
+_[IN_TEMPLATE_MODE] = Object.create(null);
+_[IN_TEMPLATE_MODE][Tokenizer.CHARACTER_TOKEN] = characterInBody;
+_[IN_TEMPLATE_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = ignoreToken;
+_[IN_TEMPLATE_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = whitespaceCharacterInBody;
+_[IN_TEMPLATE_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[IN_TEMPLATE_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[IN_TEMPLATE_MODE][Tokenizer.START_TAG_TOKEN] = startTagInTemplate;
+_[IN_TEMPLATE_MODE][Tokenizer.END_TAG_TOKEN] = endTagInTemplate;
+_[IN_TEMPLATE_MODE][Tokenizer.EOF_TOKEN] = eofInTemplate;
+
+_[AFTER_BODY_MODE] = Object.create(null);
+_[AFTER_BODY_MODE][Tokenizer.CHARACTER_TOKEN] =
+_[AFTER_BODY_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = tokenAfterBody;
+_[AFTER_BODY_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = whitespaceCharacterInBody;
+_[AFTER_BODY_MODE][Tokenizer.COMMENT_TOKEN] = appendCommentToRootHtmlElement;
+_[AFTER_BODY_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[AFTER_BODY_MODE][Tokenizer.START_TAG_TOKEN] = startTagAfterBody;
+_[AFTER_BODY_MODE][Tokenizer.END_TAG_TOKEN] = endTagAfterBody;
+_[AFTER_BODY_MODE][Tokenizer.EOF_TOKEN] = stopParsing;
+
+_[IN_FRAMESET_MODE] = Object.create(null);
+_[IN_FRAMESET_MODE][Tokenizer.CHARACTER_TOKEN] =
+_[IN_FRAMESET_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = ignoreToken;
+_[IN_FRAMESET_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = insertCharacters;
+_[IN_FRAMESET_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[IN_FRAMESET_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[IN_FRAMESET_MODE][Tokenizer.START_TAG_TOKEN] = startTagInFrameset;
+_[IN_FRAMESET_MODE][Tokenizer.END_TAG_TOKEN] = endTagInFrameset;
+_[IN_FRAMESET_MODE][Tokenizer.EOF_TOKEN] = stopParsing;
+
+_[AFTER_FRAMESET_MODE] = Object.create(null);
+_[AFTER_FRAMESET_MODE][Tokenizer.CHARACTER_TOKEN] =
+_[AFTER_FRAMESET_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = ignoreToken;
+_[AFTER_FRAMESET_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = insertCharacters;
+_[AFTER_FRAMESET_MODE][Tokenizer.COMMENT_TOKEN] = appendComment;
+_[AFTER_FRAMESET_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[AFTER_FRAMESET_MODE][Tokenizer.START_TAG_TOKEN] = startTagAfterFrameset;
+_[AFTER_FRAMESET_MODE][Tokenizer.END_TAG_TOKEN] = endTagAfterFrameset;
+_[AFTER_FRAMESET_MODE][Tokenizer.EOF_TOKEN] = stopParsing;
+
+_[AFTER_AFTER_BODY_MODE] = Object.create(null);
+_[AFTER_AFTER_BODY_MODE][Tokenizer.CHARACTER_TOKEN] = tokenAfterAfterBody;
+_[AFTER_AFTER_BODY_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = tokenAfterAfterBody;
+_[AFTER_AFTER_BODY_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = whitespaceCharacterInBody;
+_[AFTER_AFTER_BODY_MODE][Tokenizer.COMMENT_TOKEN] = appendCommentToDocument;
+_[AFTER_AFTER_BODY_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[AFTER_AFTER_BODY_MODE][Tokenizer.START_TAG_TOKEN] = startTagAfterAfterBody;
+_[AFTER_AFTER_BODY_MODE][Tokenizer.END_TAG_TOKEN] = tokenAfterAfterBody;
+_[AFTER_AFTER_BODY_MODE][Tokenizer.EOF_TOKEN] = stopParsing;
+
+_[AFTER_AFTER_FRAMESET_MODE] = Object.create(null);
+_[AFTER_AFTER_FRAMESET_MODE][Tokenizer.CHARACTER_TOKEN] =
+_[AFTER_AFTER_FRAMESET_MODE][Tokenizer.NULL_CHARACTER_TOKEN] = ignoreToken;
+_[AFTER_AFTER_FRAMESET_MODE][Tokenizer.WHITESPACE_CHARACTER_TOKEN] = whitespaceCharacterInBody;
+_[AFTER_AFTER_FRAMESET_MODE][Tokenizer.COMMENT_TOKEN] = appendCommentToDocument;
+_[AFTER_AFTER_FRAMESET_MODE][Tokenizer.DOCTYPE_TOKEN] = ignoreToken;
+_[AFTER_AFTER_FRAMESET_MODE][Tokenizer.START_TAG_TOKEN] = startTagAfterAfterFrameset;
+_[AFTER_AFTER_FRAMESET_MODE][Tokenizer.END_TAG_TOKEN] = ignoreToken;
+_[AFTER_AFTER_FRAMESET_MODE][Tokenizer.EOF_TOKEN] = stopParsing;
+
+
+//Parser
+var Parser = module.exports = function (options) {
+ this.options = mergeOptions(DEFAULT_OPTIONS, options);
+
+ this.treeAdapter = this.options.treeAdapter;
+ this.pendingScript = null;
+
+ if (this.options.locationInfo)
+ new LocationInfoParserMixin(this);
+};
+
+// API
+Parser.prototype.parse = function (html) {
+ var document = this.treeAdapter.createDocument();
+
+ this._bootstrap(document, null);
+ this.tokenizer.write(html, true);
+ this._runParsingLoop(null);
+
+ return document;
+};
+
+Parser.prototype.parseFragment = function (html, fragmentContext) {
+ //NOTE: use <template> element as a fragment context if context element was not provided,
+ //so we will parse in "forgiving" manner
+ if (!fragmentContext)
+ fragmentContext = this.treeAdapter.createElement($.TEMPLATE, NS.HTML, []);
+
+ //NOTE: create fake element which will be used as 'document' for fragment parsing.
+ //This is important for jsdom there 'document' can't be recreated, therefore
+ //fragment parsing causes messing of the main `document`.
+ var documentMock = this.treeAdapter.createElement('documentmock', NS.HTML, []);
+
+ this._bootstrap(documentMock, fragmentContext);
+
+ if (this.treeAdapter.getTagName(fragmentContext) === $.TEMPLATE)
+ this._pushTmplInsertionMode(IN_TEMPLATE_MODE);
+
+ this._initTokenizerForFragmentParsing();
+ this._insertFakeRootElement();
+ this._resetInsertionMode();
+ this._findFormInFragmentContext();
+ this.tokenizer.write(html, true);
+ this._runParsingLoop(null);
+
+ var rootElement = this.treeAdapter.getFirstChild(documentMock),
+ fragment = this.treeAdapter.createDocumentFragment();
+
+ this._adoptNodes(rootElement, fragment);
+
+ return fragment;
+};
+
+//Bootstrap parser
+Parser.prototype._bootstrap = function (document, fragmentContext) {
+ this.tokenizer = new Tokenizer(this.options);
+
+ this.stopped = false;
+
+ this.insertionMode = INITIAL_MODE;
+ this.originalInsertionMode = '';
+
+ this.document = document;
+ this.fragmentContext = fragmentContext;
+
+ this.headElement = null;
+ this.formElement = null;
+
+ this.openElements = new OpenElementStack(this.document, this.treeAdapter);
+ this.activeFormattingElements = new FormattingElementList(this.treeAdapter);
+
+ this.tmplInsertionModeStack = [];
+ this.tmplInsertionModeStackTop = -1;
+ this.currentTmplInsertionMode = null;
+
+ this.pendingCharacterTokens = [];
+ this.hasNonWhitespacePendingCharacterToken = false;
+
+ this.framesetOk = true;
+ this.skipNextNewLine = false;
+ this.fosterParentingEnabled = false;
+};
+
+//Parsing loop
+Parser.prototype._runParsingLoop = function (scriptHandler) {
+ while (!this.stopped) {
+ this._setupTokenizerCDATAMode();
+
+ var token = this.tokenizer.getNextToken();
+
+ if (token.type === Tokenizer.HIBERNATION_TOKEN)
+ break;
+
+ if (this.skipNextNewLine) {
+ this.skipNextNewLine = false;
+
+ if (token.type === Tokenizer.WHITESPACE_CHARACTER_TOKEN && token.chars[0] === '\n') {
+ if (token.chars.length === 1)
+ continue;
+
+ token.chars = token.chars.substr(1);
+ }
+ }
+
+ this._processInputToken(token);
+
+ if (scriptHandler && this.pendingScript)
+ break;
+ }
+};
+
+Parser.prototype.runParsingLoopForCurrentChunk = function (writeCallback, scriptHandler) {
+ this._runParsingLoop(scriptHandler);
+
+ if (scriptHandler && this.pendingScript) {
+ var script = this.pendingScript;
+
+ this.pendingScript = null;
+
+ scriptHandler(script);
+
+ return;
+ }
+
+ if (writeCallback)
+ writeCallback();
+};
+
+//Text parsing
+Parser.prototype._setupTokenizerCDATAMode = function () {
+ var current = this._getAdjustedCurrentElement();
+
+ this.tokenizer.allowCDATA = current && current !== this.document &&
+ this.treeAdapter.getNamespaceURI(current) !== NS.HTML && !this._isIntegrationPoint(current);
+};
+
+Parser.prototype._switchToTextParsing = function (currentToken, nextTokenizerState) {
+ this._insertElement(currentToken, NS.HTML);
+ this.tokenizer.state = nextTokenizerState;
+ this.originalInsertionMode = this.insertionMode;
+ this.insertionMode = TEXT_MODE;
+};
+
+Parser.prototype.switchToPlaintextParsing = function () {
+ this.insertionMode = TEXT_MODE;
+ this.originalInsertionMode = IN_BODY_MODE;
+ this.tokenizer.state = Tokenizer.MODE.PLAINTEXT;
+};
+
+//Fragment parsing
+Parser.prototype._getAdjustedCurrentElement = function () {
+ return this.openElements.stackTop === 0 && this.fragmentContext ?
+ this.fragmentContext :
+ this.openElements.current;
+};
+
+Parser.prototype._findFormInFragmentContext = function () {
+ var node = this.fragmentContext;
+
+ do {
+ if (this.treeAdapter.getTagName(node) === $.FORM) {
+ this.formElement = node;
+ break;
+ }
+
+ node = this.treeAdapter.getParentNode(node);
+ } while (node);
+};
+
+Parser.prototype._initTokenizerForFragmentParsing = function () {
+ if (this.treeAdapter.getNamespaceURI(this.fragmentContext) === NS.HTML) {
+ var tn = this.treeAdapter.getTagName(this.fragmentContext);
+
+ if (tn === $.TITLE || tn === $.TEXTAREA)
+ this.tokenizer.state = Tokenizer.MODE.RCDATA;
+
+ else if (tn === $.STYLE || tn === $.XMP || tn === $.IFRAME ||
+ tn === $.NOEMBED || tn === $.NOFRAMES || tn === $.NOSCRIPT)
+ this.tokenizer.state = Tokenizer.MODE.RAWTEXT;
+
+ else if (tn === $.SCRIPT)
+ this.tokenizer.state = Tokenizer.MODE.SCRIPT_DATA;
+
+ else if (tn === $.PLAINTEXT)
+ this.tokenizer.state = Tokenizer.MODE.PLAINTEXT;
+ }
+};
+
+//Tree mutation
+Parser.prototype._setDocumentType = function (token) {
+ this.treeAdapter.setDocumentType(this.document, token.name, token.publicId, token.systemId);
+};
+
+Parser.prototype._attachElementToTree = function (element) {
+ if (this._shouldFosterParentOnInsertion())
+ this._fosterParentElement(element);
+
+ else {
+ var parent = this.openElements.currentTmplContent || this.openElements.current;
+
+ this.treeAdapter.appendChild(parent, element);
+ }
+};
+
+Parser.prototype._appendElement = function (token, namespaceURI) {
+ var element = this.treeAdapter.createElement(token.tagName, namespaceURI, token.attrs);
+
+ this._attachElementToTree(element);
+};
+
+Parser.prototype._insertElement = function (token, namespaceURI) {
+ var element = this.treeAdapter.createElement(token.tagName, namespaceURI, token.attrs);
+
+ this._attachElementToTree(element);
+ this.openElements.push(element);
+};
+
+Parser.prototype._insertFakeElement = function (tagName) {
+ var element = this.treeAdapter.createElement(tagName, NS.HTML, []);
+
+ this._attachElementToTree(element);
+ this.openElements.push(element);
+};
+
+Parser.prototype._insertTemplate = function (token) {
+ var tmpl = this.treeAdapter.createElement(token.tagName, NS.HTML, token.attrs),
+ content = this.treeAdapter.createDocumentFragment();
+
+ this.treeAdapter.setTemplateContent(tmpl, content);
+ this._attachElementToTree(tmpl);
+ this.openElements.push(tmpl);
+};
+
+Parser.prototype._insertFakeRootElement = function () {
+ var element = this.treeAdapter.createElement($.HTML, NS.HTML, []);
+
+ this.treeAdapter.appendChild(this.openElements.current, element);
+ this.openElements.push(element);
+};
+
+Parser.prototype._appendCommentNode = function (token, parent) {
+ var commentNode = this.treeAdapter.createCommentNode(token.data);
+
+ this.treeAdapter.appendChild(parent, commentNode);
+};
+
+Parser.prototype._insertCharacters = function (token) {
+ if (this._shouldFosterParentOnInsertion())
+ this._fosterParentText(token.chars);
+
+ else {
+ var parent = this.openElements.currentTmplContent || this.openElements.current;
+
+ this.treeAdapter.insertText(parent, token.chars);
+ }
+};
+
+Parser.prototype._adoptNodes = function (donor, recipient) {
+ while (true) {
+ var child = this.treeAdapter.getFirstChild(donor);
+
+ if (!child)
+ break;
+
+ this.treeAdapter.detachNode(child);
+ this.treeAdapter.appendChild(recipient, child);
+ }
+};
+
+//Token processing
+Parser.prototype._shouldProcessTokenInForeignContent = function (token) {
+ var current = this._getAdjustedCurrentElement();
+
+ if (!current || current === this.document)
+ return false;
+
+ var ns = this.treeAdapter.getNamespaceURI(current);
+
+ if (ns === NS.HTML)
+ return false;
+
+ if (this.treeAdapter.getTagName(current) === $.ANNOTATION_XML && ns === NS.MATHML &&
+ token.type === Tokenizer.START_TAG_TOKEN && token.tagName === $.SVG)
+ return false;
+
+ var isCharacterToken = token.type === Tokenizer.CHARACTER_TOKEN ||
+ token.type === Tokenizer.NULL_CHARACTER_TOKEN ||
+ token.type === Tokenizer.WHITESPACE_CHARACTER_TOKEN,
+ isMathMLTextStartTag = token.type === Tokenizer.START_TAG_TOKEN &&
+ token.tagName !== $.MGLYPH &&
+ token.tagName !== $.MALIGNMARK;
+
+ if ((isMathMLTextStartTag || isCharacterToken) && this._isIntegrationPoint(current, NS.MATHML))
+ return false;
+
+ if ((token.type === Tokenizer.START_TAG_TOKEN || isCharacterToken) && this._isIntegrationPoint(current, NS.HTML))
+ return false;
+
+ return token.type !== Tokenizer.EOF_TOKEN;
+};
+
+Parser.prototype._processToken = function (token) {
+ _[this.insertionMode][token.type](this, token);
+};
+
+Parser.prototype._processTokenInBodyMode = function (token) {
+ _[IN_BODY_MODE][token.type](this, token);
+};
+
+Parser.prototype._processTokenInForeignContent = function (token) {
+ if (token.type === Tokenizer.CHARACTER_TOKEN)
+ characterInForeignContent(this, token);
+
+ else if (token.type === Tokenizer.NULL_CHARACTER_TOKEN)
+ nullCharacterInForeignContent(this, token);
+
+ else if (token.type === Tokenizer.WHITESPACE_CHARACTER_TOKEN)
+ insertCharacters(this, token);
+
+ else if (token.type === Tokenizer.COMMENT_TOKEN)
+ appendComment(this, token);
+
+ else if (token.type === Tokenizer.START_TAG_TOKEN)
+ startTagInForeignContent(this, token);
+
+ else if (token.type === Tokenizer.END_TAG_TOKEN)
+ endTagInForeignContent(this, token);
+};
+
+Parser.prototype._processInputToken = function (token) {
+ if (this._shouldProcessTokenInForeignContent(token))
+ this._processTokenInForeignContent(token);
+
+ else
+ this._processToken(token);
+};
+
+//Integration points
+Parser.prototype._isIntegrationPoint = function (element, foreignNS) {
+ var tn = this.treeAdapter.getTagName(element),
+ ns = this.treeAdapter.getNamespaceURI(element),
+ attrs = this.treeAdapter.getAttrList(element);
+
+ return foreignContent.isIntegrationPoint(tn, ns, attrs, foreignNS);
+};
+
+//Active formatting elements reconstruction
+Parser.prototype._reconstructActiveFormattingElements = function () {
+ var listLength = this.activeFormattingElements.length;
+
+ if (listLength) {
+ var unopenIdx = listLength,
+ entry = null;
+
+ do {
+ unopenIdx--;
+ entry = this.activeFormattingElements.entries[unopenIdx];
+
+ if (entry.type === FormattingElementList.MARKER_ENTRY || this.openElements.contains(entry.element)) {
+ unopenIdx++;
+ break;
+ }
+ } while (unopenIdx > 0);
+
+ for (var i = unopenIdx; i < listLength; i++) {
+ entry = this.activeFormattingElements.entries[i];
+ this._insertElement(entry.token, this.treeAdapter.getNamespaceURI(entry.element));
+ entry.element = this.openElements.current;
+ }
+ }
+};
+
+//Close elements
+Parser.prototype._closeTableCell = function () {
+ this.openElements.generateImpliedEndTags();
+ this.openElements.popUntilTableCellPopped();
+ this.activeFormattingElements.clearToLastMarker();
+ this.insertionMode = IN_ROW_MODE;
+};
+
+Parser.prototype._closePElement = function () {
+ this.openElements.generateImpliedEndTagsWithExclusion($.P);
+ this.openElements.popUntilTagNamePopped($.P);
+};
+
+//Insertion modes
+Parser.prototype._resetInsertionMode = function () {
+ for (var i = this.openElements.stackTop, last = false; i >= 0; i--) {
+ var element = this.openElements.items[i];
+
+ if (i === 0) {
+ last = true;
+
+ if (this.fragmentContext)
+ element = this.fragmentContext;
+ }
+
+ var tn = this.treeAdapter.getTagName(element),
+ newInsertionMode = INSERTION_MODE_RESET_MAP[tn];
+
+ if (newInsertionMode) {
+ this.insertionMode = newInsertionMode;
+ break;
+ }
+
+ else if (!last && (tn === $.TD || tn === $.TH)) {
+ this.insertionMode = IN_CELL_MODE;
+ break;
+ }
+
+ else if (!last && tn === $.HEAD) {
+ this.insertionMode = IN_HEAD_MODE;
+ break;
+ }
+
+ else if (tn === $.SELECT) {
+ this._resetInsertionModeForSelect(i);
+ break;
+ }
+
+ else if (tn === $.TEMPLATE) {
+ this.insertionMode = this.currentTmplInsertionMode;
+ break;
+ }
+
+ else if (tn === $.HTML) {
+ this.insertionMode = this.headElement ? AFTER_HEAD_MODE : BEFORE_HEAD_MODE;
+ break;
+ }
+
+ else if (last) {
+ this.insertionMode = IN_BODY_MODE;
+ break;
+ }
+ }
+};
+
+Parser.prototype._resetInsertionModeForSelect = function (selectIdx) {
+ if (selectIdx > 0) {
+ for (var i = selectIdx - 1; i > 0; i--) {
+ var ancestor = this.openElements.items[i],
+ tn = this.treeAdapter.getTagName(ancestor);
+
+ if (tn === $.TEMPLATE)
+ break;
+
+ else if (tn === $.TABLE) {
+ this.insertionMode = IN_SELECT_IN_TABLE_MODE;
+ return;
+ }
+ }
+ }
+
+ this.insertionMode = IN_SELECT_MODE;
+};
+
+Parser.prototype._pushTmplInsertionMode = function (mode) {
+ this.tmplInsertionModeStack.push(mode);
+ this.tmplInsertionModeStackTop++;
+ this.currentTmplInsertionMode = mode;
+};
+
+Parser.prototype._popTmplInsertionMode = function () {
+ this.tmplInsertionModeStack.pop();
+ this.tmplInsertionModeStackTop--;
+ this.currentTmplInsertionMode = this.tmplInsertionModeStack[this.tmplInsertionModeStackTop];
+};
+
+//Foster parenting
+Parser.prototype._isElementCausesFosterParenting = function (element) {
+ var tn = this.treeAdapter.getTagName(element);
+
+ return tn === $.TABLE || tn === $.TBODY || tn === $.TFOOT || tn === $.THEAD || tn === $.TR;
+};
+
+Parser.prototype._shouldFosterParentOnInsertion = function () {
+ return this.fosterParentingEnabled && this._isElementCausesFosterParenting(this.openElements.current);
+};
+
+Parser.prototype._findFosterParentingLocation = function () {
+ var location = {
+ parent: null,
+ beforeElement: null
+ };
+
+ for (var i = this.openElements.stackTop; i >= 0; i--) {
+ var openElement = this.openElements.items[i],
+ tn = this.treeAdapter.getTagName(openElement),
+ ns = this.treeAdapter.getNamespaceURI(openElement);
+
+ if (tn === $.TEMPLATE && ns === NS.HTML) {
+ location.parent = this.treeAdapter.getTemplateContent(openElement);
+ break;
+ }
+
+ else if (tn === $.TABLE) {
+ location.parent = this.treeAdapter.getParentNode(openElement);
+
+ if (location.parent)
+ location.beforeElement = openElement;
+ else
+ location.parent = this.openElements.items[i - 1];
+
+ break;
+ }
+ }
+
+ if (!location.parent)
+ location.parent = this.openElements.items[0];
+
+ return location;
+};
+
+Parser.prototype._fosterParentElement = function (element) {
+ var location = this._findFosterParentingLocation();
+
+ if (location.beforeElement)
+ this.treeAdapter.insertBefore(location.parent, element, location.beforeElement);
+ else
+ this.treeAdapter.appendChild(location.parent, element);
+};
+
+Parser.prototype._fosterParentText = function (chars) {
+ var location = this._findFosterParentingLocation();
+
+ if (location.beforeElement)
+ this.treeAdapter.insertTextBefore(location.parent, chars, location.beforeElement);
+ else
+ this.treeAdapter.insertText(location.parent, chars);
+};
+
+//Special elements
+Parser.prototype._isSpecialElement = function (element) {
+ var tn = this.treeAdapter.getTagName(element),
+ ns = this.treeAdapter.getNamespaceURI(element);
+
+ return HTML.SPECIAL_ELEMENTS[ns][tn];
+};
+
+//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) {
+ var 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.tagName))
+ formattingElementEntry = null;
+ }
+
+ else
+ genericEndTagInBody(p, token);
+
+ return formattingElementEntry;
+}
+
+//Steps 9 and 10 of the algorithm
+function aaObtainFurthestBlock(p, formattingElementEntry) {
+ var furthestBlock = null;
+
+ for (var i = p.openElements.stackTop; i >= 0; i--) {
+ var element = p.openElements.items[i];
+
+ if (element === formattingElementEntry.element)
+ break;
+
+ if (p._isSpecialElement(element))
+ furthestBlock = element;
+ }
+
+ if (!furthestBlock) {
+ p.openElements.popUntilElementPopped(formattingElementEntry.element);
+ p.activeFormattingElements.removeEntry(formattingElementEntry);
+ }
+
+ return furthestBlock;
+}
+
+//Step 13 of the algorithm
+function aaInnerLoop(p, furthestBlock, formattingElement) {
+ var lastElement = furthestBlock,
+ nextElement = p.openElements.getCommonAncestor(furthestBlock);
+
+ for (var i = 0, element = nextElement; element !== formattingElement; i++, element = nextElement) {
+ //NOTE: store next element for the next loop iteration (it may be deleted from the stack by step 9.5)
+ nextElement = p.openElements.getCommonAncestor(element);
+
+ var elementEntry = p.activeFormattingElements.getElementEntry(element),
+ counterOverflow = elementEntry && i >= AA_INNER_LOOP_ITER,
+ 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) {
+ var ns = p.treeAdapter.getNamespaceURI(elementEntry.element),
+ 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) {
+ if (p._isElementCausesFosterParenting(commonAncestor))
+ p._fosterParentElement(lastElement);
+
+ else {
+ var tn = p.treeAdapter.getTagName(commonAncestor),
+ ns = p.treeAdapter.getNamespaceURI(commonAncestor);
+
+ if (tn === $.TEMPLATE && ns === NS.HTML)
+ commonAncestor = p.treeAdapter.getTemplateContent(commonAncestor);
+
+ p.treeAdapter.appendChild(commonAncestor, lastElement);
+ }
+}
+
+//Steps 15-19 of the algorithm
+function aaReplaceFormattingElement(p, furthestBlock, formattingElementEntry) {
+ var ns = p.treeAdapter.getNamespaceURI(formattingElementEntry.element),
+ token = formattingElementEntry.token,
+ newElement = p.treeAdapter.createElement(token.tagName, ns, token.attrs);
+
+ p._adoptNodes(furthestBlock, newElement);
+ p.treeAdapter.appendChild(furthestBlock, newElement);
+
+ p.activeFormattingElements.insertElementAfterBookmark(newElement, formattingElementEntry.token);
+ p.activeFormattingElements.removeEntry(formattingElementEntry);
+
+ p.openElements.remove(formattingElementEntry.element);
+ p.openElements.insertAfter(furthestBlock, newElement);
+}
+
+//Algorithm entry point
+function callAdoptionAgency(p, token) {
+ var formattingElementEntry;
+
+ for (var i = 0; i < AA_OUTER_LOOP_ITER; i++) {
+ formattingElementEntry = aaObtainFormattingElementEntry(p, token, formattingElementEntry);
+
+ if (!formattingElementEntry)
+ break;
+
+ var furthestBlock = aaObtainFurthestBlock(p, formattingElementEntry);
+
+ if (!furthestBlock)
+ break;
+
+ p.activeFormattingElements.bookmark = formattingElementEntry;
+
+ var lastElement = aaInnerLoop(p, furthestBlock, formattingElementEntry.element),
+ commonAncestor = p.openElements.getCommonAncestor(formattingElementEntry.element);
+
+ p.treeAdapter.detachNode(lastElement);
+ aaInsertLastNodeInCommonAncestor(p, commonAncestor, lastElement);
+ aaReplaceFormattingElement(p, furthestBlock, formattingElementEntry);
+ }
+}
+
+
+//Generic token handlers
+//------------------------------------------------------------------
+function ignoreToken() {
+ //NOTE: do nothing =)
+}
+
+function appendComment(p, token) {
+ p._appendCommentNode(token, p.openElements.currentTmplContent || p.openElements.current);
+}
+
+function appendCommentToRootHtmlElement(p, token) {
+ p._appendCommentNode(token, p.openElements.items[0]);
+}
+
+function appendCommentToDocument(p, token) {
+ p._appendCommentNode(token, p.document);
+}
+
+function insertCharacters(p, token) {
+ p._insertCharacters(token);
+}
+
+function stopParsing(p) {
+ p.stopped = true;
+}
+
+//12.2.5.4.1 The "initial" insertion mode
+//------------------------------------------------------------------
+function doctypeInInitialMode(p, token) {
+ p._setDocumentType(token);
+
+ var mode = token.forceQuirks ?
+ HTML.DOCUMENT_MODE.QUIRKS :
+ doctype.getDocumentMode(token.name, token.publicId, token.systemId);
+
+ p.treeAdapter.setDocumentMode(p.document, mode);
+
+ p.insertionMode = BEFORE_HTML_MODE;
+}
+
+function tokenInInitialMode(p, token) {
+ p.treeAdapter.setDocumentMode(p.document, HTML.DOCUMENT_MODE.QUIRKS);
+ p.insertionMode = BEFORE_HTML_MODE;
+ p._processToken(token);
+}
+
+
+//12.2.5.4.2 The "before html" insertion mode
+//------------------------------------------------------------------
+function startTagBeforeHtml(p, token) {
+ if (token.tagName === $.HTML) {
+ p._insertElement(token, NS.HTML);
+ p.insertionMode = BEFORE_HEAD_MODE;
+ }
+
+ else
+ tokenBeforeHtml(p, token);
+}
+
+function endTagBeforeHtml(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.HTML || tn === $.HEAD || tn === $.BODY || tn === $.BR)
+ tokenBeforeHtml(p, token);
+}
+
+function tokenBeforeHtml(p, token) {
+ p._insertFakeRootElement();
+ p.insertionMode = BEFORE_HEAD_MODE;
+ p._processToken(token);
+}
+
+
+//12.2.5.4.3 The "before head" insertion mode
+//------------------------------------------------------------------
+function startTagBeforeHead(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.HTML)
+ startTagInBody(p, token);
+
+ else if (tn === $.HEAD) {
+ p._insertElement(token, NS.HTML);
+ p.headElement = p.openElements.current;
+ p.insertionMode = IN_HEAD_MODE;
+ }
+
+ else
+ tokenBeforeHead(p, token);
+}
+
+function endTagBeforeHead(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.HEAD || tn === $.BODY || tn === $.HTML || tn === $.BR)
+ tokenBeforeHead(p, token);
+}
+
+function tokenBeforeHead(p, token) {
+ p._insertFakeElement($.HEAD);
+ p.headElement = p.openElements.current;
+ p.insertionMode = IN_HEAD_MODE;
+ p._processToken(token);
+}
+
+
+//12.2.5.4.4 The "in head" insertion mode
+//------------------------------------------------------------------
+function startTagInHead(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.HTML)
+ startTagInBody(p, token);
+
+ else if (tn === $.BASE || tn === $.BASEFONT || tn === $.BGSOUND || tn === $.LINK || tn === $.META)
+ p._appendElement(token, NS.HTML);
+
+ else if (tn === $.TITLE)
+ p._switchToTextParsing(token, Tokenizer.MODE.RCDATA);
+
+ //NOTE: here we assume that we always act as an interactive user agent with enabled scripting, so we parse
+ //<noscript> as a rawtext.
+ else if (tn === $.NOSCRIPT || tn === $.NOFRAMES || tn === $.STYLE)
+ p._switchToTextParsing(token, Tokenizer.MODE.RAWTEXT);
+
+ else if (tn === $.SCRIPT)
+ p._switchToTextParsing(token, Tokenizer.MODE.SCRIPT_DATA);
+
+ else if (tn === $.TEMPLATE) {
+ p._insertTemplate(token, NS.HTML);
+ p.activeFormattingElements.insertMarker();
+ p.framesetOk = false;
+ p.insertionMode = IN_TEMPLATE_MODE;
+ p._pushTmplInsertionMode(IN_TEMPLATE_MODE);
+ }
+
+ else if (tn !== $.HEAD)
+ tokenInHead(p, token);
+}
+
+function endTagInHead(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.HEAD) {
+ p.openElements.pop();
+ p.insertionMode = AFTER_HEAD_MODE;
+ }
+
+ else if (tn === $.BODY || tn === $.BR || tn === $.HTML)
+ tokenInHead(p, token);
+
+ else if (tn === $.TEMPLATE && p.openElements.tmplCount > 0) {
+ p.openElements.generateImpliedEndTags();
+ p.openElements.popUntilTagNamePopped($.TEMPLATE);
+ p.activeFormattingElements.clearToLastMarker();
+ p._popTmplInsertionMode();
+ p._resetInsertionMode();
+ }
+}
+
+function tokenInHead(p, token) {
+ p.openElements.pop();
+ p.insertionMode = AFTER_HEAD_MODE;
+ p._processToken(token);
+}
+
+
+//12.2.5.4.6 The "after head" insertion mode
+//------------------------------------------------------------------
+function startTagAfterHead(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.HTML)
+ startTagInBody(p, token);
+
+ else if (tn === $.BODY) {
+ p._insertElement(token, NS.HTML);
+ p.framesetOk = false;
+ p.insertionMode = IN_BODY_MODE;
+ }
+
+ else if (tn === $.FRAMESET) {
+ p._insertElement(token, NS.HTML);
+ p.insertionMode = IN_FRAMESET_MODE;
+ }
+
+ else if (tn === $.BASE || tn === $.BASEFONT || tn === $.BGSOUND || tn === $.LINK || tn === $.META ||
+ tn === $.NOFRAMES || tn === $.SCRIPT || tn === $.STYLE || tn === $.TEMPLATE || tn === $.TITLE) {
+ p.openElements.push(p.headElement);
+ startTagInHead(p, token);
+ p.openElements.remove(p.headElement);
+ }
+
+ else if (tn !== $.HEAD)
+ tokenAfterHead(p, token);
+}
+
+function endTagAfterHead(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.BODY || tn === $.HTML || tn === $.BR)
+ tokenAfterHead(p, token);
+
+ else if (tn === $.TEMPLATE)
+ endTagInHead(p, token);
+}
+
+function tokenAfterHead(p, token) {
+ p._insertFakeElement($.BODY);
+ p.insertionMode = IN_BODY_MODE;
+ p._processToken(token);
+}
+
+
+//12.2.5.4.7 The "in body" insertion mode
+//------------------------------------------------------------------
+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) {
+ var bodyElement = p.openElements.tryPeekProperlyNestedBodyElement();
+
+ if (bodyElement && p.openElements.tmplCount === 0) {
+ p.framesetOk = false;
+ p.treeAdapter.adoptAttributes(bodyElement, token.attrs);
+ }
+}
+
+function framesetStartTagInBody(p, token) {
+ var bodyElement = p.openElements.tryPeekProperlyNestedBodyElement();
+
+ if (p.framesetOk && bodyElement) {
+ p.treeAdapter.detachNode(bodyElement);
+ p.openElements.popAllUpToHtmlElement();
+ p._insertElement(token, NS.HTML);
+ p.insertionMode = IN_FRAMESET_MODE;
+ }
+}
+
+function addressStartTagInBody(p, token) {
+ if (p.openElements.hasInButtonScope($.P))
+ p._closePElement();
+
+ p._insertElement(token, NS.HTML);
+}
+
+function numberedHeaderStartTagInBody(p, token) {
+ if (p.openElements.hasInButtonScope($.P))
+ p._closePElement();
+
+ var tn = p.openElements.currentTagName;
+
+ if (tn === $.H1 || tn === $.H2 || tn === $.H3 || tn === $.H4 || tn === $.H5 || tn === $.H6)
+ p.openElements.pop();
+
+ p._insertElement(token, NS.HTML);
+}
+
+function preStartTagInBody(p, token) {
+ if (p.openElements.hasInButtonScope($.P))
+ p._closePElement();
+
+ p._insertElement(token, 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) {
+ var inTemplate = p.openElements.tmplCount > 0;
+
+ if (!p.formElement || inTemplate) {
+ if (p.openElements.hasInButtonScope($.P))
+ p._closePElement();
+
+ p._insertElement(token, NS.HTML);
+
+ if (!inTemplate)
+ p.formElement = p.openElements.current;
+ }
+}
+
+function listItemStartTagInBody(p, token) {
+ p.framesetOk = false;
+
+ var tn = token.tagName;
+
+ for (var i = p.openElements.stackTop; i >= 0; i--) {
+ var element = p.openElements.items[i],
+ elementTn = p.treeAdapter.getTagName(element),
+ closeTn = null;
+
+ if (tn === $.LI && elementTn === $.LI)
+ closeTn = $.LI;
+
+ else if ((tn === $.DD || tn === $.DT) && (elementTn === $.DD || elementTn === $.DT))
+ closeTn = elementTn;
+
+ if (closeTn) {
+ p.openElements.generateImpliedEndTagsWithExclusion(closeTn);
+ p.openElements.popUntilTagNamePopped(closeTn);
+ break;
+ }
+
+ if (elementTn !== $.ADDRESS && elementTn !== $.DIV && elementTn !== $.P && p._isSpecialElement(element))
+ break;
+ }
+
+ if (p.openElements.hasInButtonScope($.P))
+ p._closePElement();
+
+ p._insertElement(token, NS.HTML);
+}
+
+function plaintextStartTagInBody(p, token) {
+ if (p.openElements.hasInButtonScope($.P))
+ p._closePElement();
+
+ p._insertElement(token, NS.HTML);
+ p.tokenizer.state = Tokenizer.MODE.PLAINTEXT;
+}
+
+function buttonStartTagInBody(p, token) {
+ if (p.openElements.hasInScope($.BUTTON)) {
+ p.openElements.generateImpliedEndTags();
+ p.openElements.popUntilTagNamePopped($.BUTTON);
+ }
+
+ p._reconstructActiveFormattingElements();
+ p._insertElement(token, NS.HTML);
+ p.framesetOk = false;
+}
+
+function aStartTagInBody(p, token) {
+ var activeElementEntry = p.activeFormattingElements.getElementEntryInScopeWithTagName($.A);
+
+ if (activeElementEntry) {
+ callAdoptionAgency(p, token);
+ p.openElements.remove(activeElementEntry.element);
+ p.activeFormattingElements.removeEntry(activeElementEntry);
+ }
+
+ p._reconstructActiveFormattingElements();
+ p._insertElement(token, NS.HTML);
+ p.activeFormattingElements.pushElement(p.openElements.current, token);
+}
+
+function bStartTagInBody(p, token) {
+ p._reconstructActiveFormattingElements();
+ p._insertElement(token, NS.HTML);
+ p.activeFormattingElements.pushElement(p.openElements.current, token);
+}
+
+function nobrStartTagInBody(p, token) {
+ p._reconstructActiveFormattingElements();
+
+ if (p.openElements.hasInScope($.NOBR)) {
+ callAdoptionAgency(p, token);
+ p._reconstructActiveFormattingElements();
+ }
+
+ p._insertElement(token, NS.HTML);
+ p.activeFormattingElements.pushElement(p.openElements.current, token);
+}
+
+function appletStartTagInBody(p, token) {
+ p._reconstructActiveFormattingElements();
+ p._insertElement(token, NS.HTML);
+ p.activeFormattingElements.insertMarker();
+ p.framesetOk = false;
+}
+
+function tableStartTagInBody(p, token) {
+ if (p.treeAdapter.getDocumentMode(p.document) !== HTML.DOCUMENT_MODE.QUIRKS && p.openElements.hasInButtonScope($.P))
+ p._closePElement();
+
+ p._insertElement(token, NS.HTML);
+ p.framesetOk = false;
+ p.insertionMode = IN_TABLE_MODE;
+}
+
+function areaStartTagInBody(p, token) {
+ p._reconstructActiveFormattingElements();
+ p._appendElement(token, NS.HTML);
+ p.framesetOk = false;
+}
+
+function inputStartTagInBody(p, token) {
+ p._reconstructActiveFormattingElements();
+ p._appendElement(token, NS.HTML);
+
+ var inputType = Tokenizer.getTokenAttr(token, ATTRS.TYPE);
+
+ if (!inputType || inputType.toLowerCase() !== HIDDEN_INPUT_TYPE)
+ p.framesetOk = false;
+
+}
+
+function paramStartTagInBody(p, token) {
+ p._appendElement(token, NS.HTML);
+}
+
+function hrStartTagInBody(p, token) {
+ if (p.openElements.hasInButtonScope($.P))
+ p._closePElement();
+
+ if (p.openElements.currentTagName === $.MENUITEM)
+ p.openElements.pop();
+
+ p._appendElement(token, NS.HTML);
+ p.framesetOk = false;
+}
+
+function imageStartTagInBody(p, token) {
+ token.tagName = $.IMG;
+ areaStartTagInBody(p, token);
+}
+
+function textareaStartTagInBody(p, token) {
+ p._insertElement(token, 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 = Tokenizer.MODE.RCDATA;
+ p.originalInsertionMode = p.insertionMode;
+ p.framesetOk = false;
+ p.insertionMode = TEXT_MODE;
+}
+
+function xmpStartTagInBody(p, token) {
+ if (p.openElements.hasInButtonScope($.P))
+ p._closePElement();
+
+ p._reconstructActiveFormattingElements();
+ p.framesetOk = false;
+ p._switchToTextParsing(token, Tokenizer.MODE.RAWTEXT);
+}
+
+function iframeStartTagInBody(p, token) {
+ p.framesetOk = false;
+ p._switchToTextParsing(token, Tokenizer.MODE.RAWTEXT);
+}
+
+//NOTE: here we assume that we always act as an user agent with enabled plugins, so we parse
+//<noembed> as a rawtext.
+function noembedStartTagInBody(p, token) {
+ p._switchToTextParsing(token, Tokenizer.MODE.RAWTEXT);
+}
+
+function selectStartTagInBody(p, token) {
+ p._reconstructActiveFormattingElements();
+ p._insertElement(token, NS.HTML);
+ p.framesetOk = false;
+
+ if (p.insertionMode === IN_TABLE_MODE ||
+ p.insertionMode === IN_CAPTION_MODE ||
+ p.insertionMode === IN_TABLE_BODY_MODE ||
+ p.insertionMode === IN_ROW_MODE ||
+ p.insertionMode === IN_CELL_MODE)
+
+ p.insertionMode = IN_SELECT_IN_TABLE_MODE;
+
+ else
+ p.insertionMode = IN_SELECT_MODE;
+}
+
+function optgroupStartTagInBody(p, token) {
+ if (p.openElements.currentTagName === $.OPTION)
+ p.openElements.pop();
+
+ p._reconstructActiveFormattingElements();
+ p._insertElement(token, NS.HTML);
+}
+
+function rbStartTagInBody(p, token) {
+ if (p.openElements.hasInScope($.RUBY))
+ p.openElements.generateImpliedEndTags();
+
+ p._insertElement(token, NS.HTML);
+}
+
+function rtStartTagInBody(p, token) {
+ if (p.openElements.hasInScope($.RUBY))
+ p.openElements.generateImpliedEndTagsWithExclusion($.RTC);
+
+ p._insertElement(token, NS.HTML);
+}
+
+function menuitemStartTagInBody(p, token) {
+ if (p.openElements.currentTagName === $.MENUITEM)
+ p.openElements.pop();
+
+ // TODO needs clarification, see https://github.com/whatwg/html/pull/907/files#r73505877
+ p._reconstructActiveFormattingElements();
+
+ p._insertElement(token, NS.HTML);
+}
+
+function menuStartTagInBody(p, token) {
+ if (p.openElements.hasInButtonScope($.P))
+ p._closePElement();
+
+ if (p.openElements.currentTagName === $.MENUITEM)
+ p.openElements.pop();
+
+ p._insertElement(token, NS.HTML);
+}
+
+function mathStartTagInBody(p, token) {
+ p._reconstructActiveFormattingElements();
+
+ foreignContent.adjustTokenMathMLAttrs(token);
+ foreignContent.adjustTokenXMLAttrs(token);
+
+ if (token.selfClosing)
+ p._appendElement(token, NS.MATHML);
+ else
+ p._insertElement(token, NS.MATHML);
+}
+
+function svgStartTagInBody(p, token) {
+ p._reconstructActiveFormattingElements();
+
+ foreignContent.adjustTokenSVGAttrs(token);
+ foreignContent.adjustTokenXMLAttrs(token);
+
+ if (token.selfClosing)
+ p._appendElement(token, NS.SVG);
+ else
+ p._insertElement(token, NS.SVG);
+}
+
+function genericStartTagInBody(p, token) {
+ p._reconstructActiveFormattingElements();
+ p._insertElement(token, NS.HTML);
+}
+
+//OPTIMIZATION: Integer comparisons are low-cost, so we can use very fast tag name length filters here.
+//It's faster than using dictionary.
+function startTagInBody(p, token) {
+ var tn = token.tagName;
+
+ switch (tn.length) {
+ case 1:
+ if (tn === $.I || tn === $.S || tn === $.B || tn === $.U)
+ bStartTagInBody(p, token);
+
+ else if (tn === $.P)
+ addressStartTagInBody(p, token);
+
+ else if (tn === $.A)
+ aStartTagInBody(p, token);
+
+ else
+ genericStartTagInBody(p, token);
+
+ break;
+
+ case 2:
+ if (tn === $.DL || tn === $.OL || tn === $.UL)
+ addressStartTagInBody(p, token);
+
+ else if (tn === $.H1 || tn === $.H2 || tn === $.H3 || tn === $.H4 || tn === $.H5 || tn === $.H6)
+ numberedHeaderStartTagInBody(p, token);
+
+ else if (tn === $.LI || tn === $.DD || tn === $.DT)
+ listItemStartTagInBody(p, token);
+
+ else if (tn === $.EM || tn === $.TT)
+ bStartTagInBody(p, token);
+
+ else if (tn === $.BR)
+ areaStartTagInBody(p, token);
+
+ else if (tn === $.HR)
+ hrStartTagInBody(p, token);
+
+ else if (tn === $.RB)
+ rbStartTagInBody(p, token);
+
+ else if (tn === $.RT || tn === $.RP)
+ rtStartTagInBody(p, token);
+
+ else if (tn !== $.TH && tn !== $.TD && tn !== $.TR)
+ genericStartTagInBody(p, token);
+
+ break;
+
+ case 3:
+ if (tn === $.DIV || tn === $.DIR || tn === $.NAV)
+ addressStartTagInBody(p, token);
+
+ else if (tn === $.PRE)
+ preStartTagInBody(p, token);
+
+ else if (tn === $.BIG)
+ bStartTagInBody(p, token);
+
+ else if (tn === $.IMG || tn === $.WBR)
+ areaStartTagInBody(p, token);
+
+ else if (tn === $.XMP)
+ xmpStartTagInBody(p, token);
+
+ else if (tn === $.SVG)
+ svgStartTagInBody(p, token);
+
+ else if (tn === $.RTC)
+ rbStartTagInBody(p, token);
+
+ else if (tn !== $.COL)
+ genericStartTagInBody(p, token);
+
+ break;
+
+ case 4:
+ if (tn === $.HTML)
+ htmlStartTagInBody(p, token);
+
+ else if (tn === $.BASE || tn === $.LINK || tn === $.META)
+ startTagInHead(p, token);
+
+ else if (tn === $.BODY)
+ bodyStartTagInBody(p, token);
+
+ else if (tn === $.MAIN)
+ addressStartTagInBody(p, token);
+
+ else if (tn === $.FORM)
+ formStartTagInBody(p, token);
+
+ else if (tn === $.CODE || tn === $.FONT)
+ bStartTagInBody(p, token);
+
+ else if (tn === $.NOBR)
+ nobrStartTagInBody(p, token);
+
+ else if (tn === $.AREA)
+ areaStartTagInBody(p, token);
+
+ else if (tn === $.MATH)
+ mathStartTagInBody(p, token);
+
+ else if (tn === $.MENU)
+ menuStartTagInBody(p, token);
+
+ else if (tn !== $.HEAD)
+ genericStartTagInBody(p, token);
+
+ break;
+
+ case 5:
+ if (tn === $.STYLE || tn === $.TITLE)
+ startTagInHead(p, token);
+
+ else if (tn === $.ASIDE)
+ addressStartTagInBody(p, token);
+
+ else if (tn === $.SMALL)
+ bStartTagInBody(p, token);
+
+ else if (tn === $.TABLE)
+ tableStartTagInBody(p, token);
+
+ else if (tn === $.EMBED)
+ areaStartTagInBody(p, token);
+
+ else if (tn === $.INPUT)
+ inputStartTagInBody(p, token);
+
+ else if (tn === $.PARAM || tn === $.TRACK)
+ paramStartTagInBody(p, token);
+
+ else if (tn === $.IMAGE)
+ imageStartTagInBody(p, token);
+
+ else if (tn !== $.FRAME && tn !== $.TBODY && tn !== $.TFOOT && tn !== $.THEAD)
+ genericStartTagInBody(p, token);
+
+ break;
+
+ case 6:
+ if (tn === $.SCRIPT)
+ startTagInHead(p, token);
+
+ else if (tn === $.CENTER || tn === $.FIGURE || tn === $.FOOTER || tn === $.HEADER || tn === $.HGROUP)
+ addressStartTagInBody(p, token);
+
+ else if (tn === $.BUTTON)
+ buttonStartTagInBody(p, token);
+
+ else if (tn === $.STRIKE || tn === $.STRONG)
+ bStartTagInBody(p, token);
+
+ else if (tn === $.APPLET || tn === $.OBJECT)
+ appletStartTagInBody(p, token);
+
+ else if (tn === $.KEYGEN)
+ areaStartTagInBody(p, token);
+
+ else if (tn === $.SOURCE)
+ paramStartTagInBody(p, token);
+
+ else if (tn === $.IFRAME)
+ iframeStartTagInBody(p, token);
+
+ else if (tn === $.SELECT)
+ selectStartTagInBody(p, token);
+
+ else if (tn === $.OPTION)
+ optgroupStartTagInBody(p, token);
+
+ else
+ genericStartTagInBody(p, token);
+
+ break;
+
+ case 7:
+ if (tn === $.BGSOUND)
+ startTagInHead(p, token);
+
+ else if (tn === $.DETAILS || tn === $.ADDRESS || tn === $.ARTICLE || tn === $.SECTION || tn === $.SUMMARY)
+ addressStartTagInBody(p, token);
+
+ else if (tn === $.LISTING)
+ preStartTagInBody(p, token);
+
+ else if (tn === $.MARQUEE)
+ appletStartTagInBody(p, token);
+
+ else if (tn === $.NOEMBED)
+ noembedStartTagInBody(p, token);
+
+ else if (tn !== $.CAPTION)
+ genericStartTagInBody(p, token);
+
+ break;
+
+ case 8:
+ if (tn === $.BASEFONT)
+ startTagInHead(p, token);
+
+ else if (tn === $.MENUITEM)
+ menuitemStartTagInBody(p, token);
+
+ else if (tn === $.FRAMESET)
+ framesetStartTagInBody(p, token);
+
+ else if (tn === $.FIELDSET)
+ addressStartTagInBody(p, token);
+
+ else if (tn === $.TEXTAREA)
+ textareaStartTagInBody(p, token);
+
+ else if (tn === $.TEMPLATE)
+ startTagInHead(p, token);
+
+ else if (tn === $.NOSCRIPT)
+ noembedStartTagInBody(p, token);
+
+ else if (tn === $.OPTGROUP)
+ optgroupStartTagInBody(p, token);
+
+ else if (tn !== $.COLGROUP)
+ genericStartTagInBody(p, token);
+
+ break;
+
+ case 9:
+ if (tn === $.PLAINTEXT)
+ plaintextStartTagInBody(p, token);
+
+ else
+ genericStartTagInBody(p, token);
+
+ break;
+
+ case 10:
+ if (tn === $.BLOCKQUOTE || tn === $.FIGCAPTION)
+ addressStartTagInBody(p, token);
+
+ else
+ genericStartTagInBody(p, token);
+
+ break;
+
+ default:
+ genericStartTagInBody(p, token);
+ }
+}
+
+function bodyEndTagInBody(p) {
+ if (p.openElements.hasInScope($.BODY))
+ p.insertionMode = AFTER_BODY_MODE;
+}
+
+function htmlEndTagInBody(p, token) {
+ if (p.openElements.hasInScope($.BODY)) {
+ p.insertionMode = AFTER_BODY_MODE;
+ p._processToken(token);
+ }
+}
+
+function addressEndTagInBody(p, token) {
+ var tn = token.tagName;
+
+ if (p.openElements.hasInScope(tn)) {
+ p.openElements.generateImpliedEndTags();
+ p.openElements.popUntilTagNamePopped(tn);
+ }
+}
+
+function formEndTagInBody(p) {
+ var inTemplate = p.openElements.tmplCount > 0,
+ formElement = p.formElement;
+
+ if (!inTemplate)
+ p.formElement = null;
+
+ if ((formElement || inTemplate) && p.openElements.hasInScope($.FORM)) {
+ p.openElements.generateImpliedEndTags();
+
+ if (inTemplate)
+ p.openElements.popUntilTagNamePopped($.FORM);
+
+ else
+ p.openElements.remove(formElement);
+ }
+}
+
+function pEndTagInBody(p) {
+ if (!p.openElements.hasInButtonScope($.P))
+ p._insertFakeElement($.P);
+
+ p._closePElement();
+}
+
+function liEndTagInBody(p) {
+ if (p.openElements.hasInListItemScope($.LI)) {
+ p.openElements.generateImpliedEndTagsWithExclusion($.LI);
+ p.openElements.popUntilTagNamePopped($.LI);
+ }
+}
+
+function ddEndTagInBody(p, token) {
+ var tn = token.tagName;
+
+ 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) {
+ var tn = token.tagName;
+
+ if (p.openElements.hasInScope(tn)) {
+ p.openElements.generateImpliedEndTags();
+ p.openElements.popUntilTagNamePopped(tn);
+ p.activeFormattingElements.clearToLastMarker();
+ }
+}
+
+function brEndTagInBody(p) {
+ p._reconstructActiveFormattingElements();
+ p._insertFakeElement($.BR);
+ p.openElements.pop();
+ p.framesetOk = false;
+}
+
+function genericEndTagInBody(p, token) {
+ var tn = token.tagName;
+
+ for (var i = p.openElements.stackTop; i > 0; i--) {
+ var element = p.openElements.items[i];
+
+ if (p.treeAdapter.getTagName(element) === tn) {
+ p.openElements.generateImpliedEndTagsWithExclusion(tn);
+ p.openElements.popUntilElementPopped(element);
+ break;
+ }
+
+ if (p._isSpecialElement(element))
+ break;
+ }
+}
+
+//OPTIMIZATION: Integer comparisons are low-cost, so we can use very fast tag name length filters here.
+//It's faster than using dictionary.
+function endTagInBody(p, token) {
+ var tn = token.tagName;
+
+ switch (tn.length) {
+ case 1:
+ if (tn === $.A || tn === $.B || tn === $.I || tn === $.S || tn === $.U)
+ callAdoptionAgency(p, token);
+
+ else if (tn === $.P)
+ pEndTagInBody(p, token);
+
+ else
+ genericEndTagInBody(p, token);
+
+ break;
+
+ case 2:
+ if (tn === $.DL || tn === $.UL || tn === $.OL)
+ addressEndTagInBody(p, token);
+
+ else if (tn === $.LI)
+ liEndTagInBody(p, token);
+
+ else if (tn === $.DD || tn === $.DT)
+ ddEndTagInBody(p, token);
+
+ else if (tn === $.H1 || tn === $.H2 || tn === $.H3 || tn === $.H4 || tn === $.H5 || tn === $.H6)
+ numberedHeaderEndTagInBody(p, token);
+
+ else if (tn === $.BR)
+ brEndTagInBody(p, token);
+
+ else if (tn === $.EM || tn === $.TT)
+ callAdoptionAgency(p, token);
+
+ else
+ genericEndTagInBody(p, token);
+
+ break;
+
+ case 3:
+ if (tn === $.BIG)
+ callAdoptionAgency(p, token);
+
+ else if (tn === $.DIR || tn === $.DIV || tn === $.NAV)
+ addressEndTagInBody(p, token);
+
+ else
+ genericEndTagInBody(p, token);
+
+ break;
+
+ case 4:
+ if (tn === $.BODY)
+ bodyEndTagInBody(p, token);
+
+ else if (tn === $.HTML)
+ htmlEndTagInBody(p, token);
+
+ else if (tn === $.FORM)
+ formEndTagInBody(p, token);
+
+ else if (tn === $.CODE || tn === $.FONT || tn === $.NOBR)
+ callAdoptionAgency(p, token);
+
+ else if (tn === $.MAIN || tn === $.MENU)
+ addressEndTagInBody(p, token);
+
+ else
+ genericEndTagInBody(p, token);
+
+ break;
+
+ case 5:
+ if (tn === $.ASIDE)
+ addressEndTagInBody(p, token);
+
+ else if (tn === $.SMALL)
+ callAdoptionAgency(p, token);
+
+ else
+ genericEndTagInBody(p, token);
+
+ break;
+
+ case 6:
+ if (tn === $.CENTER || tn === $.FIGURE || tn === $.FOOTER || tn === $.HEADER || tn === $.HGROUP)
+ addressEndTagInBody(p, token);
+
+ else if (tn === $.APPLET || tn === $.OBJECT)
+ appletEndTagInBody(p, token);
+
+ else if (tn === $.STRIKE || tn === $.STRONG)
+ callAdoptionAgency(p, token);
+
+ else
+ genericEndTagInBody(p, token);
+
+ break;
+
+ case 7:
+ if (tn === $.ADDRESS || tn === $.ARTICLE || tn === $.DETAILS || tn === $.SECTION || tn === $.SUMMARY)
+ addressEndTagInBody(p, token);
+
+ else if (tn === $.MARQUEE)
+ appletEndTagInBody(p, token);
+
+ else
+ genericEndTagInBody(p, token);
+
+ break;
+
+ case 8:
+ if (tn === $.FIELDSET)
+ addressEndTagInBody(p, token);
+
+ else if (tn === $.TEMPLATE)
+ endTagInHead(p, token);
+
+ else
+ genericEndTagInBody(p, token);
+
+ break;
+
+ case 10:
+ if (tn === $.BLOCKQUOTE || tn === $.FIGCAPTION)
+ addressEndTagInBody(p, token);
+
+ else
+ genericEndTagInBody(p, token);
+
+ break;
+
+ default :
+ genericEndTagInBody(p, token);
+ }
+}
+
+function eofInBody(p, token) {
+ if (p.tmplInsertionModeStackTop > -1)
+ eofInTemplate(p, token);
+
+ else
+ p.stopped = true;
+}
+
+//12.2.5.4.8 The "text" insertion mode
+//------------------------------------------------------------------
+function endTagInText(p, token) {
+ if (token.tagName === $.SCRIPT)
+ p.pendingScript = p.openElements.current;
+
+ p.openElements.pop();
+ p.insertionMode = p.originalInsertionMode;
+}
+
+
+function eofInText(p, token) {
+ p.openElements.pop();
+ p.insertionMode = p.originalInsertionMode;
+ p._processToken(token);
+}
+
+
+//12.2.5.4.9 The "in table" insertion mode
+//------------------------------------------------------------------
+function characterInTable(p, token) {
+ var curTn = p.openElements.currentTagName;
+
+ if (curTn === $.TABLE || curTn === $.TBODY || curTn === $.TFOOT || curTn === $.THEAD || curTn === $.TR) {
+ p.pendingCharacterTokens = [];
+ p.hasNonWhitespacePendingCharacterToken = false;
+ p.originalInsertionMode = p.insertionMode;
+ p.insertionMode = IN_TABLE_TEXT_MODE;
+ p._processToken(token);
+ }
+
+ else
+ tokenInTable(p, token);
+}
+
+function captionStartTagInTable(p, token) {
+ p.openElements.clearBackToTableContext();
+ p.activeFormattingElements.insertMarker();
+ p._insertElement(token, NS.HTML);
+ p.insertionMode = IN_CAPTION_MODE;
+}
+
+function colgroupStartTagInTable(p, token) {
+ p.openElements.clearBackToTableContext();
+ p._insertElement(token, NS.HTML);
+ p.insertionMode = IN_COLUMN_GROUP_MODE;
+}
+
+function colStartTagInTable(p, token) {
+ p.openElements.clearBackToTableContext();
+ p._insertFakeElement($.COLGROUP);
+ p.insertionMode = IN_COLUMN_GROUP_MODE;
+ p._processToken(token);
+}
+
+function tbodyStartTagInTable(p, token) {
+ p.openElements.clearBackToTableContext();
+ p._insertElement(token, NS.HTML);
+ p.insertionMode = IN_TABLE_BODY_MODE;
+}
+
+function tdStartTagInTable(p, token) {
+ p.openElements.clearBackToTableContext();
+ p._insertFakeElement($.TBODY);
+ p.insertionMode = IN_TABLE_BODY_MODE;
+ p._processToken(token);
+}
+
+function tableStartTagInTable(p, token) {
+ if (p.openElements.hasInTableScope($.TABLE)) {
+ p.openElements.popUntilTagNamePopped($.TABLE);
+ p._resetInsertionMode();
+ p._processToken(token);
+ }
+}
+
+function inputStartTagInTable(p, token) {
+ var inputType = Tokenizer.getTokenAttr(token, ATTRS.TYPE);
+
+ if (inputType && inputType.toLowerCase() === HIDDEN_INPUT_TYPE)
+ p._appendElement(token, NS.HTML);
+
+ else
+ tokenInTable(p, token);
+}
+
+function formStartTagInTable(p, token) {
+ if (!p.formElement && p.openElements.tmplCount === 0) {
+ p._insertElement(token, NS.HTML);
+ p.formElement = p.openElements.current;
+ p.openElements.pop();
+ }
+}
+
+function startTagInTable(p, token) {
+ var tn = token.tagName;
+
+ switch (tn.length) {
+ case 2:
+ if (tn === $.TD || tn === $.TH || tn === $.TR)
+ tdStartTagInTable(p, token);
+
+ else
+ tokenInTable(p, token);
+
+ break;
+
+ case 3:
+ if (tn === $.COL)
+ colStartTagInTable(p, token);
+
+ else
+ tokenInTable(p, token);
+
+ break;
+
+ case 4:
+ if (tn === $.FORM)
+ formStartTagInTable(p, token);
+
+ else
+ tokenInTable(p, token);
+
+ break;
+
+ case 5:
+ if (tn === $.TABLE)
+ tableStartTagInTable(p, token);
+
+ else if (tn === $.STYLE)
+ startTagInHead(p, token);
+
+ else if (tn === $.TBODY || tn === $.TFOOT || tn === $.THEAD)
+ tbodyStartTagInTable(p, token);
+
+ else if (tn === $.INPUT)
+ inputStartTagInTable(p, token);
+
+ else
+ tokenInTable(p, token);
+
+ break;
+
+ case 6:
+ if (tn === $.SCRIPT)
+ startTagInHead(p, token);
+
+ else
+ tokenInTable(p, token);
+
+ break;
+
+ case 7:
+ if (tn === $.CAPTION)
+ captionStartTagInTable(p, token);
+
+ else
+ tokenInTable(p, token);
+
+ break;
+
+ case 8:
+ if (tn === $.COLGROUP)
+ colgroupStartTagInTable(p, token);
+
+ else if (tn === $.TEMPLATE)
+ startTagInHead(p, token);
+
+ else
+ tokenInTable(p, token);
+
+ break;
+
+ default:
+ tokenInTable(p, token);
+ }
+
+}
+
+function endTagInTable(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.TABLE) {
+ if (p.openElements.hasInTableScope($.TABLE)) {
+ p.openElements.popUntilTagNamePopped($.TABLE);
+ p._resetInsertionMode();
+ }
+ }
+
+ else if (tn === $.TEMPLATE)
+ endTagInHead(p, token);
+
+ else if (tn !== $.BODY && tn !== $.CAPTION && tn !== $.COL && tn !== $.COLGROUP && tn !== $.HTML &&
+ tn !== $.TBODY && tn !== $.TD && tn !== $.TFOOT && tn !== $.TH && tn !== $.THEAD && tn !== $.TR)
+ tokenInTable(p, token);
+}
+
+function tokenInTable(p, token) {
+ var savedFosterParentingState = p.fosterParentingEnabled;
+
+ p.fosterParentingEnabled = true;
+ p._processTokenInBodyMode(token);
+ p.fosterParentingEnabled = savedFosterParentingState;
+}
+
+
+//12.2.5.4.10 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) {
+ var 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);
+}
+
+
+//12.2.5.4.11 The "in caption" insertion mode
+//------------------------------------------------------------------
+function startTagInCaption(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.CAPTION || tn === $.COL || tn === $.COLGROUP || tn === $.TBODY ||
+ tn === $.TD || tn === $.TFOOT || tn === $.TH || tn === $.THEAD || tn === $.TR) {
+ if (p.openElements.hasInTableScope($.CAPTION)) {
+ p.openElements.generateImpliedEndTags();
+ p.openElements.popUntilTagNamePopped($.CAPTION);
+ p.activeFormattingElements.clearToLastMarker();
+ p.insertionMode = IN_TABLE_MODE;
+ p._processToken(token);
+ }
+ }
+
+ else
+ startTagInBody(p, token);
+}
+
+function endTagInCaption(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.CAPTION || tn === $.TABLE) {
+ if (p.openElements.hasInTableScope($.CAPTION)) {
+ p.openElements.generateImpliedEndTags();
+ p.openElements.popUntilTagNamePopped($.CAPTION);
+ p.activeFormattingElements.clearToLastMarker();
+ p.insertionMode = IN_TABLE_MODE;
+
+ if (tn === $.TABLE)
+ p._processToken(token);
+ }
+ }
+
+ else if (tn !== $.BODY && tn !== $.COL && tn !== $.COLGROUP && tn !== $.HTML && tn !== $.TBODY &&
+ tn !== $.TD && tn !== $.TFOOT && tn !== $.TH && tn !== $.THEAD && tn !== $.TR)
+ endTagInBody(p, token);
+}
+
+
+//12.2.5.4.12 The "in column group" insertion mode
+//------------------------------------------------------------------
+function startTagInColumnGroup(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.HTML)
+ startTagInBody(p, token);
+
+ else if (tn === $.COL)
+ p._appendElement(token, NS.HTML);
+
+ else if (tn === $.TEMPLATE)
+ startTagInHead(p, token);
+
+ else
+ tokenInColumnGroup(p, token);
+}
+
+function endTagInColumnGroup(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.COLGROUP) {
+ if (p.openElements.currentTagName === $.COLGROUP) {
+ p.openElements.pop();
+ p.insertionMode = IN_TABLE_MODE;
+ }
+ }
+
+ else if (tn === $.TEMPLATE)
+ endTagInHead(p, token);
+
+ else if (tn !== $.COL)
+ tokenInColumnGroup(p, token);
+}
+
+function tokenInColumnGroup(p, token) {
+ if (p.openElements.currentTagName === $.COLGROUP) {
+ p.openElements.pop();
+ p.insertionMode = IN_TABLE_MODE;
+ p._processToken(token);
+ }
+}
+
+//12.2.5.4.13 The "in table body" insertion mode
+//------------------------------------------------------------------
+function startTagInTableBody(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.TR) {
+ p.openElements.clearBackToTableBodyContext();
+ p._insertElement(token, NS.HTML);
+ p.insertionMode = IN_ROW_MODE;
+ }
+
+ else if (tn === $.TH || tn === $.TD) {
+ p.openElements.clearBackToTableBodyContext();
+ p._insertFakeElement($.TR);
+ p.insertionMode = IN_ROW_MODE;
+ p._processToken(token);
+ }
+
+ else if (tn === $.CAPTION || tn === $.COL || tn === $.COLGROUP ||
+ tn === $.TBODY || tn === $.TFOOT || tn === $.THEAD) {
+
+ if (p.openElements.hasTableBodyContextInTableScope()) {
+ p.openElements.clearBackToTableBodyContext();
+ p.openElements.pop();
+ p.insertionMode = IN_TABLE_MODE;
+ p._processToken(token);
+ }
+ }
+
+ else
+ startTagInTable(p, token);
+}
+
+function endTagInTableBody(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.TBODY || tn === $.TFOOT || tn === $.THEAD) {
+ if (p.openElements.hasInTableScope(tn)) {
+ p.openElements.clearBackToTableBodyContext();
+ p.openElements.pop();
+ p.insertionMode = IN_TABLE_MODE;
+ }
+ }
+
+ else if (tn === $.TABLE) {
+ if (p.openElements.hasTableBodyContextInTableScope()) {
+ p.openElements.clearBackToTableBodyContext();
+ p.openElements.pop();
+ p.insertionMode = IN_TABLE_MODE;
+ p._processToken(token);
+ }
+ }
+
+ else if (tn !== $.BODY && tn !== $.CAPTION && tn !== $.COL && tn !== $.COLGROUP ||
+ tn !== $.HTML && tn !== $.TD && tn !== $.TH && tn !== $.TR)
+ endTagInTable(p, token);
+}
+
+//12.2.5.4.14 The "in row" insertion mode
+//------------------------------------------------------------------
+function startTagInRow(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.TH || tn === $.TD) {
+ p.openElements.clearBackToTableRowContext();
+ p._insertElement(token, NS.HTML);
+ p.insertionMode = IN_CELL_MODE;
+ p.activeFormattingElements.insertMarker();
+ }
+
+ else if (tn === $.CAPTION || tn === $.COL || tn === $.COLGROUP || tn === $.TBODY ||
+ tn === $.TFOOT || tn === $.THEAD || tn === $.TR) {
+ if (p.openElements.hasInTableScope($.TR)) {
+ p.openElements.clearBackToTableRowContext();
+ p.openElements.pop();
+ p.insertionMode = IN_TABLE_BODY_MODE;
+ p._processToken(token);
+ }
+ }
+
+ else
+ startTagInTable(p, token);
+}
+
+function endTagInRow(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.TR) {
+ if (p.openElements.hasInTableScope($.TR)) {
+ p.openElements.clearBackToTableRowContext();
+ p.openElements.pop();
+ p.insertionMode = IN_TABLE_BODY_MODE;
+ }
+ }
+
+ else if (tn === $.TABLE) {
+ if (p.openElements.hasInTableScope($.TR)) {
+ p.openElements.clearBackToTableRowContext();
+ p.openElements.pop();
+ p.insertionMode = IN_TABLE_BODY_MODE;
+ p._processToken(token);
+ }
+ }
+
+ else if (tn === $.TBODY || tn === $.TFOOT || tn === $.THEAD) {
+ if (p.openElements.hasInTableScope(tn) || p.openElements.hasInTableScope($.TR)) {
+ p.openElements.clearBackToTableRowContext();
+ p.openElements.pop();
+ p.insertionMode = IN_TABLE_BODY_MODE;
+ p._processToken(token);
+ }
+ }
+
+ else if (tn !== $.BODY && tn !== $.CAPTION && tn !== $.COL && tn !== $.COLGROUP ||
+ tn !== $.HTML && tn !== $.TD && tn !== $.TH)
+ endTagInTable(p, token);
+}
+
+
+//12.2.5.4.15 The "in cell" insertion mode
+//------------------------------------------------------------------
+function startTagInCell(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.CAPTION || tn === $.COL || tn === $.COLGROUP || tn === $.TBODY ||
+ tn === $.TD || tn === $.TFOOT || tn === $.TH || tn === $.THEAD || tn === $.TR) {
+
+ if (p.openElements.hasInTableScope($.TD) || p.openElements.hasInTableScope($.TH)) {
+ p._closeTableCell();
+ p._processToken(token);
+ }
+ }
+
+ else
+ startTagInBody(p, token);
+}
+
+function endTagInCell(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.TD || tn === $.TH) {
+ if (p.openElements.hasInTableScope(tn)) {
+ p.openElements.generateImpliedEndTags();
+ p.openElements.popUntilTagNamePopped(tn);
+ p.activeFormattingElements.clearToLastMarker();
+ p.insertionMode = IN_ROW_MODE;
+ }
+ }
+
+ else if (tn === $.TABLE || tn === $.TBODY || tn === $.TFOOT || tn === $.THEAD || tn === $.TR) {
+ if (p.openElements.hasInTableScope(tn)) {
+ p._closeTableCell();
+ p._processToken(token);
+ }
+ }
+
+ else if (tn !== $.BODY && tn !== $.CAPTION && tn !== $.COL && tn !== $.COLGROUP && tn !== $.HTML)
+ endTagInBody(p, token);
+}
+
+//12.2.5.4.16 The "in select" insertion mode
+//------------------------------------------------------------------
+function startTagInSelect(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.HTML)
+ startTagInBody(p, token);
+
+ else if (tn === $.OPTION) {
+ if (p.openElements.currentTagName === $.OPTION)
+ p.openElements.pop();
+
+ p._insertElement(token, NS.HTML);
+ }
+
+ else if (tn === $.OPTGROUP) {
+ if (p.openElements.currentTagName === $.OPTION)
+ p.openElements.pop();
+
+ if (p.openElements.currentTagName === $.OPTGROUP)
+ p.openElements.pop();
+
+ p._insertElement(token, NS.HTML);
+ }
+
+ else if (tn === $.INPUT || tn === $.KEYGEN || tn === $.TEXTAREA || tn === $.SELECT) {
+ if (p.openElements.hasInSelectScope($.SELECT)) {
+ p.openElements.popUntilTagNamePopped($.SELECT);
+ p._resetInsertionMode();
+
+ if (tn !== $.SELECT)
+ p._processToken(token);
+ }
+ }
+
+ else if (tn === $.SCRIPT || tn === $.TEMPLATE)
+ startTagInHead(p, token);
+}
+
+function endTagInSelect(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.OPTGROUP) {
+ var prevOpenElement = p.openElements.items[p.openElements.stackTop - 1],
+ prevOpenElementTn = prevOpenElement && p.treeAdapter.getTagName(prevOpenElement);
+
+ if (p.openElements.currentTagName === $.OPTION && prevOpenElementTn === $.OPTGROUP)
+ p.openElements.pop();
+
+ if (p.openElements.currentTagName === $.OPTGROUP)
+ p.openElements.pop();
+ }
+
+ else if (tn === $.OPTION) {
+ if (p.openElements.currentTagName === $.OPTION)
+ p.openElements.pop();
+ }
+
+ else if (tn === $.SELECT && p.openElements.hasInSelectScope($.SELECT)) {
+ p.openElements.popUntilTagNamePopped($.SELECT);
+ p._resetInsertionMode();
+ }
+
+ else if (tn === $.TEMPLATE)
+ endTagInHead(p, token);
+}
+
+//12.2.5.4.17 The "in select in table" insertion mode
+//------------------------------------------------------------------
+function startTagInSelectInTable(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.CAPTION || tn === $.TABLE || tn === $.TBODY || tn === $.TFOOT ||
+ tn === $.THEAD || tn === $.TR || tn === $.TD || tn === $.TH) {
+ p.openElements.popUntilTagNamePopped($.SELECT);
+ p._resetInsertionMode();
+ p._processToken(token);
+ }
+
+ else
+ startTagInSelect(p, token);
+}
+
+function endTagInSelectInTable(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.CAPTION || tn === $.TABLE || tn === $.TBODY || tn === $.TFOOT ||
+ tn === $.THEAD || tn === $.TR || tn === $.TD || tn === $.TH) {
+ if (p.openElements.hasInTableScope(tn)) {
+ p.openElements.popUntilTagNamePopped($.SELECT);
+ p._resetInsertionMode();
+ p._processToken(token);
+ }
+ }
+
+ else
+ endTagInSelect(p, token);
+}
+
+//12.2.5.4.18 The "in template" insertion mode
+//------------------------------------------------------------------
+function startTagInTemplate(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.BASE || tn === $.BASEFONT || tn === $.BGSOUND || tn === $.LINK || tn === $.META ||
+ tn === $.NOFRAMES || tn === $.SCRIPT || tn === $.STYLE || tn === $.TEMPLATE || tn === $.TITLE)
+ startTagInHead(p, token);
+
+ else {
+ var newInsertionMode = TEMPLATE_INSERTION_MODE_SWITCH_MAP[tn] || IN_BODY_MODE;
+
+ p._popTmplInsertionMode();
+ p._pushTmplInsertionMode(newInsertionMode);
+ p.insertionMode = newInsertionMode;
+ p._processToken(token);
+ }
+}
+
+function endTagInTemplate(p, token) {
+ if (token.tagName === $.TEMPLATE)
+ endTagInHead(p, token);
+}
+
+function eofInTemplate(p, token) {
+ if (p.openElements.tmplCount > 0) {
+ p.openElements.popUntilTagNamePopped($.TEMPLATE);
+ p.activeFormattingElements.clearToLastMarker();
+ p._popTmplInsertionMode();
+ p._resetInsertionMode();
+ p._processToken(token);
+ }
+
+ else
+ p.stopped = true;
+}
+
+
+//12.2.5.4.19 The "after body" insertion mode
+//------------------------------------------------------------------
+function startTagAfterBody(p, token) {
+ if (token.tagName === $.HTML)
+ startTagInBody(p, token);
+
+ else
+ tokenAfterBody(p, token);
+}
+
+function endTagAfterBody(p, token) {
+ if (token.tagName === $.HTML) {
+ if (!p.fragmentContext)
+ p.insertionMode = AFTER_AFTER_BODY_MODE;
+ }
+
+ else
+ tokenAfterBody(p, token);
+}
+
+function tokenAfterBody(p, token) {
+ p.insertionMode = IN_BODY_MODE;
+ p._processToken(token);
+}
+
+//12.2.5.4.20 The "in frameset" insertion mode
+//------------------------------------------------------------------
+function startTagInFrameset(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.HTML)
+ startTagInBody(p, token);
+
+ else if (tn === $.FRAMESET)
+ p._insertElement(token, NS.HTML);
+
+ else if (tn === $.FRAME)
+ p._appendElement(token, NS.HTML);
+
+ else if (tn === $.NOFRAMES)
+ startTagInHead(p, token);
+}
+
+function endTagInFrameset(p, token) {
+ if (token.tagName === $.FRAMESET && !p.openElements.isRootHtmlElementCurrent()) {
+ p.openElements.pop();
+
+ if (!p.fragmentContext && p.openElements.currentTagName !== $.FRAMESET)
+ p.insertionMode = AFTER_FRAMESET_MODE;
+ }
+}
+
+//12.2.5.4.21 The "after frameset" insertion mode
+//------------------------------------------------------------------
+function startTagAfterFrameset(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.HTML)
+ startTagInBody(p, token);
+
+ else if (tn === $.NOFRAMES)
+ startTagInHead(p, token);
+}
+
+function endTagAfterFrameset(p, token) {
+ if (token.tagName === $.HTML)
+ p.insertionMode = AFTER_AFTER_FRAMESET_MODE;
+}
+
+//12.2.5.4.22 The "after after body" insertion mode
+//------------------------------------------------------------------
+function startTagAfterAfterBody(p, token) {
+ if (token.tagName === $.HTML)
+ startTagInBody(p, token);
+
+ else
+ tokenAfterAfterBody(p, token);
+}
+
+function tokenAfterAfterBody(p, token) {
+ p.insertionMode = IN_BODY_MODE;
+ p._processToken(token);
+}
+
+//12.2.5.4.23 The "after after frameset" insertion mode
+//------------------------------------------------------------------
+function startTagAfterAfterFrameset(p, token) {
+ var tn = token.tagName;
+
+ if (tn === $.HTML)
+ startTagInBody(p, token);
+
+ else if (tn === $.NOFRAMES)
+ startTagInHead(p, token);
+}
+
+
+//12.2.5.5 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 startTagInForeignContent(p, token) {
+ if (foreignContent.causesExit(token) && !p.fragmentContext) {
+ while (p.treeAdapter.getNamespaceURI(p.openElements.current) !== NS.HTML && !p._isIntegrationPoint(p.openElements.current))
+ p.openElements.pop();
+
+ p._processToken(token);
+ }
+
+ else {
+ var current = p._getAdjustedCurrentElement(),
+ currentNs = p.treeAdapter.getNamespaceURI(current);
+
+ if (currentNs === NS.MATHML)
+ foreignContent.adjustTokenMathMLAttrs(token);
+
+ else if (currentNs === NS.SVG) {
+ foreignContent.adjustTokenSVGTagName(token);
+ foreignContent.adjustTokenSVGAttrs(token);
+ }
+
+ foreignContent.adjustTokenXMLAttrs(token);
+
+ if (token.selfClosing)
+ p._appendElement(token, currentNs);
+ else
+ p._insertElement(token, currentNs);
+ }
+}
+
+function endTagInForeignContent(p, token) {
+ for (var i = p.openElements.stackTop; i > 0; i--) {
+ var element = p.openElements.items[i];
+
+ if (p.treeAdapter.getNamespaceURI(element) === NS.HTML) {
+ p._processToken(token);
+ break;
+ }
+
+ if (p.treeAdapter.getTagName(element).toLowerCase() === token.tagName) {
+ p.openElements.popUntilElementPopped(element);
+ break;
+ }
+ }
+}