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