Index: node_modules/vulcanize/node_modules/whacko/node_modules/parse5/lib/tree_construction/parser.js |
diff --git a/node_modules/vulcanize/node_modules/whacko/node_modules/parse5/lib/tree_construction/parser.js b/node_modules/vulcanize/node_modules/whacko/node_modules/parse5/lib/tree_construction/parser.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..42cf8e15084735d689ea8e63c0c726280f5119d9 |
--- /dev/null |
+++ b/node_modules/vulcanize/node_modules/whacko/node_modules/parse5/lib/tree_construction/parser.js |
@@ -0,0 +1,2810 @@ |
+'use strict'; |
+ |
+var Tokenizer = require('../tokenization/tokenizer'), |
+ OpenElementStack = require('./open_element_stack'), |
+ FormattingElementList = require('./formatting_element_list'), |
+ Doctype = require('./doctype'), |
+ DefaultTreeAdapter = require('../tree_adapters/default'), |
+ ForeignContent = require('../common/foreign_content'), |
+ UNICODE = require('../common/unicode'), |
+ HTML = require('../common/html'); |
+ |
+//Aliases |
+var $ = HTML.TAG_NAMES, |
+ NS = HTML.NAMESPACES, |
+ ATTRS = HTML.ATTRS; |
+ |
+//Misc constants |
+var SEARCHABLE_INDEX_DEFAULT_PROMPT = 'This is a searchable index. Enter search keywords: ', |
+ SEARCHABLE_INDEX_INPUT_NAME = 'isindex', |
+ 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 = {}; |
+ |
+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 = {}; |
+ |
+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 _ = {}; |
+ |
+_[INITIAL_MODE] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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] = {}; |
+_[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; |
+ |
+//Searchable index building utils (<isindex> tag) |
+function getSearchableIndexFormAttrs(isindexStartTagToken) { |
+ var indexAction = Tokenizer.getTokenAttr(isindexStartTagToken, ATTRS.ACTION), |
+ attrs = []; |
+ |
+ if (indexAction !== null) { |
+ attrs.push({ |
+ name: ATTRS.ACTION, |
+ value: indexAction |
+ }); |
+ } |
+ |
+ return attrs; |
+} |
+ |
+function getSearchableIndexLabelText(isindexStartTagToken) { |
+ var indexPrompt = Tokenizer.getTokenAttr(isindexStartTagToken, ATTRS.PROMPT); |
+ |
+ return indexPrompt === null ? SEARCHABLE_INDEX_DEFAULT_PROMPT : indexPrompt; |
+} |
+ |
+function getSearchableIndexInputAttrs(isindexStartTagToken) { |
+ var isindexAttrs = isindexStartTagToken.attrs, |
+ inputAttrs = []; |
+ |
+ for (var i = 0; i < isindexAttrs.length; i++) { |
+ var name = isindexAttrs[i].name; |
+ |
+ if (name !== ATTRS.NAME && name !== ATTRS.ACTION && name !== ATTRS.PROMPT) |
+ inputAttrs.push(isindexAttrs[i]); |
+ } |
+ |
+ inputAttrs.push({ |
+ name: ATTRS.NAME, |
+ value: SEARCHABLE_INDEX_INPUT_NAME |
+ }); |
+ |
+ return inputAttrs; |
+} |
+ |
+//Parser |
+var Parser = module.exports = function (treeAdapter) { |
+ this.treeAdapter = treeAdapter || DefaultTreeAdapter; |
+ this.scriptHandler = null; |
+}; |
+ |
+//API |
+Parser.prototype.parse = function (html) { |
+ var document = this.treeAdapter.createDocument(); |
+ |
+ this._reset(html, document, null); |
+ this._runParsingLoop(); |
+ |
+ 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._reset(html, documentMock, fragmentContext); |
+ |
+ if (this.treeAdapter.getTagName(fragmentContext) === $.TEMPLATE) |
+ this._pushTmplInsertionMode(IN_TEMPLATE_MODE); |
+ |
+ this._initTokenizerForFragmentParsing(); |
+ this._insertFakeRootElement(); |
+ this._resetInsertionMode(); |
+ this._findFormInFragmentContext(); |
+ this._runParsingLoop(); |
+ |
+ var rootElement = this.treeAdapter.getFirstChild(documentMock), |
+ fragment = this.treeAdapter.createDocumentFragment(); |
+ |
+ this._adoptNodes(rootElement, fragment); |
+ |
+ return fragment; |
+}; |
+ |
+//Reset state |
+Parser.prototype._reset = function (html, document, fragmentContext) { |
+ this.tokenizer = new Tokenizer(html); |
+ |
+ 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._iterateParsingLoop = function () { |
+ this._setupTokenizerCDATAMode(); |
+ |
+ var token = this.tokenizer.getNextToken(); |
+ |
+ if (this.skipNextNewLine) { |
+ this.skipNextNewLine = false; |
+ |
+ if (token.type === Tokenizer.WHITESPACE_CHARACTER_TOKEN && token.chars[0] === '\n') { |
+ if (token.chars.length === 1) |
+ return; |
+ |
+ token.chars = token.chars.substr(1); |
+ } |
+ } |
+ |
+ if (this._shouldProcessTokenInForeignContent(token)) |
+ this._processTokenInForeignContent(token); |
+ |
+ else |
+ this._processToken(token); |
+}; |
+ |
+Parser.prototype._runParsingLoop = function () { |
+ while (!this.stopped) |
+ this._iterateParsingLoop(); |
+}; |
+ |
+//Text parsing |
+Parser.prototype._setupTokenizerCDATAMode = function () { |
+ var current = this._getAdjustedCurrentElement(); |
+ |
+ this.tokenizer.allowCDATA = current && current !== this.document && |
+ this.treeAdapter.getNamespaceURI(current) !== NS.HTML && |
+ (!this._isHtmlIntegrationPoint(current)) && |
+ (!this._isMathMLTextIntegrationPoint(current)); |
+}; |
+ |
+Parser.prototype._switchToTextParsing = function (currentToken, nextTokenizerState) { |
+ this._insertElement(currentToken, NS.HTML); |
+ this.tokenizer.state = nextTokenizerState; |
+ this.originalInsertionMode = this.insertionMode; |
+ this.insertionMode = TEXT_MODE; |
+}; |
+ |
+//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 () { |
+ var tn = this.treeAdapter.getTagName(this.fragmentContext); |
+ |
+ if (tn === $.TITLE || tn === $.TEXTAREA) |
+ this.tokenizer.state = Tokenizer.RCDATA_STATE; |
+ |
+ else if (tn === $.STYLE || tn === $.XMP || tn === $.IFRAME || |
+ tn === $.NOEMBED || tn === $.NOFRAMES || tn === $.NOSCRIPT) { |
+ this.tokenizer.state = Tokenizer.RAWTEXT_STATE; |
+ } |
+ |
+ else if (tn === $.SCRIPT) |
+ this.tokenizer.state = Tokenizer.SCRIPT_DATA_STATE; |
+ |
+ else if (tn === $.PLAINTEXT) |
+ this.tokenizer.state = Tokenizer.PLAINTEXT_STATE; |
+}; |
+ |
+//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.fosterParentingEnabled && this._isElementCausesFosterParenting(this.openElements.current)) |
+ 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._insertTemplate = function (token) { |
+ var tmpl = this.treeAdapter.createElement(token.tagName, NS.HTML, token.attrs), |
+ content = this.treeAdapter.createDocumentFragment(); |
+ |
+ this.treeAdapter.appendChild(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.fosterParentingEnabled && this._isElementCausesFosterParenting(this.openElements.current)) |
+ 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._isMathMLTextIntegrationPoint(current)) |
+ return false; |
+ |
+ if ((token.type === Tokenizer.START_TAG_TOKEN || isCharacterToken) && this._isHtmlIntegrationPoint(current)) |
+ 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._processFakeStartTagWithAttrs = function (tagName, attrs) { |
+ var fakeToken = this.tokenizer.buildStartTagToken(tagName); |
+ |
+ fakeToken.attrs = attrs; |
+ this._processToken(fakeToken); |
+}; |
+ |
+Parser.prototype._processFakeStartTag = function (tagName) { |
+ var fakeToken = this.tokenizer.buildStartTagToken(tagName); |
+ |
+ this._processToken(fakeToken); |
+ return fakeToken; |
+}; |
+ |
+Parser.prototype._processFakeEndTag = function (tagName) { |
+ var fakeToken = this.tokenizer.buildEndTagToken(tagName); |
+ |
+ this._processToken(fakeToken); |
+ return fakeToken; |
+}; |
+ |
+//Integration points |
+Parser.prototype._isMathMLTextIntegrationPoint = function (element) { |
+ var tn = this.treeAdapter.getTagName(element), |
+ ns = this.treeAdapter.getNamespaceURI(element); |
+ |
+ return ForeignContent.isMathMLTextIntegrationPoint(tn, ns); |
+}; |
+ |
+Parser.prototype._isHtmlIntegrationPoint = function (element) { |
+ var tn = this.treeAdapter.getTagName(element), |
+ ns = this.treeAdapter.getNamespaceURI(element), |
+ attrs = this.treeAdapter.getAttrList(element); |
+ |
+ return ForeignContent.isHtmlIntegrationPoint(tn, ns, attrs); |
+}; |
+ |
+//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 () { |
+ if (this.openElements.hasInTableScope($.TD)) |
+ this._processFakeEndTag($.TD); |
+ |
+ else |
+ this._processFakeEndTag($.TH); |
+}; |
+ |
+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._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.getChildNodes(openElement)[0]; |
+ 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 element = null, |
+ lastElement = furthestBlock, |
+ nextElement = p.openElements.getCommonAncestor(furthestBlock); |
+ |
+ for (var i = 0; i < AA_INNER_LOOP_ITER; 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); |
+ |
+ if (!elementEntry) { |
+ p.openElements.remove(element); |
+ continue; |
+ } |
+ |
+ if (element === formattingElement) |
+ break; |
+ |
+ 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.getChildNodes(commonAncestor)[0]; |
+ |
+ 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) { |
+ for (var i = 0; i < AA_OUTER_LOOP_ITER; i++) { |
+ var 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(p, token) { |
+ //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, token) { |
+ p.stopped = true; |
+} |
+ |
+//12.2.5.4.1 The "initial" insertion mode |
+//------------------------------------------------------------------ |
+function doctypeInInitialMode(p, token) { |
+ p._setDocumentType(token); |
+ |
+ if (token.forceQuirks || Doctype.isQuirks(token.name, token.publicId, token.systemId)) |
+ p.treeAdapter.setQuirksMode(p.document); |
+ |
+ p.insertionMode = BEFORE_HTML_MODE; |
+} |
+ |
+function tokenInInitialMode(p, token) { |
+ p.treeAdapter.setQuirksMode(p.document); |
+ 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._processFakeStartTag($.HEAD); |
+ 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 === $.COMMAND || tn === $.LINK || tn === $.META) { |
+ p._appendElement(token, NS.HTML); |
+ } |
+ |
+ else if (tn === $.TITLE) |
+ p._switchToTextParsing(token, Tokenizer.RCDATA_STATE); |
+ |
+ //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.RAWTEXT_STATE); |
+ |
+ else if (tn === $.SCRIPT) { |
+ p._insertElement(token, NS.HTML); |
+ p.tokenizer.state = Tokenizer.SCRIPT_DATA_STATE; |
+ p.originalInsertionMode = p.insertionMode; |
+ p.insertionMode = TEXT_MODE; |
+ } |
+ |
+ 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.popUntilTemplatePopped(); |
+ p.activeFormattingElements.clearToLastMarker(); |
+ p._popTmplInsertionMode(); |
+ p._resetInsertionMode(); |
+ } |
+} |
+ |
+function tokenInHead(p, token) { |
+ p._processFakeEndTag($.HEAD); |
+ 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._processFakeStartTag($.BODY); |
+ p.framesetOk = true; |
+ 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; |
+ |
+ for (var i = p.openElements.stackTop; i >= 0; i--) { |
+ var element = p.openElements.items[i], |
+ tn = p.treeAdapter.getTagName(element); |
+ |
+ if ((token.tagName === $.LI && tn === $.LI) || |
+ ((token.tagName === $.DD || token.tagName === $.DT) && (tn === $.DD || tn == $.DT))) { |
+ p._processFakeEndTag(tn); |
+ break; |
+ } |
+ |
+ if (tn !== $.ADDRESS && tn !== $.DIV && tn !== $.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.PLAINTEXT_STATE; |
+} |
+ |
+function buttonStartTagInBody(p, token) { |
+ if (p.openElements.hasInScope($.BUTTON)) { |
+ p._processFakeEndTag($.BUTTON); |
+ buttonStartTagInBody(p, token); |
+ } |
+ |
+ else { |
+ p._reconstructActiveFormattingElements(); |
+ p._insertElement(token, NS.HTML); |
+ p.framesetOk = false; |
+ } |
+} |
+ |
+function aStartTagInBody(p, token) { |
+ var activeElementEntry = p.activeFormattingElements.getElementEntryInScopeWithTagName($.A); |
+ |
+ if (activeElementEntry) { |
+ p._processFakeEndTag($.A); |
+ 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)) { |
+ p._processFakeEndTag($.NOBR); |
+ 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.isQuirksMode(p.document) && 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(); |
+ |
+ p._appendElement(token, NS.HTML); |
+ p.framesetOk = false; |
+} |
+ |
+function imageStartTagInBody(p, token) { |
+ token.tagName = $.IMG; |
+ areaStartTagInBody(p, token); |
+} |
+ |
+function isindexStartTagInBody(p, token) { |
+ if (!p.formElement || p.openElements.tmplCount > 0) { |
+ p._processFakeStartTagWithAttrs($.FORM, getSearchableIndexFormAttrs(token)); |
+ p._processFakeStartTag($.HR); |
+ p._processFakeStartTag($.LABEL); |
+ p.treeAdapter.insertText(p.openElements.current, getSearchableIndexLabelText(token)); |
+ p._processFakeStartTagWithAttrs($.INPUT, getSearchableIndexInputAttrs(token)); |
+ p._processFakeEndTag($.LABEL); |
+ p._processFakeStartTag($.HR); |
+ p._processFakeEndTag($.FORM); |
+ } |
+} |
+ |
+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.RCDATA_STATE; |
+ 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.RAWTEXT_STATE); |
+} |
+ |
+function iframeStartTagInBody(p, token) { |
+ p.framesetOk = false; |
+ p._switchToTextParsing(token, Tokenizer.RAWTEXT_STATE); |
+} |
+ |
+//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.RAWTEXT_STATE); |
+} |
+ |
+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._processFakeEndTag($.OPTION); |
+ |
+ p._reconstructActiveFormattingElements(); |
+ p._insertElement(token, NS.HTML); |
+} |
+ |
+function rpStartTagInBody(p, token) { |
+ if (p.openElements.hasInScope($.RUBY)) |
+ p.openElements.generateImpliedEndTags(); |
+ |
+ p._insertElement(token, NS.HTML); |
+} |
+ |
+function menuitemStartTagInBody(p, token) { |
+ p._appendElement(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 === $.RP || tn === $.RT) |
+ rpStartTagInBody(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 !== $.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 || tn === $.MENU) |
+ 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 !== $.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 || tn === $.COMMAND) |
+ 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 === $.ISINDEX) |
+ isindexStartTagInBody(p, token); |
+ |
+ else if (tn === $.NOEMBED) |
+ noembedStartTagInBody(p, token); |
+ |
+ else if (tn !== $.CAPTION) |
+ genericStartTagInBody(p, token); |
+ |
+ break; |
+ |
+ case 8: |
+ if (tn === $.BASEFONT || 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, token) { |
+ if (p.openElements.hasInScope($.BODY)) |
+ p.insertionMode = AFTER_BODY_MODE; |
+ |
+ else |
+ token.ignored = true; |
+} |
+ |
+function htmlEndTagInBody(p, token) { |
+ var fakeToken = p._processFakeEndTag($.BODY); |
+ |
+ if (!fakeToken.ignored) |
+ 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, token) { |
+ var inTemplate = p.openElements.tmplCount > 0, |
+ formElement = p.formElement; |
+ |
+ if (!inTemplate) |
+ p.formElement = null; |
+ |
+ if ((formElement || inTemplate) && p.openElements.hasInScope($.FORM)) { |
+ p.openElements.generateImpliedEndTags(); |
+ p.openElements.remove(formElement); |
+ } |
+} |
+ |
+function pEndTagInBody(p, token) { |
+ if (p.openElements.hasInButtonScope($.P)) { |
+ p.openElements.generateImpliedEndTagsWithExclusion($.P); |
+ p.openElements.popUntilTagNamePopped($.P); |
+ } |
+ |
+ else { |
+ p._processFakeStartTag($.P); |
+ p._processToken(token); |
+ } |
+} |
+ |
+function liEndTagInBody(p, token) { |
+ 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, token) { |
+ 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, token) { |
+ p._processFakeStartTag($.BR); |
+} |
+ |
+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 (!p.fragmentContext && p.scriptHandler && token.tagName === $.SCRIPT) |
+ p.scriptHandler(p.document, 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._processFakeStartTag($.COLGROUP); |
+ 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._processFakeStartTag($.TBODY); |
+ p._processToken(token); |
+} |
+ |
+function tableStartTagInTable(p, token) { |
+ var fakeToken = p._processFakeEndTag($.TABLE); |
+ |
+ //NOTE: The fake end tag token here can only be ignored in the fragment case. |
+ if (!fakeToken.ignored) |
+ 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 |
+ token.ignored = true; |
+ } |
+ |
+ 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) { |
+ if (p.hasNonWhitespacePendingCharacterToken) { |
+ for (var i = 0; i < p.pendingCharacterTokens.length; i++) |
+ tokenInTable(p, p.pendingCharacterTokens[i]); |
+ } |
+ |
+ else { |
+ for (var i = 0; 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) { |
+ var fakeToken = p._processFakeEndTag($.CAPTION); |
+ |
+ //NOTE: The fake end tag token here can only be ignored in the fragment case. |
+ if (!fakeToken.ignored) |
+ p._processToken(token); |
+ } |
+ |
+ else |
+ startTagInBody(p, token); |
+} |
+ |
+function endTagInCaption(p, token) { |
+ var tn = token.tagName; |
+ |
+ if (tn === $.CAPTION) { |
+ if (p.openElements.hasInTableScope($.CAPTION)) { |
+ p.openElements.generateImpliedEndTags(); |
+ p.openElements.popUntilTagNamePopped($.CAPTION); |
+ p.activeFormattingElements.clearToLastMarker(); |
+ p.insertionMode = IN_TABLE_MODE; |
+ } |
+ |
+ else |
+ token.ignored = true; |
+ } |
+ |
+ else if (tn === $.TABLE) { |
+ var fakeToken = p._processFakeEndTag($.CAPTION); |
+ |
+ //NOTE: The fake end tag token here can only be ignored in the fragment case. |
+ if (!fakeToken.ignored) |
+ 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) |
+ token.ignored = true; |
+ |
+ else { |
+ 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) { |
+ var fakeToken = p._processFakeEndTag($.COLGROUP); |
+ |
+ //NOTE: The fake end tag token here can only be ignored in the fragment case. |
+ if (!fakeToken.ignored) |
+ 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._processFakeStartTag($.TR); |
+ 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._processFakeEndTag(p.openElements.currentTagName); |
+ 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._processFakeEndTag(p.openElements.currentTagName); |
+ 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) { |
+ var fakeToken = p._processFakeEndTag($.TR); |
+ |
+ //NOTE: The fake end tag token here can only be ignored in the fragment case. |
+ if (!fakeToken.ignored) |
+ 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 |
+ token.ignored = true; |
+ } |
+ |
+ else if (tn === $.TABLE) { |
+ var fakeToken = p._processFakeEndTag($.TR); |
+ |
+ //NOTE: The fake end tag token here can only be ignored in the fragment case. |
+ if (!fakeToken.ignored) |
+ p._processToken(token); |
+ } |
+ |
+ else if (tn === $.TBODY || tn === $.TFOOT || tn === $.THEAD) { |
+ if (p.openElements.hasInTableScope(tn)) { |
+ p._processFakeEndTag($.TR); |
+ 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._processFakeEndTag($.OPTION); |
+ |
+ p._insertElement(token, NS.HTML); |
+ } |
+ |
+ else if (tn === $.OPTGROUP) { |
+ if (p.openElements.currentTagName === $.OPTION) |
+ p._processFakeEndTag($.OPTION); |
+ |
+ if (p.openElements.currentTagName === $.OPTGROUP) |
+ p._processFakeEndTag($.OPTGROUP); |
+ |
+ p._insertElement(token, NS.HTML); |
+ } |
+ |
+ else if (tn === $.SELECT) |
+ p._processFakeEndTag($.SELECT); |
+ |
+ else if (tn === $.INPUT || tn === $.KEYGEN || tn === $.TEXTAREA) { |
+ if (p.openElements.hasInSelectScope($.SELECT)) { |
+ p._processFakeEndTag($.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._processFakeEndTag($.OPTION); |
+ |
+ 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._processFakeEndTag($.SELECT); |
+ 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._processFakeEndTag($.SELECT); |
+ 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.popUntilTemplatePopped(); |
+ 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._isMathMLTextIntegrationPoint(p.openElements.current)) && |
+ (!p._isHtmlIntegrationPoint(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; |
+ } |
+ } |
+} |