12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819 |
- '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;
- }
- }
- }
|