123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135 |
- 'use strict';
- var conventions = require('./conventions');
- var find = conventions.find;
- var hasDefaultHTMLNamespace = conventions.hasDefaultHTMLNamespace;
- var hasOwn = conventions.hasOwn;
- var isHTMLMimeType = conventions.isHTMLMimeType;
- var isHTMLRawTextElement = conventions.isHTMLRawTextElement;
- var isHTMLVoidElement = conventions.isHTMLVoidElement;
- var MIME_TYPE = conventions.MIME_TYPE;
- var NAMESPACE = conventions.NAMESPACE;
- /**
- * Private DOM Constructor symbol
- *
- * Internal symbol used for construction of all classes whose constructors should be private.
- * Currently used for checks in `Node`, `Document`, `Element`, `Attr`, `CharacterData`, `Text`, `Comment`,
- * `CDATASection`, `DocumentType`, `Notation`, `Entity`, `EntityReference`, `DocumentFragment`, `ProcessingInstruction`
- * so the constructor can't be used from outside the module.
- */
- var PDC = Symbol();
- var errors = require('./errors');
- var DOMException = errors.DOMException;
- var DOMExceptionName = errors.DOMExceptionName;
- var g = require('./grammar');
- /**
- * Checks if the given symbol equals the Private DOM Constructor symbol (PDC)
- * and throws an Illegal constructor exception when the symbols don't match.
- * This ensures that the constructor remains private and can't be used outside this module.
- */
- function checkSymbol(symbol) {
- if (symbol !== PDC) {
- throw new TypeError('Illegal constructor');
- }
- }
- /**
- * A prerequisite for `[].filter`, to drop elements that are empty.
- *
- * @param {string} input
- * The string to be checked.
- * @returns {boolean}
- * Returns `true` if the input string is not empty, `false` otherwise.
- */
- function notEmptyString(input) {
- return input !== '';
- }
- /**
- * Splits a string on ASCII whitespace characters (U+0009 TAB, U+000A LF, U+000C FF, U+000D CR,
- * U+0020 SPACE).
- * It follows the definition from the infra specification from WHATWG.
- *
- * @param {string} input
- * The string to be split.
- * @returns {string[]}
- * An array of the split strings. The array can be empty if the input string is empty or only
- * contains whitespace characters.
- * @see {@link https://infra.spec.whatwg.org/#split-on-ascii-whitespace}
- * @see {@link https://infra.spec.whatwg.org/#ascii-whitespace}
- */
- function splitOnASCIIWhitespace(input) {
- // U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, U+0020 SPACE
- return input ? input.split(/[\t\n\f\r ]+/).filter(notEmptyString) : [];
- }
- /**
- * Adds element as a key to current if it is not already present.
- *
- * @param {Record<string, boolean | undefined>} current
- * The current record object to which the element will be added as a key.
- * The object's keys are string types and values are either boolean or undefined.
- * @param {string} element
- * The string to be added as a key to the current record.
- * @returns {Record<string, boolean | undefined>}
- * The updated record object after the addition of the new element.
- */
- function orderedSetReducer(current, element) {
- if (!hasOwn(current, element)) {
- current[element] = true;
- }
- return current;
- }
- /**
- * Converts a string into an ordered set by splitting the input on ASCII whitespace and
- * ensuring uniqueness of elements.
- * This follows the definition of an ordered set from the infra specification by WHATWG.
- *
- * @param {string} input
- * The input string to be transformed into an ordered set.
- * @returns {string[]}
- * An array of unique strings obtained from the input, preserving the original order.
- * The array can be empty if the input string is empty or only contains whitespace characters.
- * @see {@link https://infra.spec.whatwg.org/#ordered-set}
- */
- function toOrderedSet(input) {
- if (!input) return [];
- var list = splitOnASCIIWhitespace(input);
- return Object.keys(list.reduce(orderedSetReducer, {}));
- }
- /**
- * Uses `list.indexOf` to implement a function that behaves like `Array.prototype.includes`.
- * This function is used in environments where `Array.prototype.includes` may not be available.
- *
- * @param {any[]} list
- * The array in which to search for the element.
- * @returns {function(any): boolean}
- * A function that accepts an element and returns a boolean indicating whether the element is
- * included in the provided list.
- */
- function arrayIncludes(list) {
- return function (element) {
- return list && list.indexOf(element) !== -1;
- };
- }
- /**
- * Validates a qualified name based on the criteria provided in the DOM specification by
- * WHATWG.
- *
- * @param {string} qualifiedName
- * The qualified name to be validated.
- * @throws {DOMException}
- * With code {@link DOMException.INVALID_CHARACTER_ERR} if the qualified name contains an
- * invalid character.
- * @see {@link https://dom.spec.whatwg.org/#validate}
- */
- function validateQualifiedName(qualifiedName) {
- if (!g.QName_exact.test(qualifiedName)) {
- throw new DOMException(DOMException.INVALID_CHARACTER_ERR, 'invalid character in qualified name "' + qualifiedName + '"');
- }
- }
- /**
- * Validates a qualified name and the namespace associated with it,
- * based on the criteria provided in the DOM specification by WHATWG.
- *
- * @param {string | null} namespace
- * The namespace to be validated. It can be a string or null.
- * @param {string} qualifiedName
- * The qualified name to be validated.
- * @returns {[namespace: string | null, prefix: string | null, localName: string]}
- * Returns a tuple with the namespace,
- * prefix and local name of the qualified name.
- * @throws {DOMException}
- * Throws a DOMException if the qualified name or the namespace is not valid.
- * @see {@link https://dom.spec.whatwg.org/#validate-and-extract}
- */
- function validateAndExtract(namespace, qualifiedName) {
- validateQualifiedName(qualifiedName);
- namespace = namespace || null;
- /**
- * @type {string | null}
- */
- var prefix = null;
- var localName = qualifiedName;
- if (qualifiedName.indexOf(':') >= 0) {
- var splitResult = qualifiedName.split(':');
- prefix = splitResult[0];
- localName = splitResult[1];
- }
- if (prefix !== null && namespace === null) {
- throw new DOMException(DOMException.NAMESPACE_ERR, 'prefix is non-null and namespace is null');
- }
- if (prefix === 'xml' && namespace !== conventions.NAMESPACE.XML) {
- throw new DOMException(DOMException.NAMESPACE_ERR, 'prefix is "xml" and namespace is not the XML namespace');
- }
- if ((prefix === 'xmlns' || qualifiedName === 'xmlns') && namespace !== conventions.NAMESPACE.XMLNS) {
- throw new DOMException(
- DOMException.NAMESPACE_ERR,
- 'either qualifiedName or prefix is "xmlns" and namespace is not the XMLNS namespace'
- );
- }
- if (namespace === conventions.NAMESPACE.XMLNS && prefix !== 'xmlns' && qualifiedName !== 'xmlns') {
- throw new DOMException(
- DOMException.NAMESPACE_ERR,
- 'namespace is the XMLNS namespace and neither qualifiedName nor prefix is "xmlns"'
- );
- }
- return [namespace, prefix, localName];
- }
- /**
- * Copies properties from one object to another.
- * It only copies the object's own (not inherited) properties.
- *
- * @param {Object} src
- * The source object from which properties are copied.
- * @param {Object} dest
- * The destination object to which properties are copied.
- */
- function copy(src, dest) {
- for (var p in src) {
- if (hasOwn(src, p)) {
- dest[p] = src[p];
- }
- }
- }
- /**
- * Extends a class with the properties and methods of a super class.
- * It uses a form of prototypal inheritance, and establishes the `constructor` property
- * correctly(?).
- *
- * It is not clear to the current maintainers if this implementation is making sense,
- * since it creates an intermediate prototype function,
- * which all properties of `Super` are copied onto using `_copy`.
- *
- * @param {Object} Class
- * The class that is to be extended.
- * @param {Object} Super
- * The super class from which properties and methods are inherited.
- * @private
- */
- function _extends(Class, Super) {
- var pt = Class.prototype;
- if (!(pt instanceof Super)) {
- function t() {}
- t.prototype = Super.prototype;
- t = new t();
- copy(pt, t);
- Class.prototype = pt = t;
- }
- if (pt.constructor != Class) {
- if (typeof Class != 'function') {
- console.error('unknown Class:' + Class);
- }
- pt.constructor = Class;
- }
- }
- var NodeType = {};
- var ELEMENT_NODE = (NodeType.ELEMENT_NODE = 1);
- var ATTRIBUTE_NODE = (NodeType.ATTRIBUTE_NODE = 2);
- var TEXT_NODE = (NodeType.TEXT_NODE = 3);
- var CDATA_SECTION_NODE = (NodeType.CDATA_SECTION_NODE = 4);
- var ENTITY_REFERENCE_NODE = (NodeType.ENTITY_REFERENCE_NODE = 5);
- var ENTITY_NODE = (NodeType.ENTITY_NODE = 6);
- var PROCESSING_INSTRUCTION_NODE = (NodeType.PROCESSING_INSTRUCTION_NODE = 7);
- var COMMENT_NODE = (NodeType.COMMENT_NODE = 8);
- var DOCUMENT_NODE = (NodeType.DOCUMENT_NODE = 9);
- var DOCUMENT_TYPE_NODE = (NodeType.DOCUMENT_TYPE_NODE = 10);
- var DOCUMENT_FRAGMENT_NODE = (NodeType.DOCUMENT_FRAGMENT_NODE = 11);
- var NOTATION_NODE = (NodeType.NOTATION_NODE = 12);
- var DocumentPosition = conventions.freeze({
- DOCUMENT_POSITION_DISCONNECTED: 1,
- DOCUMENT_POSITION_PRECEDING: 2,
- DOCUMENT_POSITION_FOLLOWING: 4,
- DOCUMENT_POSITION_CONTAINS: 8,
- DOCUMENT_POSITION_CONTAINED_BY: 16,
- DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: 32,
- });
- //helper functions for compareDocumentPosition
- /**
- * Finds the common ancestor in two parent chains.
- *
- * @param {Node[]} a
- * The first parent chain.
- * @param {Node[]} b
- * The second parent chain.
- * @returns {Node}
- * The common ancestor node if it exists. If there is no common ancestor, the function will
- * return `null`.
- */
- function commonAncestor(a, b) {
- if (b.length < a.length) return commonAncestor(b, a);
- var c = null;
- for (var n in a) {
- if (a[n] !== b[n]) return c;
- c = a[n];
- }
- return c;
- }
- /**
- * Assigns a unique identifier to a document to ensure consistency while comparing unrelated
- * nodes.
- *
- * @param {Document} doc
- * The document to which a unique identifier is to be assigned.
- * @returns {string}
- * The unique identifier of the document. If the document already had a unique identifier, the
- * function will return the existing one.
- */
- function docGUID(doc) {
- if (!doc.guid) doc.guid = Math.random();
- return doc.guid;
- }
- //-- end of helper functions
- /**
- * The NodeList interface provides the abstraction of an ordered collection of nodes,
- * without defining or constraining how this collection is implemented.
- * NodeList objects in the DOM are live.
- * The items in the NodeList are accessible via an integral index, starting from 0.
- * You can also access the items of the NodeList with a `for...of` loop.
- *
- * @class NodeList
- * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
- * @constructs NodeList
- */
- function NodeList() {}
- NodeList.prototype = {
- /**
- * The number of nodes in the list. The range of valid child node indices is 0 to length-1
- * inclusive.
- *
- * @type {number}
- */
- length: 0,
- /**
- * Returns the item at `index`. If index is greater than or equal to the number of nodes in
- * the list, this returns null.
- *
- * @param index
- * Unsigned long Index into the collection.
- * @returns {Node | null}
- * The node at position `index` in the NodeList,
- * or null if that is not a valid index.
- */
- item: function (index) {
- return index >= 0 && index < this.length ? this[index] : null;
- },
- /**
- * Returns a string representation of the NodeList.
- *
- * @param {unknown} nodeFilter
- * __A filter function? Not implemented according to the spec?__.
- * @returns {string}
- * A string representation of the NodeList.
- */
- toString: function (nodeFilter) {
- for (var buf = [], i = 0; i < this.length; i++) {
- serializeToString(this[i], buf, nodeFilter);
- }
- return buf.join('');
- },
- /**
- * Filters the NodeList based on a predicate.
- *
- * @param {function(Node): boolean} predicate
- * - A predicate function to filter the NodeList.
- * @returns {Node[]}
- * An array of nodes that satisfy the predicate.
- * @private
- */
- filter: function (predicate) {
- return Array.prototype.filter.call(this, predicate);
- },
- /**
- * Returns the first index at which a given node can be found in the NodeList, or -1 if it is
- * not present.
- *
- * @param {Node} item
- * - The Node item to locate in the NodeList.
- * @returns {number}
- * The first index of the node in the NodeList; -1 if not found.
- * @private
- */
- indexOf: function (item) {
- return Array.prototype.indexOf.call(this, item);
- },
- };
- NodeList.prototype[Symbol.iterator] = function () {
- var me = this;
- var index = 0;
- return {
- next: function () {
- if (index < me.length) {
- return {
- value: me[index++],
- done: false,
- };
- } else {
- return {
- done: true,
- };
- }
- },
- return: function () {
- return {
- done: true,
- };
- },
- };
- };
- /**
- * Represents a live collection of nodes that is automatically updated when its associated
- * document changes.
- *
- * @class LiveNodeList
- * @param {Node} node
- * The associated node.
- * @param {function} refresh
- * The function to refresh the live node list.
- * @augments NodeList
- * @constructs LiveNodeList
- */
- function LiveNodeList(node, refresh) {
- this._node = node;
- this._refresh = refresh;
- _updateLiveList(this);
- }
- /**
- * Updates the live node list.
- *
- * @param {LiveNodeList} list
- * The live node list to update.
- * @private
- */
- function _updateLiveList(list) {
- var inc = list._node._inc || list._node.ownerDocument._inc;
- if (list._inc !== inc) {
- var ls = list._refresh(list._node);
- __set__(list, 'length', ls.length);
- if (!list.$$length || ls.length < list.$$length) {
- for (var i = ls.length; i in list; i++) {
- if (hasOwn(list, i)) {
- delete list[i];
- }
- }
- }
- copy(ls, list);
- list._inc = inc;
- }
- }
- /**
- * Returns the node at position `index` in the LiveNodeList, or null if that is not a valid
- * index.
- *
- * @param {number} i
- * Index into the collection.
- * @returns {Node | null}
- * The node at position `index` in the LiveNodeList, or null if that is not a valid index.
- */
- LiveNodeList.prototype.item = function (i) {
- _updateLiveList(this);
- return this[i] || null;
- };
- _extends(LiveNodeList, NodeList);
- /**
- * Objects implementing the NamedNodeMap interface are used to represent collections of nodes
- * that can be accessed by name.
- * Note that NamedNodeMap does not inherit from NodeList;
- * NamedNodeMaps are not maintained in any particular order.
- * Objects contained in an object implementing NamedNodeMap may also be accessed by an ordinal
- * index,
- * but this is simply to allow convenient enumeration of the contents of a NamedNodeMap,
- * and does not imply that the DOM specifies an order to these Nodes.
- * NamedNodeMap objects in the DOM are live.
- * used for attributes or DocumentType entities
- *
- * This implementation only supports property indices, but does not support named properties,
- * as specified in the living standard.
- *
- * @class NamedNodeMap
- * @see https://dom.spec.whatwg.org/#interface-namednodemap
- * @see https://webidl.spec.whatwg.org/#dfn-supported-property-names
- * @constructs NamedNodeMap
- */
- function NamedNodeMap() {}
- /**
- * Returns the index of a node within the list.
- *
- * @param {Array} list
- * The list of nodes.
- * @param {Node} node
- * The node to find.
- * @returns {number}
- * The index of the node within the list, or -1 if not found.
- * @private
- */
- function _findNodeIndex(list, node) {
- var i = 0;
- while (i < list.length) {
- if (list[i] === node) {
- return i;
- }
- i++;
- }
- }
- /**
- * Adds a new attribute to the list and updates the owner element of the attribute.
- *
- * @param {Element} el
- * The element which will become the owner of the new attribute.
- * @param {NamedNodeMap} list
- * The list to which the new attribute will be added.
- * @param {Attr} newAttr
- * The new attribute to be added.
- * @param {Attr} oldAttr
- * The old attribute to be replaced, or null if no attribute is to be replaced.
- * @returns {void}
- * @private
- */
- function _addNamedNode(el, list, newAttr, oldAttr) {
- if (oldAttr) {
- list[_findNodeIndex(list, oldAttr)] = newAttr;
- } else {
- list[list.length] = newAttr;
- list.length++;
- }
- if (el) {
- newAttr.ownerElement = el;
- var doc = el.ownerDocument;
- if (doc) {
- oldAttr && _onRemoveAttribute(doc, el, oldAttr);
- _onAddAttribute(doc, el, newAttr);
- }
- }
- }
- /**
- * Removes an attribute from the list and updates the owner element of the attribute.
- *
- * @param {Element} el
- * The element which is the current owner of the attribute.
- * @param {NamedNodeMap} list
- * The list from which the attribute will be removed.
- * @param {Attr} attr
- * The attribute to be removed.
- * @returns {void}
- * @private
- */
- function _removeNamedNode(el, list, attr) {
- //console.log('remove attr:'+attr)
- var i = _findNodeIndex(list, attr);
- if (i >= 0) {
- var lastIndex = list.length - 1;
- while (i <= lastIndex) {
- list[i] = list[++i];
- }
- list.length = lastIndex;
- if (el) {
- var doc = el.ownerDocument;
- if (doc) {
- _onRemoveAttribute(doc, el, attr);
- }
- attr.ownerElement = null;
- }
- }
- }
- NamedNodeMap.prototype = {
- length: 0,
- item: NodeList.prototype.item,
- /**
- * Get an attribute by name. Note: Name is in lower case in case of HTML namespace and
- * document.
- *
- * @param {string} localName
- * The local name of the attribute.
- * @returns {Attr | null}
- * The attribute with the given local name, or null if no such attribute exists.
- * @see https://dom.spec.whatwg.org/#concept-element-attributes-get-by-name
- */
- getNamedItem: function (localName) {
- if (this._ownerElement && this._ownerElement._isInHTMLDocumentAndNamespace()) {
- localName = localName.toLowerCase();
- }
- var i = 0;
- while (i < this.length) {
- var attr = this[i];
- if (attr.nodeName === localName) {
- return attr;
- }
- i++;
- }
- return null;
- },
- /**
- * Set an attribute.
- *
- * @param {Attr} attr
- * The attribute to set.
- * @returns {Attr | null}
- * The old attribute with the same local name and namespace URI as the new one, or null if no
- * such attribute exists.
- * @throws {DOMException}
- * With code:
- * - {@link INUSE_ATTRIBUTE_ERR} - If the attribute is already an attribute of another
- * element.
- * @see https://dom.spec.whatwg.org/#concept-element-attributes-set
- */
- setNamedItem: function (attr) {
- var el = attr.ownerElement;
- if (el && el !== this._ownerElement) {
- throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR);
- }
- var oldAttr = this.getNamedItemNS(attr.namespaceURI, attr.localName);
- if (oldAttr === attr) {
- return attr;
- }
- _addNamedNode(this._ownerElement, this, attr, oldAttr);
- return oldAttr;
- },
- /**
- * Set an attribute, replacing an existing attribute with the same local name and namespace
- * URI if one exists.
- *
- * @param {Attr} attr
- * The attribute to set.
- * @returns {Attr | null}
- * The old attribute with the same local name and namespace URI as the new one, or null if no
- * such attribute exists.
- * @throws {DOMException}
- * Throws a DOMException with the name "InUseAttributeError" if the attribute is already an
- * attribute of another element.
- * @see https://dom.spec.whatwg.org/#concept-element-attributes-set
- */
- setNamedItemNS: function (attr) {
- return this.setNamedItem(attr);
- },
- /**
- * Removes an attribute specified by the local name.
- *
- * @param {string} localName
- * The local name of the attribute to be removed.
- * @returns {Attr}
- * The attribute node that was removed.
- * @throws {DOMException}
- * With code:
- * - {@link DOMException.NOT_FOUND_ERR} if no attribute with the given name is found.
- * @see https://dom.spec.whatwg.org/#dom-namednodemap-removenameditem
- * @see https://dom.spec.whatwg.org/#concept-element-attributes-remove-by-name
- */
- removeNamedItem: function (localName) {
- var attr = this.getNamedItem(localName);
- if (!attr) {
- throw new DOMException(DOMException.NOT_FOUND_ERR, localName);
- }
- _removeNamedNode(this._ownerElement, this, attr);
- return attr;
- },
- /**
- * Removes an attribute specified by the namespace and local name.
- *
- * @param {string | null} namespaceURI
- * The namespace URI of the attribute to be removed.
- * @param {string} localName
- * The local name of the attribute to be removed.
- * @returns {Attr}
- * The attribute node that was removed.
- * @throws {DOMException}
- * With code:
- * - {@link DOMException.NOT_FOUND_ERR} if no attribute with the given namespace URI and local
- * name is found.
- * @see https://dom.spec.whatwg.org/#dom-namednodemap-removenameditemns
- * @see https://dom.spec.whatwg.org/#concept-element-attributes-remove-by-namespace
- */
- removeNamedItemNS: function (namespaceURI, localName) {
- var attr = this.getNamedItemNS(namespaceURI, localName);
- if (!attr) {
- throw new DOMException(DOMException.NOT_FOUND_ERR, namespaceURI ? namespaceURI + ' : ' + localName : localName);
- }
- _removeNamedNode(this._ownerElement, this, attr);
- return attr;
- },
- /**
- * Get an attribute by namespace and local name.
- *
- * @param {string | null} namespaceURI
- * The namespace URI of the attribute.
- * @param {string} localName
- * The local name of the attribute.
- * @returns {Attr | null}
- * The attribute with the given namespace URI and local name, or null if no such attribute
- * exists.
- * @see https://dom.spec.whatwg.org/#concept-element-attributes-get-by-namespace
- */
- getNamedItemNS: function (namespaceURI, localName) {
- if (!namespaceURI) {
- namespaceURI = null;
- }
- var i = 0;
- while (i < this.length) {
- var node = this[i];
- if (node.localName === localName && node.namespaceURI === namespaceURI) {
- return node;
- }
- i++;
- }
- return null;
- },
- };
- NamedNodeMap.prototype[Symbol.iterator] = function () {
- var me = this;
- var index = 0;
- return {
- next: function () {
- if (index < me.length) {
- return {
- value: me[index++],
- done: false,
- };
- } else {
- return {
- done: true,
- };
- }
- },
- return: function () {
- return {
- done: true,
- };
- },
- };
- };
- /**
- * The DOMImplementation interface provides a number of methods for performing operations that
- * are independent of any particular instance of the document object model.
- *
- * The DOMImplementation interface represents an object providing methods which are not
- * dependent on any particular document.
- * Such an object is returned by the `Document.implementation` property.
- *
- * **The individual methods describe the differences compared to the specs**.
- *
- * @class DOMImplementation
- * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation MDN
- * @see https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490 DOM Level 1 Core
- * (Initial)
- * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-102161490 DOM Level 2 Core
- * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-102161490 DOM Level 3 Core
- * @see https://dom.spec.whatwg.org/#domimplementation DOM Living Standard
- * @constructs DOMImplementation
- */
- function DOMImplementation() {}
- DOMImplementation.prototype = {
- /**
- * Test if the DOM implementation implements a specific feature and version, as specified in
- * {@link https://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMFeatures DOM Features}.
- *
- * The DOMImplementation.hasFeature() method returns a Boolean flag indicating if a given
- * feature is supported. The different implementations fairly diverged in what kind of
- * features were reported. The latest version of the spec settled to force this method to
- * always return true, where the functionality was accurate and in use.
- *
- * @deprecated
- * It is deprecated and modern browsers return true in all cases.
- * @function DOMImplementation#hasFeature
- * @param {string} feature
- * The name of the feature to test.
- * @param {string} [version]
- * This is the version number of the feature to test.
- * @returns {boolean}
- * Always returns true.
- * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/hasFeature MDN
- * @see https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-5CED94D7 DOM Level 1 Core
- * @see https://dom.spec.whatwg.org/#dom-domimplementation-hasfeature DOM Living Standard
- * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-5CED94D7 DOM Level 3 Core
- */
- hasFeature: function (feature, version) {
- return true;
- },
- /**
- * Creates a DOM Document object of the specified type with its document element. Note that
- * based on the {@link DocumentType}
- * given to create the document, the implementation may instantiate specialized
- * {@link Document} objects that support additional features than the "Core", such as "HTML"
- * {@link https://www.w3.org/TR/DOM-Level-3-Core/references.html#DOM2HTML DOM Level 2 HTML}.
- * On the other hand, setting the {@link DocumentType} after the document was created makes
- * this very unlikely to happen. Alternatively, specialized {@link Document} creation methods,
- * such as createHTMLDocument
- * {@link https://www.w3.org/TR/DOM-Level-3-Core/references.html#DOM2HTML DOM Level 2 HTML},
- * can be used to obtain specific types of {@link Document} objects.
- *
- * __It behaves slightly different from the description in the living standard__:
- * - There is no interface/class `XMLDocument`, it returns a `Document`
- * instance (with it's `type` set to `'xml'`).
- * - `encoding`, `mode`, `origin`, `url` fields are currently not declared.
- *
- * @function DOMImplementation.createDocument
- * @param {string | null} namespaceURI
- * The
- * {@link https://www.w3.org/TR/DOM-Level-3-Core/glossary.html#dt-namespaceURI namespace URI}
- * of the document element to create or null.
- * @param {string | null} qualifiedName
- * The
- * {@link https://www.w3.org/TR/DOM-Level-3-Core/glossary.html#dt-qualifiedname qualified name}
- * of the document element to be created or null.
- * @param {DocumentType | null} [doctype=null]
- * The type of document to be created or null. When doctype is not null, its
- * {@link Node#ownerDocument} attribute is set to the document being created. Default is
- * `null`
- * @returns {Document}
- * A new {@link Document} object with its document element. If the NamespaceURI,
- * qualifiedName, and doctype are null, the returned {@link Document} is empty with no
- * document element.
- * @throws {DOMException}
- * With code:
- *
- * - `INVALID_CHARACTER_ERR`: Raised if the specified qualified name is not an XML name
- * according to {@link https://www.w3.org/TR/DOM-Level-3-Core/references.html#XML XML 1.0}.
- * - `NAMESPACE_ERR`: Raised if the qualifiedName is malformed, if the qualifiedName has a
- * prefix and the namespaceURI is null, or if the qualifiedName is null and the namespaceURI
- * is different from null, or if the qualifiedName has a prefix that is "xml" and the
- * namespaceURI is different from "{@link http://www.w3.org/XML/1998/namespace}"
- * {@link https://www.w3.org/TR/DOM-Level-3-Core/references.html#Namespaces XML Namespaces},
- * or if the DOM implementation does not support the "XML" feature but a non-null namespace
- * URI was provided, since namespaces were defined by XML.
- * - `WRONG_DOCUMENT_ERR`: Raised if doctype has already been used with a different document
- * or was created from a different implementation.
- * - `NOT_SUPPORTED_ERR`: May be raised if the implementation does not support the feature
- * "XML" and the language exposed through the Document does not support XML Namespaces (such
- * as {@link https://www.w3.org/TR/DOM-Level-3-Core/references.html#HTML40 HTML 4.01}).
- * @since DOM Level 2.
- * @see {@link #createHTMLDocument}
- * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocument MDN
- * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument DOM Living Standard
- * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#Level-2-Core-DOM-createDocument DOM
- * Level 3 Core
- * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocument DOM
- * Level 2 Core (initial)
- */
- createDocument: function (namespaceURI, qualifiedName, doctype) {
- var contentType = MIME_TYPE.XML_APPLICATION;
- if (namespaceURI === NAMESPACE.HTML) {
- contentType = MIME_TYPE.XML_XHTML_APPLICATION;
- } else if (namespaceURI === NAMESPACE.SVG) {
- contentType = MIME_TYPE.XML_SVG_IMAGE;
- }
- var doc = new Document(PDC, { contentType: contentType });
- doc.implementation = this;
- doc.childNodes = new NodeList();
- doc.doctype = doctype || null;
- if (doctype) {
- doc.appendChild(doctype);
- }
- if (qualifiedName) {
- var root = doc.createElementNS(namespaceURI, qualifiedName);
- doc.appendChild(root);
- }
- return doc;
- },
- /**
- * Creates an empty DocumentType node. Entity declarations and notations are not made
- * available. Entity reference expansions and default attribute additions do not occur.
- *
- * **This behavior is slightly different from the one in the specs**:
- * - `encoding`, `mode`, `origin`, `url` fields are currently not declared.
- * - `publicId` and `systemId` contain the raw data including any possible quotes,
- * so they can always be serialized back to the original value
- * - `internalSubset` contains the raw string between `[` and `]` if present,
- * but is not parsed or validated in any form.
- *
- * @function DOMImplementation#createDocumentType
- * @param {string} qualifiedName
- * The {@link https://www.w3.org/TR/DOM-Level-3-Core/glossary.html#dt-qualifiedname qualified
- * name} of the document type to be created.
- * @param {string} [publicId]
- * The external subset public identifier.
- * @param {string} [systemId]
- * The external subset system identifier.
- * @param {string} [internalSubset]
- * the internal subset or an empty string if it is not present
- * @returns {DocumentType}
- * A new {@link DocumentType} node with {@link Node#ownerDocument} set to null.
- * @throws {DOMException}
- * With code:
- *
- * - `INVALID_CHARACTER_ERR`: Raised if the specified qualified name is not an XML name
- * according to {@link https://www.w3.org/TR/DOM-Level-3-Core/references.html#XML XML 1.0}.
- * - `NAMESPACE_ERR`: Raised if the qualifiedName is malformed.
- * - `NOT_SUPPORTED_ERR`: May be raised if the implementation does not support the feature
- * "XML" and the language exposed through the Document does not support XML Namespaces (such
- * as {@link https://www.w3.org/TR/DOM-Level-3-Core/references.html#HTML40 HTML 4.01}).
- * @since DOM Level 2.
- * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocumentType
- * MDN
- * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype DOM Living
- * Standard
- * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#Level-3-Core-DOM-createDocType DOM
- * Level 3 Core
- * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocType DOM
- * Level 2 Core
- * @see https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md#050
- * @see https://www.w3.org/TR/DOM-Level-2-Core/#core-ID-Core-DocType-internalSubset
- * @prettierignore
- */
- createDocumentType: function (qualifiedName, publicId, systemId, internalSubset) {
- validateQualifiedName(qualifiedName);
- var node = new DocumentType(PDC);
- node.name = qualifiedName;
- node.nodeName = qualifiedName;
- node.publicId = publicId || '';
- node.systemId = systemId || '';
- node.internalSubset = internalSubset || '';
- node.childNodes = new NodeList();
- return node;
- },
- /**
- * Returns an HTML document, that might already have a basic DOM structure.
- *
- * __It behaves slightly different from the description in the living standard__:
- * - If the first argument is `false` no initial nodes are added (steps 3-7 in the specs are
- * omitted)
- * - `encoding`, `mode`, `origin`, `url` fields are currently not declared.
- *
- * @param {string | false} [title]
- * A string containing the title to give the new HTML document.
- * @returns {Document}
- * The HTML document.
- * @since WHATWG Living Standard.
- * @see {@link #createDocument}
- * @see https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument
- * @see https://dom.spec.whatwg.org/#html-document
- */
- createHTMLDocument: function (title) {
- var doc = new Document(PDC, { contentType: MIME_TYPE.HTML });
- doc.implementation = this;
- doc.childNodes = new NodeList();
- if (title !== false) {
- doc.doctype = this.createDocumentType('html');
- doc.doctype.ownerDocument = doc;
- doc.appendChild(doc.doctype);
- var htmlNode = doc.createElement('html');
- doc.appendChild(htmlNode);
- var headNode = doc.createElement('head');
- htmlNode.appendChild(headNode);
- if (typeof title === 'string') {
- var titleNode = doc.createElement('title');
- titleNode.appendChild(doc.createTextNode(title));
- headNode.appendChild(titleNode);
- }
- htmlNode.appendChild(doc.createElement('body'));
- }
- return doc;
- },
- };
- /**
- * The DOM Node interface is an abstract base class upon which many other DOM API objects are
- * based, thus letting those object types to be used similarly and often interchangeably. As an
- * abstract class, there is no such thing as a plain Node object. All objects that implement
- * Node functionality are based on one of its subclasses. Most notable are Document, Element,
- * and DocumentFragment.
- *
- * In addition, every kind of DOM node is represented by an interface based on Node. These
- * include Attr, CharacterData (which Text, Comment, CDATASection and ProcessingInstruction are
- * all based on), and DocumentType.
- *
- * In some cases, a particular feature of the base Node interface may not apply to one of its
- * child interfaces; in that case, the inheriting node may return null or throw an exception,
- * depending on circumstances. For example, attempting to add children to a node type that
- * cannot have children will throw an exception.
- *
- * **This behavior is slightly different from the in the specs**:
- * - unimplemented interfaces: `EventTarget`
- *
- * @class
- * @abstract
- * @param {Symbol} symbol
- * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247
- * @see https://dom.spec.whatwg.org/#node
- * @prettierignore
- */
- function Node(symbol) {
- checkSymbol(symbol);
- }
- Node.prototype = {
- /**
- * The first child of this node.
- *
- * @type {Node | null}
- */
- firstChild: null,
- /**
- * The last child of this node.
- *
- * @type {Node | null}
- */
- lastChild: null,
- /**
- * The previous sibling of this node.
- *
- * @type {Node | null}
- */
- previousSibling: null,
- /**
- * The next sibling of this node.
- *
- * @type {Node | null}
- */
- nextSibling: null,
- /**
- * The parent node of this node.
- *
- * @type {Node | null}
- */
- parentNode: null,
- /**
- * The parent element of this node.
- *
- * @type {Element | null}
- */
- get parentElement() {
- return this.parentNode && this.parentNode.nodeType === this.ELEMENT_NODE ? this.parentNode : null;
- },
- /**
- * The child nodes of this node.
- *
- * @type {NodeList}
- */
- childNodes: null,
- /**
- * The document object associated with this node.
- *
- * @type {Document | null}
- */
- ownerDocument: null,
- /**
- * The value of this node.
- *
- * @type {string | null}
- */
- nodeValue: null,
- /**
- * The namespace URI of this node.
- *
- * @type {string | null}
- */
- namespaceURI: null,
- /**
- * The prefix of the namespace for this node.
- *
- * @type {string | null}
- */
- prefix: null,
- /**
- * The local part of the qualified name of this node.
- *
- * @type {string | null}
- */
- localName: null,
- /**
- * The baseURI is currently always `about:blank`,
- * since that's what happens when you create a document from scratch.
- *
- * @type {'about:blank'}
- */
- baseURI: 'about:blank',
- /**
- * Is true if this node is part of a document.
- *
- * @type {boolean}
- */
- get isConnected() {
- var rootNode = this.getRootNode();
- return rootNode && rootNode.nodeType === rootNode.DOCUMENT_NODE;
- },
- /**
- * Checks whether `other` is an inclusive descendant of this node.
- *
- * @param {Node | null | undefined} other
- * The node to check.
- * @returns {boolean}
- * True if `other` is an inclusive descendant of this node; false otherwise.
- * @see https://dom.spec.whatwg.org/#dom-node-contains
- */
- contains: function (other) {
- if (!other) return false;
- var parent = other;
- do {
- if (this === parent) return true;
- parent = other.parentNode;
- } while (parent);
- return false;
- },
- /**
- * @typedef GetRootNodeOptions
- * @property {boolean} [composed=false]
- */
- /**
- * Searches for the root node of this node.
- *
- * **This behavior is slightly different from the in the specs**:
- * - ignores `options.composed`, since `ShadowRoot`s are unsupported, always returns root.
- *
- * @param {GetRootNodeOptions} [options]
- * @returns {Node}
- * Root node.
- * @see https://dom.spec.whatwg.org/#dom-node-getrootnode
- * @see https://dom.spec.whatwg.org/#concept-shadow-including-root
- */
- getRootNode: function (options) {
- var parent = this;
- do {
- if (!parent.parentNode) {
- return parent;
- }
- parent = parent.parentNode;
- } while (parent);
- },
- /**
- * Checks whether the given node is equal to this node.
- *
- * @param {Node} [otherNode]
- * @see https://dom.spec.whatwg.org/#concept-node-equals
- */
- isEqualNode: function (otherNode) {
- if (!otherNode) return false;
- if (this.nodeType !== otherNode.nodeType) return false;
- switch (this.nodeType) {
- case this.DOCUMENT_TYPE_NODE:
- if (this.name !== otherNode.name) return false;
- if (this.publicId !== otherNode.publicId) return false;
- if (this.systemId !== otherNode.systemId) return false;
- break;
- case this.ELEMENT_NODE:
- if (this.namespaceURI !== otherNode.namespaceURI) return false;
- if (this.prefix !== otherNode.prefix) return false;
- if (this.localName !== otherNode.localName) return false;
- if (this.attributes.length !== otherNode.attributes.length) return false;
- for (var i = 0; i < this.attributes.length; i++) {
- var attr = this.attributes.item(i);
- if (!attr.isEqualNode(otherNode.getAttributeNodeNS(attr.namespaceURI, attr.localName))) {
- return false;
- }
- }
- break;
- case this.ATTRIBUTE_NODE:
- if (this.namespaceURI !== otherNode.namespaceURI) return false;
- if (this.localName !== otherNode.localName) return false;
- if (this.value !== otherNode.value) return false;
- break;
- case this.PROCESSING_INSTRUCTION_NODE:
- if (this.target !== otherNode.target || this.data !== otherNode.data) {
- return false;
- }
- break;
- case this.TEXT_NODE:
- case this.COMMENT_NODE:
- if (this.data !== otherNode.data) return false;
- break;
- }
- if (this.childNodes.length !== otherNode.childNodes.length) {
- return false;
- }
- for (var i = 0; i < this.childNodes.length; i++) {
- if (!this.childNodes[i].isEqualNode(otherNode.childNodes[i])) {
- return false;
- }
- }
- return true;
- },
- /**
- * Checks whether or not the given node is this node.
- *
- * @param {Node} [otherNode]
- */
- isSameNode: function (otherNode) {
- return this === otherNode;
- },
- /**
- * Inserts a node before a reference node as a child of this node.
- *
- * @param {Node} newChild
- * The new child node to be inserted.
- * @param {Node | null} refChild
- * The reference node before which newChild will be inserted.
- * @returns {Node}
- * The new child node successfully inserted.
- * @throws {DOMException}
- * Throws a DOMException if inserting the node would result in a DOM tree that is not
- * well-formed, or if `child` is provided but is not a child of `parent`.
- * See {@link _insertBefore} for more details.
- * @since Modified in DOM L2
- */
- insertBefore: function (newChild, refChild) {
- return _insertBefore(this, newChild, refChild);
- },
- /**
- * Replaces an old child node with a new child node within this node.
- *
- * @param {Node} newChild
- * The new node that is to replace the old node.
- * If it already exists in the DOM, it is removed from its original position.
- * @param {Node} oldChild
- * The existing child node to be replaced.
- * @returns {Node}
- * Returns the replaced child node.
- * @throws {DOMException}
- * Throws a DOMException if replacing the node would result in a DOM tree that is not
- * well-formed, or if `oldChild` is not a child of `this`.
- * This can also occur if the pre-replacement validity assertion fails.
- * See {@link _insertBefore}, {@link Node.removeChild}, and
- * {@link assertPreReplacementValidityInDocument} for more details.
- * @see https://dom.spec.whatwg.org/#concept-node-replace
- */
- replaceChild: function (newChild, oldChild) {
- _insertBefore(this, newChild, oldChild, assertPreReplacementValidityInDocument);
- if (oldChild) {
- this.removeChild(oldChild);
- }
- },
- /**
- * Removes an existing child node from this node.
- *
- * @param {Node} oldChild
- * The child node to be removed.
- * @returns {Node}
- * Returns the removed child node.
- * @throws {DOMException}
- * Throws a DOMException if `oldChild` is not a child of `this`.
- * See {@link _removeChild} for more details.
- */
- removeChild: function (oldChild) {
- return _removeChild(this, oldChild);
- },
- /**
- * Appends a child node to this node.
- *
- * @param {Node} newChild
- * The child node to be appended to this node.
- * If it already exists in the DOM, it is removed from its original position.
- * @returns {Node}
- * Returns the appended child node.
- * @throws {DOMException}
- * Throws a DOMException if appending the node would result in a DOM tree that is not
- * well-formed, or if `newChild` is not a valid Node.
- * See {@link insertBefore} for more details.
- */
- appendChild: function (newChild) {
- return this.insertBefore(newChild, null);
- },
- /**
- * Determines whether this node has any child nodes.
- *
- * @returns {boolean}
- * Returns true if this node has any child nodes, and false otherwise.
- */
- hasChildNodes: function () {
- return this.firstChild != null;
- },
- /**
- * Creates a copy of the calling node.
- *
- * @param {boolean} deep
- * If true, the contents of the node are recursively copied.
- * If false, only the node itself (and its attributes, if it is an element) are copied.
- * @returns {Node}
- * Returns the newly created copy of the node.
- * @throws {DOMException}
- * May throw a DOMException if operations within {@link Element#setAttributeNode} or
- * {@link Node#appendChild} (which are potentially invoked in this method) do not meet their
- * specific constraints.
- * @see {@link cloneNode}
- */
- cloneNode: function (deep) {
- return cloneNode(this.ownerDocument || this, this, deep);
- },
- /**
- * Puts the specified node and all of its subtree into a "normalized" form. In a normalized
- * subtree, no text nodes in the subtree are empty and there are no adjacent text nodes.
- *
- * Specifically, this method merges any adjacent text nodes (i.e., nodes for which `nodeType`
- * is `TEXT_NODE`) into a single node with the combined data. It also removes any empty text
- * nodes.
- *
- * This method operates recursively, so it also normalizes any and all descendent nodes within
- * the subtree.
- *
- * @throws {DOMException}
- * May throw a DOMException if operations within removeChild or appendData (which are
- * potentially invoked in this method) do not meet their specific constraints.
- * @since Modified in DOM Level 2
- * @see {@link Node.removeChild}
- * @see {@link CharacterData.appendData}
- */
- normalize: function () {
- var child = this.firstChild;
- while (child) {
- var next = child.nextSibling;
- if (next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE) {
- this.removeChild(next);
- child.appendData(next.data);
- } else {
- child.normalize();
- child = next;
- }
- }
- },
- /**
- * Checks whether the DOM implementation implements a specific feature and its version.
- *
- * @deprecated
- * Since `DOMImplementation.hasFeature` is deprecated and always returns true.
- * @param {string} feature
- * The package name of the feature to test. This is the same name that can be passed to the
- * method `hasFeature` on `DOMImplementation`.
- * @param {string} version
- * This is the version number of the package name to test.
- * @returns {boolean}
- * Returns true in all cases in the current implementation.
- * @since Introduced in DOM Level 2
- * @see {@link DOMImplementation.hasFeature}
- */
- isSupported: function (feature, version) {
- return this.ownerDocument.implementation.hasFeature(feature, version);
- },
- /**
- * Look up the prefix associated to the given namespace URI, starting from this node.
- * **The default namespace declarations are ignored by this method.**
- * See Namespace Prefix Lookup for details on the algorithm used by this method.
- *
- * **This behavior is different from the in the specs**:
- * - no node type specific handling
- * - uses the internal attribute _nsMap for resolving namespaces that is updated when changing attributes
- *
- * @param {string | null} namespaceURI
- * The namespace URI for which to find the associated prefix.
- * @returns {string | null}
- * The associated prefix, if found; otherwise, null.
- * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespacePrefix
- * @see https://www.w3.org/TR/DOM-Level-3-Core/namespaces-algorithms.html#lookupNamespacePrefixAlgo
- * @see https://dom.spec.whatwg.org/#dom-node-lookupprefix
- * @see https://github.com/xmldom/xmldom/issues/322
- * @prettierignore
- */
- lookupPrefix: function (namespaceURI) {
- var el = this;
- while (el) {
- var map = el._nsMap;
- //console.dir(map)
- if (map) {
- for (var n in map) {
- if (hasOwn(map, n) && map[n] === namespaceURI) {
- return n;
- }
- }
- }
- el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode;
- }
- return null;
- },
- /**
- * This function is used to look up the namespace URI associated with the given prefix,
- * starting from this node.
- *
- * **This behavior is different from the in the specs**:
- * - no node type specific handling
- * - uses the internal attribute _nsMap for resolving namespaces that is updated when changing attributes
- *
- * @param {string | null} prefix
- * The prefix for which to find the associated namespace URI.
- * @returns {string | null}
- * The associated namespace URI, if found; otherwise, null.
- * @since DOM Level 3
- * @see https://dom.spec.whatwg.org/#dom-node-lookupnamespaceuri
- * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI
- * @prettierignore
- */
- lookupNamespaceURI: function (prefix) {
- var el = this;
- while (el) {
- var map = el._nsMap;
- //console.dir(map)
- if (map) {
- if (hasOwn(map, prefix)) {
- return map[prefix];
- }
- }
- el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode;
- }
- return null;
- },
- /**
- * Determines whether the given namespace URI is the default namespace.
- *
- * The function works by looking up the prefix associated with the given namespace URI. If no
- * prefix is found (i.e., the namespace URI is not registered in the namespace map of this
- * node or any of its ancestors), it returns `true`, implying the namespace URI is considered
- * the default.
- *
- * **This behavior is different from the in the specs**:
- * - no node type specific handling
- * - uses the internal attribute _nsMap for resolving namespaces that is updated when changing attributes
- *
- * @param {string | null} namespaceURI
- * The namespace URI to be checked.
- * @returns {boolean}
- * Returns true if the given namespace URI is the default namespace, false otherwise.
- * @since DOM Level 3
- * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-isDefaultNamespace
- * @see https://dom.spec.whatwg.org/#dom-node-isdefaultnamespace
- * @prettierignore
- */
- isDefaultNamespace: function (namespaceURI) {
- var prefix = this.lookupPrefix(namespaceURI);
- return prefix == null;
- },
- /**
- * Compares the reference node with a node with regard to their position in the document and
- * according to the document order.
- *
- * @param {Node} other
- * The node to compare the reference node to.
- * @returns {number}
- * Returns how the node is positioned relatively to the reference node according to the
- * bitmask. 0 if reference node and given node are the same.
- * @since DOM Level 3
- * @see https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Node3-compare
- * @see https://dom.spec.whatwg.org/#dom-node-comparedocumentposition
- */
- compareDocumentPosition: function (other) {
- if (this === other) return 0;
- var node1 = other;
- var node2 = this;
- var attr1 = null;
- var attr2 = null;
- if (node1 instanceof Attr) {
- attr1 = node1;
- node1 = attr1.ownerElement;
- }
- if (node2 instanceof Attr) {
- attr2 = node2;
- node2 = attr2.ownerElement;
- if (attr1 && node1 && node2 === node1) {
- for (var i = 0, attr; (attr = node2.attributes[i]); i++) {
- if (attr === attr1)
- return DocumentPosition.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC + DocumentPosition.DOCUMENT_POSITION_PRECEDING;
- if (attr === attr2)
- return DocumentPosition.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC + DocumentPosition.DOCUMENT_POSITION_FOLLOWING;
- }
- }
- }
- if (!node1 || !node2 || node2.ownerDocument !== node1.ownerDocument) {
- return (
- DocumentPosition.DOCUMENT_POSITION_DISCONNECTED +
- DocumentPosition.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
- (docGUID(node2.ownerDocument) > docGUID(node1.ownerDocument)
- ? DocumentPosition.DOCUMENT_POSITION_FOLLOWING
- : DocumentPosition.DOCUMENT_POSITION_PRECEDING)
- );
- }
- if (attr2 && node1 === node2) {
- return DocumentPosition.DOCUMENT_POSITION_CONTAINS + DocumentPosition.DOCUMENT_POSITION_PRECEDING;
- }
- if (attr1 && node1 === node2) {
- return DocumentPosition.DOCUMENT_POSITION_CONTAINED_BY + DocumentPosition.DOCUMENT_POSITION_FOLLOWING;
- }
- var chain1 = [];
- var ancestor1 = node1.parentNode;
- while (ancestor1) {
- if (!attr2 && ancestor1 === node2) {
- return DocumentPosition.DOCUMENT_POSITION_CONTAINED_BY + DocumentPosition.DOCUMENT_POSITION_FOLLOWING;
- }
- chain1.push(ancestor1);
- ancestor1 = ancestor1.parentNode;
- }
- chain1.reverse();
- var chain2 = [];
- var ancestor2 = node2.parentNode;
- while (ancestor2) {
- if (!attr1 && ancestor2 === node1) {
- return DocumentPosition.DOCUMENT_POSITION_CONTAINS + DocumentPosition.DOCUMENT_POSITION_PRECEDING;
- }
- chain2.push(ancestor2);
- ancestor2 = ancestor2.parentNode;
- }
- chain2.reverse();
- var ca = commonAncestor(chain1, chain2);
- for (var n in ca.childNodes) {
- var child = ca.childNodes[n];
- if (child === node2) return DocumentPosition.DOCUMENT_POSITION_FOLLOWING;
- if (child === node1) return DocumentPosition.DOCUMENT_POSITION_PRECEDING;
- if (chain2.indexOf(child) >= 0) return DocumentPosition.DOCUMENT_POSITION_FOLLOWING;
- if (chain1.indexOf(child) >= 0) return DocumentPosition.DOCUMENT_POSITION_PRECEDING;
- }
- return 0;
- },
- };
- /**
- * Encodes special XML characters to their corresponding entities.
- *
- * @param {string} c
- * The character to be encoded.
- * @returns {string}
- * The encoded character.
- * @private
- */
- function _xmlEncoder(c) {
- return (
- (c == '<' && '<') || (c == '>' && '>') || (c == '&' && '&') || (c == '"' && '"') || '&#' + c.charCodeAt() + ';'
- );
- }
- copy(NodeType, Node);
- copy(NodeType, Node.prototype);
- copy(DocumentPosition, Node);
- copy(DocumentPosition, Node.prototype);
- /**
- * @param callback
- * Return true for continue,false for break.
- * @returns
- * boolean true: break visit;
- */
- function _visitNode(node, callback) {
- if (callback(node)) {
- return true;
- }
- if ((node = node.firstChild)) {
- do {
- if (_visitNode(node, callback)) {
- return true;
- }
- } while ((node = node.nextSibling));
- }
- }
- /**
- * @typedef DocumentOptions
- * @property {string} [contentType=MIME_TYPE.XML_APPLICATION]
- */
- /**
- * The Document interface describes the common properties and methods for any kind of document.
- *
- * It should usually be created using `new DOMImplementation().createDocument(...)`
- * or `new DOMImplementation().createHTMLDocument(...)`.
- *
- * The constructor is considered a private API and offers to initially set the `contentType`
- * property via it's options parameter.
- *
- * @class
- * @param {Symbol} symbol
- * @param {DocumentOptions} [options]
- * @augments Node
- * @private
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Document
- * @see https://dom.spec.whatwg.org/#interface-document
- */
- function Document(symbol, options) {
- checkSymbol(symbol);
- var opt = options || {};
- this.ownerDocument = this;
- /**
- * The mime type of the document is determined at creation time and can not be modified.
- *
- * @type {string}
- * @see https://dom.spec.whatwg.org/#concept-document-content-type
- * @see {@link DOMImplementation}
- * @see {@link MIME_TYPE}
- * @readonly
- */
- this.contentType = opt.contentType || MIME_TYPE.XML_APPLICATION;
- /**
- * @type {'html' | 'xml'}
- * @see https://dom.spec.whatwg.org/#concept-document-type
- * @see {@link DOMImplementation}
- * @readonly
- */
- this.type = isHTMLMimeType(this.contentType) ? 'html' : 'xml';
- }
- /**
- * Updates the namespace mapping of an element when a new attribute is added.
- *
- * @param {Document} doc
- * The document that the element belongs to.
- * @param {Element} el
- * The element to which the attribute is being added.
- * @param {Attr} newAttr
- * The new attribute being added.
- * @private
- */
- function _onAddAttribute(doc, el, newAttr) {
- doc && doc._inc++;
- var ns = newAttr.namespaceURI;
- if (ns === NAMESPACE.XMLNS) {
- //update namespace
- el._nsMap[newAttr.prefix ? newAttr.localName : ''] = newAttr.value;
- }
- }
- /**
- * Updates the namespace mapping of an element when an attribute is removed.
- *
- * @param {Document} doc
- * The document that the element belongs to.
- * @param {Element} el
- * The element from which the attribute is being removed.
- * @param {Attr} newAttr
- * The attribute being removed.
- * @param {boolean} remove
- * Indicates whether the attribute is to be removed.
- * @private
- */
- function _onRemoveAttribute(doc, el, newAttr, remove) {
- doc && doc._inc++;
- var ns = newAttr.namespaceURI;
- if (ns === NAMESPACE.XMLNS) {
- //update namespace
- delete el._nsMap[newAttr.prefix ? newAttr.localName : ''];
- }
- }
- /**
- * Updates `parent.childNodes`, adjusting the indexed items and its `length`.
- * If `newChild` is provided and has no nextSibling, it will be appended.
- * Otherwise, it's assumed that an item has been removed or inserted,
- * and `parent.firstNode` and its `.nextSibling` to re-indexing all child nodes of `parent`.
- *
- * @param {Document} doc
- * The parent document of `el`.
- * @param {Node} parent
- * The parent node whose childNodes list needs to be updated.
- * @param {Node} [newChild]
- * The new child node to be appended. If not provided, the function assumes a node has been
- * removed.
- * @private
- */
- function _onUpdateChild(doc, parent, newChild) {
- if (doc && doc._inc) {
- doc._inc++;
- var childNodes = parent.childNodes;
- // assumes nextSibling and previousSibling were already configured upfront
- if (newChild && !newChild.nextSibling) {
- // if an item has been appended, we only need to update the last index and the length
- childNodes[childNodes.length++] = newChild;
- } else {
- // otherwise we need to reindex all items,
- // which can take a while when processing nodes with a lot of children
- var child = parent.firstChild;
- var i = 0;
- while (child) {
- childNodes[i++] = child;
- child = child.nextSibling;
- }
- childNodes.length = i;
- delete childNodes[childNodes.length];
- }
- }
- }
- /**
- * Removes the connections between `parentNode` and `child`
- * and any existing `child.previousSibling` or `child.nextSibling`.
- *
- * @param {Node} parentNode
- * The parent node from which the child node is to be removed.
- * @param {Node} child
- * The child node to be removed from the parentNode.
- * @returns {Node}
- * Returns the child node that was removed.
- * @throws {DOMException}
- * With code:
- * - {@link DOMException.NOT_FOUND_ERR} If the parentNode is not the parent of the child node.
- * @private
- * @see https://github.com/xmldom/xmldom/issues/135
- * @see https://github.com/xmldom/xmldom/issues/145
- */
- function _removeChild(parentNode, child) {
- if (parentNode !== child.parentNode) {
- throw new DOMException(DOMException.NOT_FOUND_ERR, "child's parent is not parent");
- }
- var oldPreviousSibling = child.previousSibling;
- var oldNextSibling = child.nextSibling;
- if (oldPreviousSibling) {
- oldPreviousSibling.nextSibling = oldNextSibling;
- } else {
- parentNode.firstChild = oldNextSibling;
- }
- if (oldNextSibling) {
- oldNextSibling.previousSibling = oldPreviousSibling;
- } else {
- parentNode.lastChild = oldPreviousSibling;
- }
- _onUpdateChild(parentNode.ownerDocument, parentNode);
- child.parentNode = null;
- child.previousSibling = null;
- child.nextSibling = null;
- return child;
- }
- /**
- * Returns `true` if `node` can be a parent for insertion.
- *
- * @param {Node} node
- * @returns {boolean}
- */
- function hasValidParentNodeType(node) {
- return (
- node &&
- (node.nodeType === Node.DOCUMENT_NODE || node.nodeType === Node.DOCUMENT_FRAGMENT_NODE || node.nodeType === Node.ELEMENT_NODE)
- );
- }
- /**
- * Returns `true` if `node` can be inserted according to it's `nodeType`.
- *
- * @param {Node} node
- * @returns {boolean}
- */
- function hasInsertableNodeType(node) {
- return (
- node &&
- (node.nodeType === Node.CDATA_SECTION_NODE ||
- node.nodeType === Node.COMMENT_NODE ||
- node.nodeType === Node.DOCUMENT_FRAGMENT_NODE ||
- node.nodeType === Node.DOCUMENT_TYPE_NODE ||
- node.nodeType === Node.ELEMENT_NODE ||
- node.nodeType === Node.PROCESSING_INSTRUCTION_NODE ||
- node.nodeType === Node.TEXT_NODE)
- );
- }
- /**
- * Returns true if `node` is a DOCTYPE node.
- *
- * @param {Node} node
- * @returns {boolean}
- */
- function isDocTypeNode(node) {
- return node && node.nodeType === Node.DOCUMENT_TYPE_NODE;
- }
- /**
- * Returns true if the node is an element.
- *
- * @param {Node} node
- * @returns {boolean}
- */
- function isElementNode(node) {
- return node && node.nodeType === Node.ELEMENT_NODE;
- }
- /**
- * Returns true if `node` is a text node.
- *
- * @param {Node} node
- * @returns {boolean}
- */
- function isTextNode(node) {
- return node && node.nodeType === Node.TEXT_NODE;
- }
- /**
- * Check if en element node can be inserted before `child`, or at the end if child is falsy,
- * according to the presence and position of a doctype node on the same level.
- *
- * @param {Document} doc
- * The document node.
- * @param {Node} child
- * The node that would become the nextSibling if the element would be inserted.
- * @returns {boolean}
- * `true` if an element can be inserted before child.
- * @private
- */
- function isElementInsertionPossible(doc, child) {
- var parentChildNodes = doc.childNodes || [];
- if (find(parentChildNodes, isElementNode) || isDocTypeNode(child)) {
- return false;
- }
- var docTypeNode = find(parentChildNodes, isDocTypeNode);
- return !(child && docTypeNode && parentChildNodes.indexOf(docTypeNode) > parentChildNodes.indexOf(child));
- }
- /**
- * Check if en element node can be inserted before `child`, or at the end if child is falsy,
- * according to the presence and position of a doctype node on the same level.
- *
- * @param {Node} doc
- * The document node.
- * @param {Node} child
- * The node that would become the nextSibling if the element would be inserted.
- * @returns {boolean}
- * `true` if an element can be inserted before child.
- * @private
- */
- function isElementReplacementPossible(doc, child) {
- var parentChildNodes = doc.childNodes || [];
- function hasElementChildThatIsNotChild(node) {
- return isElementNode(node) && node !== child;
- }
- if (find(parentChildNodes, hasElementChildThatIsNotChild)) {
- return false;
- }
- var docTypeNode = find(parentChildNodes, isDocTypeNode);
- return !(child && docTypeNode && parentChildNodes.indexOf(docTypeNode) > parentChildNodes.indexOf(child));
- }
- /**
- * Asserts pre-insertion validity of a node into a parent before a child.
- * Throws errors for invalid node combinations that would result in an ill-formed DOM.
- *
- * @param {Node} parent
- * The parent node to insert `node` into.
- * @param {Node} node
- * The node to insert.
- * @param {Node | null} child
- * The node that should become the `nextSibling` of `node`. If null, no sibling is considered.
- * @throws {DOMException}
- * With code:
- * - {@link DOMException.HIERARCHY_REQUEST_ERR} If `parent` is not a Document,
- * DocumentFragment, or Element node.
- * - {@link DOMException.HIERARCHY_REQUEST_ERR} If `node` is a host-including inclusive
- * ancestor of `parent`. (Currently not implemented)
- * - {@link DOMException.NOT_FOUND_ERR} If `child` is non-null and its `parent` is not
- * `parent`.
- * - {@link DOMException.HIERARCHY_REQUEST_ERR} If `node` is not a DocumentFragment,
- * DocumentType, Element, or CharacterData node.
- * - {@link DOMException.HIERARCHY_REQUEST_ERR} If either `node` is a Text node and `parent` is
- * a document, or if `node` is a doctype and `parent` is not a document.
- * @private
- * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
- * @see https://dom.spec.whatwg.org/#concept-node-replace
- */
- function assertPreInsertionValidity1to5(parent, node, child) {
- // 1. If `parent` is not a Document, DocumentFragment, or Element node, then throw a "HierarchyRequestError" DOMException.
- if (!hasValidParentNodeType(parent)) {
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Unexpected parent node type ' + parent.nodeType);
- }
- // 2. If `node` is a host-including inclusive ancestor of `parent`, then throw a "HierarchyRequestError" DOMException.
- // not implemented!
- // 3. If `child` is non-null and its parent is not `parent`, then throw a "NotFoundError" DOMException.
- if (child && child.parentNode !== parent) {
- throw new DOMException(DOMException.NOT_FOUND_ERR, 'child not in parent');
- }
- if (
- // 4. If `node` is not a DocumentFragment, DocumentType, Element, or CharacterData node, then throw a "HierarchyRequestError" DOMException.
- !hasInsertableNodeType(node) ||
- // 5. If either `node` is a Text node and `parent` is a document,
- // the sax parser currently adds top level text nodes, this will be fixed in 0.9.0
- // || (node.nodeType === Node.TEXT_NODE && parent.nodeType === Node.DOCUMENT_NODE)
- // or `node` is a doctype and `parent` is not a document, then throw a "HierarchyRequestError" DOMException.
- (isDocTypeNode(node) && parent.nodeType !== Node.DOCUMENT_NODE)
- ) {
- throw new DOMException(
- DOMException.HIERARCHY_REQUEST_ERR,
- 'Unexpected node type ' + node.nodeType + ' for parent node type ' + parent.nodeType
- );
- }
- }
- /**
- * Asserts pre-insertion validity of a node into a document before a child.
- * Throws errors for invalid node combinations that would result in an ill-formed DOM.
- *
- * @param {Document} parent
- * The parent node to insert `node` into.
- * @param {Node} node
- * The node to insert.
- * @param {Node | undefined} child
- * The node that should become the `nextSibling` of `node`. If undefined, no sibling is
- * considered.
- * @returns {Node}
- * @throws {DOMException}
- * With code:
- * - {@link DOMException.HIERARCHY_REQUEST_ERR} If `node` is a DocumentFragment with more than
- * one element child or has a Text node child.
- * - {@link DOMException.HIERARCHY_REQUEST_ERR} If `node` is a DocumentFragment with one
- * element child and either `parent` has an element child, `child` is a doctype, or `child` is
- * non-null and a doctype is following `child`.
- * - {@link DOMException.HIERARCHY_REQUEST_ERR} If `node` is an Element and `parent` has an
- * element child, `child` is a doctype, or `child` is non-null and a doctype is following
- * `child`.
- * - {@link DOMException.HIERARCHY_REQUEST_ERR} If `node` is a DocumentType and `parent` has a
- * doctype child, `child` is non-null and an element is preceding `child`, or `child` is null
- * and `parent` has an element child.
- * @private
- * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
- * @see https://dom.spec.whatwg.org/#concept-node-replace
- */
- function assertPreInsertionValidityInDocument(parent, node, child) {
- var parentChildNodes = parent.childNodes || [];
- var nodeChildNodes = node.childNodes || [];
- // DocumentFragment
- if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
- var nodeChildElements = nodeChildNodes.filter(isElementNode);
- // If node has more than one element child or has a Text node child.
- if (nodeChildElements.length > 1 || find(nodeChildNodes, isTextNode)) {
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'More than one element or text in fragment');
- }
- // Otherwise, if `node` has one element child and either `parent` has an element child,
- // `child` is a doctype, or `child` is non-null and a doctype is following `child`.
- if (nodeChildElements.length === 1 && !isElementInsertionPossible(parent, child)) {
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype');
- }
- }
- // Element
- if (isElementNode(node)) {
- // `parent` has an element child, `child` is a doctype,
- // or `child` is non-null and a doctype is following `child`.
- if (!isElementInsertionPossible(parent, child)) {
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Only one element can be added and only after doctype');
- }
- }
- // DocumentType
- if (isDocTypeNode(node)) {
- // `parent` has a doctype child,
- if (find(parentChildNodes, isDocTypeNode)) {
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Only one doctype is allowed');
- }
- var parentElementChild = find(parentChildNodes, isElementNode);
- // `child` is non-null and an element is preceding `child`,
- if (child && parentChildNodes.indexOf(parentElementChild) < parentChildNodes.indexOf(child)) {
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Doctype can only be inserted before an element');
- }
- // or `child` is null and `parent` has an element child.
- if (!child && parentElementChild) {
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Doctype can not be appended since element is present');
- }
- }
- }
- /**
- * @param {Document} parent
- * The parent node to insert `node` into.
- * @param {Node} node
- * The node to insert.
- * @param {Node | undefined} child
- * the node that should become the `nextSibling` of `node`
- * @returns {Node}
- * @throws {DOMException}
- * For several node combinations that would create a DOM that is not well-formed.
- * @throws {DOMException}
- * If `child` is provided but is not a child of `parent`.
- * @private
- * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
- * @see https://dom.spec.whatwg.org/#concept-node-replace
- */
- function assertPreReplacementValidityInDocument(parent, node, child) {
- var parentChildNodes = parent.childNodes || [];
- var nodeChildNodes = node.childNodes || [];
- // DocumentFragment
- if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
- var nodeChildElements = nodeChildNodes.filter(isElementNode);
- // If `node` has more than one element child or has a Text node child.
- if (nodeChildElements.length > 1 || find(nodeChildNodes, isTextNode)) {
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'More than one element or text in fragment');
- }
- // Otherwise, if `node` has one element child and either `parent` has an element child that is not `child` or a doctype is following `child`.
- if (nodeChildElements.length === 1 && !isElementReplacementPossible(parent, child)) {
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype');
- }
- }
- // Element
- if (isElementNode(node)) {
- // `parent` has an element child that is not `child` or a doctype is following `child`.
- if (!isElementReplacementPossible(parent, child)) {
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Only one element can be added and only after doctype');
- }
- }
- // DocumentType
- if (isDocTypeNode(node)) {
- function hasDoctypeChildThatIsNotChild(node) {
- return isDocTypeNode(node) && node !== child;
- }
- // `parent` has a doctype child that is not `child`,
- if (find(parentChildNodes, hasDoctypeChildThatIsNotChild)) {
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Only one doctype is allowed');
- }
- var parentElementChild = find(parentChildNodes, isElementNode);
- // or an element is preceding `child`.
- if (child && parentChildNodes.indexOf(parentElementChild) < parentChildNodes.indexOf(child)) {
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Doctype can only be inserted before an element');
- }
- }
- }
- /**
- * Inserts a node into a parent node before a child node.
- *
- * @param {Node} parent
- * The parent node to insert the node into.
- * @param {Node} node
- * The node to insert into the parent.
- * @param {Node | null} child
- * The node that should become the next sibling of the node.
- * If null, the function inserts the node at the end of the children of the parent node.
- * @param {Function} [_inDocumentAssertion]
- * An optional function to check pre-insertion validity if parent is a document node.
- * Defaults to {@link assertPreInsertionValidityInDocument}
- * @returns {Node}
- * Returns the inserted node.
- * @throws {DOMException}
- * Throws a DOMException if inserting the node would result in a DOM tree that is not
- * well-formed. See {@link assertPreInsertionValidity1to5},
- * {@link assertPreInsertionValidityInDocument}.
- * @throws {DOMException}
- * Throws a DOMException if child is provided but is not a child of the parent. See
- * {@link Node.removeChild}
- * @private
- * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
- */
- function _insertBefore(parent, node, child, _inDocumentAssertion) {
- // To ensure pre-insertion validity of a node into a parent before a child, run these steps:
- assertPreInsertionValidity1to5(parent, node, child);
- // If parent is a document, and any of the statements below, switched on the interface node implements,
- // are true, then throw a "HierarchyRequestError" DOMException.
- if (parent.nodeType === Node.DOCUMENT_NODE) {
- (_inDocumentAssertion || assertPreInsertionValidityInDocument)(parent, node, child);
- }
- var cp = node.parentNode;
- if (cp) {
- cp.removeChild(node); //remove and update
- }
- if (node.nodeType === DOCUMENT_FRAGMENT_NODE) {
- var newFirst = node.firstChild;
- if (newFirst == null) {
- return node;
- }
- var newLast = node.lastChild;
- } else {
- newFirst = newLast = node;
- }
- var pre = child ? child.previousSibling : parent.lastChild;
- newFirst.previousSibling = pre;
- newLast.nextSibling = child;
- if (pre) {
- pre.nextSibling = newFirst;
- } else {
- parent.firstChild = newFirst;
- }
- if (child == null) {
- parent.lastChild = newLast;
- } else {
- child.previousSibling = newLast;
- }
- do {
- newFirst.parentNode = parent;
- } while (newFirst !== newLast && (newFirst = newFirst.nextSibling));
- _onUpdateChild(parent.ownerDocument || parent, parent, node);
- if (node.nodeType == DOCUMENT_FRAGMENT_NODE) {
- node.firstChild = node.lastChild = null;
- }
- return node;
- }
- Document.prototype = {
- /**
- * The implementation that created this document.
- *
- * @type DOMImplementation
- * @readonly
- */
- implementation: null,
- nodeName: '#document',
- nodeType: DOCUMENT_NODE,
- /**
- * The DocumentType node of the document.
- *
- * @type DocumentType
- * @readonly
- */
- doctype: null,
- documentElement: null,
- _inc: 1,
- insertBefore: function (newChild, refChild) {
- //raises
- if (newChild.nodeType === DOCUMENT_FRAGMENT_NODE) {
- var child = newChild.firstChild;
- while (child) {
- var next = child.nextSibling;
- this.insertBefore(child, refChild);
- child = next;
- }
- return newChild;
- }
- _insertBefore(this, newChild, refChild);
- newChild.ownerDocument = this;
- if (this.documentElement === null && newChild.nodeType === ELEMENT_NODE) {
- this.documentElement = newChild;
- }
- return newChild;
- },
- removeChild: function (oldChild) {
- var removed = _removeChild(this, oldChild);
- if (removed === this.documentElement) {
- this.documentElement = null;
- }
- return removed;
- },
- replaceChild: function (newChild, oldChild) {
- //raises
- _insertBefore(this, newChild, oldChild, assertPreReplacementValidityInDocument);
- newChild.ownerDocument = this;
- if (oldChild) {
- this.removeChild(oldChild);
- }
- if (isElementNode(newChild)) {
- this.documentElement = newChild;
- }
- },
- // Introduced in DOM Level 2:
- importNode: function (importedNode, deep) {
- return importNode(this, importedNode, deep);
- },
- // Introduced in DOM Level 2:
- getElementById: function (id) {
- var rtv = null;
- _visitNode(this.documentElement, function (node) {
- if (node.nodeType == ELEMENT_NODE) {
- if (node.getAttribute('id') == id) {
- rtv = node;
- return true;
- }
- }
- });
- return rtv;
- },
- /**
- * Creates a new `Element` that is owned by this `Document`.
- * In HTML Documents `localName` is the lower cased `tagName`,
- * otherwise no transformation is being applied.
- * When `contentType` implies the HTML namespace, it will be set as `namespaceURI`.
- *
- * __This implementation differs from the specification:__ - The provided name is not checked
- * against the `Name` production,
- * so no related error will be thrown.
- * - There is no interface `HTMLElement`, it is always an `Element`.
- * - There is no support for a second argument to indicate using custom elements.
- *
- * @param {string} tagName
- * @returns {Element}
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement
- * @see https://dom.spec.whatwg.org/#dom-document-createelement
- * @see https://dom.spec.whatwg.org/#concept-create-element
- */
- createElement: function (tagName) {
- var node = new Element(PDC);
- node.ownerDocument = this;
- if (this.type === 'html') {
- tagName = tagName.toLowerCase();
- }
- if (hasDefaultHTMLNamespace(this.contentType)) {
- node.namespaceURI = NAMESPACE.HTML;
- }
- node.nodeName = tagName;
- node.tagName = tagName;
- node.localName = tagName;
- node.childNodes = new NodeList();
- var attrs = (node.attributes = new NamedNodeMap());
- attrs._ownerElement = node;
- return node;
- },
- /**
- * @returns {DocumentFragment}
- */
- createDocumentFragment: function () {
- var node = new DocumentFragment(PDC);
- node.ownerDocument = this;
- node.childNodes = new NodeList();
- return node;
- },
- /**
- * @param {string} data
- * @returns {Text}
- */
- createTextNode: function (data) {
- var node = new Text(PDC);
- node.ownerDocument = this;
- node.childNodes = new NodeList();
- node.appendData(data);
- return node;
- },
- /**
- * @param {string} data
- * @returns {Comment}
- */
- createComment: function (data) {
- var node = new Comment(PDC);
- node.ownerDocument = this;
- node.childNodes = new NodeList();
- node.appendData(data);
- return node;
- },
- /**
- * @param {string} data
- * @returns {CDATASection}
- */
- createCDATASection: function (data) {
- var node = new CDATASection(PDC);
- node.ownerDocument = this;
- node.childNodes = new NodeList();
- node.appendData(data);
- return node;
- },
- /**
- * @param {string} target
- * @param {string} data
- * @returns {ProcessingInstruction}
- */
- createProcessingInstruction: function (target, data) {
- var node = new ProcessingInstruction(PDC);
- node.ownerDocument = this;
- node.childNodes = new NodeList();
- node.nodeName = node.target = target;
- node.nodeValue = node.data = data;
- return node;
- },
- /**
- * Creates an `Attr` node that is owned by this document.
- * In HTML Documents `localName` is the lower cased `name`,
- * otherwise no transformation is being applied.
- *
- * __This implementation differs from the specification:__ - The provided name is not checked
- * against the `Name` production,
- * so no related error will be thrown.
- *
- * @param {string} name
- * @returns {Attr}
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createAttribute
- * @see https://dom.spec.whatwg.org/#dom-document-createattribute
- */
- createAttribute: function (name) {
- if (!g.QName_exact.test(name)) {
- throw new DOMException(DOMException.INVALID_CHARACTER_ERR, 'invalid character in name "' + name + '"');
- }
- if (this.type === 'html') {
- name = name.toLowerCase();
- }
- return this._createAttribute(name);
- },
- _createAttribute: function (name) {
- var node = new Attr(PDC);
- node.ownerDocument = this;
- node.childNodes = new NodeList();
- node.name = name;
- node.nodeName = name;
- node.localName = name;
- node.specified = true;
- return node;
- },
- /**
- * Creates an EntityReference object.
- * The current implementation does not fill the `childNodes` with those of the corresponding
- * `Entity`
- *
- * @deprecated
- * In DOM Level 4.
- * @param {string} name
- * The name of the entity to reference. No namespace well-formedness checks are performed.
- * @returns {EntityReference}
- * @throws {DOMException}
- * With code `INVALID_CHARACTER_ERR` when `name` is not valid.
- * @throws {DOMException}
- * with code `NOT_SUPPORTED_ERR` when the document is of type `html`
- * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-392B75AE
- */
- createEntityReference: function (name) {
- if (!g.Name.test(name)) {
- throw new DOMException(DOMException.INVALID_CHARACTER_ERR, 'not a valid xml name "' + name + '"');
- }
- if (this.type === 'html') {
- throw new DOMException('document is an html document', DOMExceptionName.NotSupportedError);
- }
- var node = new EntityReference(PDC);
- node.ownerDocument = this;
- node.childNodes = new NodeList();
- node.nodeName = name;
- return node;
- },
- // Introduced in DOM Level 2:
- /**
- * @param {string} namespaceURI
- * @param {string} qualifiedName
- * @returns {Element}
- */
- createElementNS: function (namespaceURI, qualifiedName) {
- var validated = validateAndExtract(namespaceURI, qualifiedName);
- var node = new Element(PDC);
- var attrs = (node.attributes = new NamedNodeMap());
- node.childNodes = new NodeList();
- node.ownerDocument = this;
- node.nodeName = qualifiedName;
- node.tagName = qualifiedName;
- node.namespaceURI = validated[0];
- node.prefix = validated[1];
- node.localName = validated[2];
- attrs._ownerElement = node;
- return node;
- },
- // Introduced in DOM Level 2:
- /**
- * @param {string} namespaceURI
- * @param {string} qualifiedName
- * @returns {Attr}
- */
- createAttributeNS: function (namespaceURI, qualifiedName) {
- var validated = validateAndExtract(namespaceURI, qualifiedName);
- var node = new Attr(PDC);
- node.ownerDocument = this;
- node.childNodes = new NodeList();
- node.nodeName = qualifiedName;
- node.name = qualifiedName;
- node.specified = true;
- node.namespaceURI = validated[0];
- node.prefix = validated[1];
- node.localName = validated[2];
- return node;
- },
- };
- _extends(Document, Node);
- function Element(symbol) {
- checkSymbol(symbol);
- this._nsMap = Object.create(null);
- }
- Element.prototype = {
- nodeType: ELEMENT_NODE,
- /**
- * The attributes of this element.
- *
- * @type {NamedNodeMap | null}
- */
- attributes: null,
- getQualifiedName: function () {
- return this.prefix ? this.prefix + ':' + this.localName : this.localName;
- },
- _isInHTMLDocumentAndNamespace: function () {
- return this.ownerDocument.type === 'html' && this.namespaceURI === NAMESPACE.HTML;
- },
- /**
- * Implementaton of Level2 Core function hasAttributes.
- *
- * @returns {boolean}
- * True if attribute list is not empty.
- * @see https://www.w3.org/TR/DOM-Level-2-Core/#core-ID-NodeHasAttrs
- */
- hasAttributes: function () {
- return !!(this.attributes && this.attributes.length);
- },
- hasAttribute: function (name) {
- return !!this.getAttributeNode(name);
- },
- /**
- * Returns element’s first attribute whose qualified name is `name`, and `null`
- * if there is no such attribute.
- *
- * @param {string} name
- * @returns {string | null}
- */
- getAttribute: function (name) {
- var attr = this.getAttributeNode(name);
- return attr ? attr.value : null;
- },
- getAttributeNode: function (name) {
- if (this._isInHTMLDocumentAndNamespace()) {
- name = name.toLowerCase();
- }
- return this.attributes.getNamedItem(name);
- },
- /**
- * Sets the value of element’s first attribute whose qualified name is qualifiedName to value.
- *
- * @param {string} name
- * @param {string} value
- */
- setAttribute: function (name, value) {
- if (this._isInHTMLDocumentAndNamespace()) {
- name = name.toLowerCase();
- }
- var attr = this.getAttributeNode(name);
- if (attr) {
- attr.value = attr.nodeValue = '' + value;
- } else {
- attr = this.ownerDocument._createAttribute(name);
- attr.value = attr.nodeValue = '' + value;
- this.setAttributeNode(attr);
- }
- },
- removeAttribute: function (name) {
- var attr = this.getAttributeNode(name);
- attr && this.removeAttributeNode(attr);
- },
- setAttributeNode: function (newAttr) {
- return this.attributes.setNamedItem(newAttr);
- },
- setAttributeNodeNS: function (newAttr) {
- return this.attributes.setNamedItemNS(newAttr);
- },
- removeAttributeNode: function (oldAttr) {
- //console.log(this == oldAttr.ownerElement)
- return this.attributes.removeNamedItem(oldAttr.nodeName);
- },
- //get real attribute name,and remove it by removeAttributeNode
- removeAttributeNS: function (namespaceURI, localName) {
- var old = this.getAttributeNodeNS(namespaceURI, localName);
- old && this.removeAttributeNode(old);
- },
- hasAttributeNS: function (namespaceURI, localName) {
- return this.getAttributeNodeNS(namespaceURI, localName) != null;
- },
- /**
- * Returns element’s attribute whose namespace is `namespaceURI` and local name is
- * `localName`,
- * or `null` if there is no such attribute.
- *
- * @param {string} namespaceURI
- * @param {string} localName
- * @returns {string | null}
- */
- getAttributeNS: function (namespaceURI, localName) {
- var attr = this.getAttributeNodeNS(namespaceURI, localName);
- return attr ? attr.value : null;
- },
- /**
- * Sets the value of element’s attribute whose namespace is `namespaceURI` and local name is
- * `localName` to value.
- *
- * @param {string} namespaceURI
- * @param {string} qualifiedName
- * @param {string} value
- * @see https://dom.spec.whatwg.org/#dom-element-setattributens
- */
- setAttributeNS: function (namespaceURI, qualifiedName, value) {
- var validated = validateAndExtract(namespaceURI, qualifiedName);
- var localName = validated[2];
- var attr = this.getAttributeNodeNS(namespaceURI, localName);
- if (attr) {
- attr.value = attr.nodeValue = '' + value;
- } else {
- attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);
- attr.value = attr.nodeValue = '' + value;
- this.setAttributeNode(attr);
- }
- },
- getAttributeNodeNS: function (namespaceURI, localName) {
- return this.attributes.getNamedItemNS(namespaceURI, localName);
- },
- /**
- * Returns a LiveNodeList of all child elements which have **all** of the given class name(s).
- *
- * Returns an empty list if `classNames` is an empty string or only contains HTML white space
- * characters.
- *
- * Warning: This returns a live LiveNodeList.
- * Changes in the DOM will reflect in the array as the changes occur.
- * If an element selected by this array no longer qualifies for the selector,
- * it will automatically be removed. Be aware of this for iteration purposes.
- *
- * @param {string} classNames
- * Is a string representing the class name(s) to match; multiple class names are separated by
- * (ASCII-)whitespace.
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByClassName
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName
- * @see https://dom.spec.whatwg.org/#concept-getelementsbyclassname
- */
- getElementsByClassName: function (classNames) {
- var classNamesSet = toOrderedSet(classNames);
- return new LiveNodeList(this, function (base) {
- var ls = [];
- if (classNamesSet.length > 0) {
- _visitNode(base, function (node) {
- if (node !== base && node.nodeType === ELEMENT_NODE) {
- var nodeClassNames = node.getAttribute('class');
- // can be null if the attribute does not exist
- if (nodeClassNames) {
- // before splitting and iterating just compare them for the most common case
- var matches = classNames === nodeClassNames;
- if (!matches) {
- var nodeClassNamesSet = toOrderedSet(nodeClassNames);
- matches = classNamesSet.every(arrayIncludes(nodeClassNamesSet));
- }
- if (matches) {
- ls.push(node);
- }
- }
- }
- });
- }
- return ls;
- });
- },
- /**
- * Returns a LiveNodeList of elements with the given qualifiedName.
- * Searching for all descendants can be done by passing `*` as `qualifiedName`.
- *
- * All descendants of the specified element are searched, but not the element itself.
- * The returned list is live, which means it updates itself with the DOM tree automatically.
- * Therefore, there is no need to call `Element.getElementsByTagName()`
- * with the same element and arguments repeatedly if the DOM changes in between calls.
- *
- * When called on an HTML element in an HTML document,
- * `getElementsByTagName` lower-cases the argument before searching for it.
- * This is undesirable when trying to match camel-cased SVG elements (such as
- * `<linearGradient>`) in an HTML document.
- * Instead, use `Element.getElementsByTagNameNS()`,
- * which preserves the capitalization of the tag name.
- *
- * `Element.getElementsByTagName` is similar to `Document.getElementsByTagName()`,
- * except that it only searches for elements that are descendants of the specified element.
- *
- * @param {string} qualifiedName
- * @returns {LiveNodeList}
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByTagName
- * @see https://dom.spec.whatwg.org/#concept-getelementsbytagname
- */
- getElementsByTagName: function (qualifiedName) {
- var isHTMLDocument = (this.nodeType === DOCUMENT_NODE ? this : this.ownerDocument).type === 'html';
- var lowerQualifiedName = qualifiedName.toLowerCase();
- return new LiveNodeList(this, function (base) {
- var ls = [];
- _visitNode(base, function (node) {
- if (node === base || node.nodeType !== ELEMENT_NODE) {
- return;
- }
- if (qualifiedName === '*') {
- ls.push(node);
- } else {
- var nodeQualifiedName = node.getQualifiedName();
- var matchingQName = isHTMLDocument && node.namespaceURI === NAMESPACE.HTML ? lowerQualifiedName : qualifiedName;
- if (nodeQualifiedName === matchingQName) {
- ls.push(node);
- }
- }
- });
- return ls;
- });
- },
- getElementsByTagNameNS: function (namespaceURI, localName) {
- return new LiveNodeList(this, function (base) {
- var ls = [];
- _visitNode(base, function (node) {
- if (
- node !== base &&
- node.nodeType === ELEMENT_NODE &&
- (namespaceURI === '*' || node.namespaceURI === namespaceURI) &&
- (localName === '*' || node.localName == localName)
- ) {
- ls.push(node);
- }
- });
- return ls;
- });
- },
- };
- Document.prototype.getElementsByClassName = Element.prototype.getElementsByClassName;
- Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;
- Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;
- _extends(Element, Node);
- function Attr(symbol) {
- checkSymbol(symbol);
- this.namespaceURI = null;
- this.prefix = null;
- this.ownerElement = null;
- }
- Attr.prototype.nodeType = ATTRIBUTE_NODE;
- _extends(Attr, Node);
- function CharacterData(symbol) {
- checkSymbol(symbol);
- }
- CharacterData.prototype = {
- data: '',
- substringData: function (offset, count) {
- return this.data.substring(offset, offset + count);
- },
- appendData: function (text) {
- text = this.data + text;
- this.nodeValue = this.data = text;
- this.length = text.length;
- },
- insertData: function (offset, text) {
- this.replaceData(offset, 0, text);
- },
- deleteData: function (offset, count) {
- this.replaceData(offset, count, '');
- },
- replaceData: function (offset, count, text) {
- var start = this.data.substring(0, offset);
- var end = this.data.substring(offset + count);
- text = start + text + end;
- this.nodeValue = this.data = text;
- this.length = text.length;
- },
- };
- _extends(CharacterData, Node);
- function Text(symbol) {
- checkSymbol(symbol);
- }
- Text.prototype = {
- nodeName: '#text',
- nodeType: TEXT_NODE,
- splitText: function (offset) {
- var text = this.data;
- var newText = text.substring(offset);
- text = text.substring(0, offset);
- this.data = this.nodeValue = text;
- this.length = text.length;
- var newNode = this.ownerDocument.createTextNode(newText);
- if (this.parentNode) {
- this.parentNode.insertBefore(newNode, this.nextSibling);
- }
- return newNode;
- },
- };
- _extends(Text, CharacterData);
- function Comment(symbol) {
- checkSymbol(symbol);
- }
- Comment.prototype = {
- nodeName: '#comment',
- nodeType: COMMENT_NODE,
- };
- _extends(Comment, CharacterData);
- function CDATASection(symbol) {
- checkSymbol(symbol);
- }
- CDATASection.prototype = {
- nodeName: '#cdata-section',
- nodeType: CDATA_SECTION_NODE,
- };
- _extends(CDATASection, Text);
- function DocumentType(symbol) {
- checkSymbol(symbol);
- }
- DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
- _extends(DocumentType, Node);
- function Notation(symbol) {
- checkSymbol(symbol);
- }
- Notation.prototype.nodeType = NOTATION_NODE;
- _extends(Notation, Node);
- function Entity(symbol) {
- checkSymbol(symbol);
- }
- Entity.prototype.nodeType = ENTITY_NODE;
- _extends(Entity, Node);
- function EntityReference(symbol) {
- checkSymbol(symbol);
- }
- EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
- _extends(EntityReference, Node);
- function DocumentFragment(symbol) {
- checkSymbol(symbol);
- }
- DocumentFragment.prototype.nodeName = '#document-fragment';
- DocumentFragment.prototype.nodeType = DOCUMENT_FRAGMENT_NODE;
- _extends(DocumentFragment, Node);
- function ProcessingInstruction(symbol) {
- checkSymbol(symbol);
- }
- ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
- _extends(ProcessingInstruction, CharacterData);
- function XMLSerializer() {}
- XMLSerializer.prototype.serializeToString = function (node, nodeFilter) {
- return nodeSerializeToString.call(node, nodeFilter);
- };
- Node.prototype.toString = nodeSerializeToString;
- function nodeSerializeToString(nodeFilter) {
- var buf = [];
- var refNode = (this.nodeType === DOCUMENT_NODE && this.documentElement) || this;
- var prefix = refNode.prefix;
- var uri = refNode.namespaceURI;
- if (uri && prefix == null) {
- var prefix = refNode.lookupPrefix(uri);
- if (prefix == null) {
- var visibleNamespaces = [
- { namespace: uri, prefix: null },
- //{namespace:uri,prefix:''}
- ];
- }
- }
- serializeToString(this, buf, nodeFilter, visibleNamespaces);
- return buf.join('');
- }
- function needNamespaceDefine(node, isHTML, visibleNamespaces) {
- var prefix = node.prefix || '';
- var uri = node.namespaceURI;
- // According to [Namespaces in XML 1.0](https://www.w3.org/TR/REC-xml-names/#ns-using) ,
- // and more specifically https://www.w3.org/TR/REC-xml-names/#nsc-NoPrefixUndecl :
- // > In a namespace declaration for a prefix [...], the attribute value MUST NOT be empty.
- // in a similar manner [Namespaces in XML 1.1](https://www.w3.org/TR/xml-names11/#ns-using)
- // and more specifically https://www.w3.org/TR/xml-names11/#nsc-NSDeclared :
- // > [...] Furthermore, the attribute value [...] must not be an empty string.
- // so serializing empty namespace value like xmlns:ds="" would produce an invalid XML document.
- if (!uri) {
- return false;
- }
- if ((prefix === 'xml' && uri === NAMESPACE.XML) || uri === NAMESPACE.XMLNS) {
- return false;
- }
- var i = visibleNamespaces.length;
- while (i--) {
- var ns = visibleNamespaces[i];
- // get namespace prefix
- if (ns.prefix === prefix) {
- return ns.namespace !== uri;
- }
- }
- return true;
- }
- /**
- * Literal whitespace other than space that appear in attribute values are serialized as
- * their entity references, so they will be preserved.
- * (In contrast to whitespace literals in the input which are normalized to spaces).
- *
- * Well-formed constraint: No < in Attribute Values:
- * > The replacement text of any entity referred to directly or indirectly
- * > in an attribute value must not contain a <.
- *
- * @see https://www.w3.org/TR/xml11/#CleanAttrVals
- * @see https://www.w3.org/TR/xml11/#NT-AttValue
- * @see https://www.w3.org/TR/xml11/#AVNormalize
- * @see https://w3c.github.io/DOM-Parsing/#serializing-an-element-s-attributes
- * @prettierignore
- */
- function addSerializedAttribute(buf, qualifiedName, value) {
- buf.push(' ', qualifiedName, '="', value.replace(/[<>&"\t\n\r]/g, _xmlEncoder), '"');
- }
- function serializeToString(node, buf, nodeFilter, visibleNamespaces) {
- if (!visibleNamespaces) {
- visibleNamespaces = [];
- }
- var doc = node.nodeType === DOCUMENT_NODE ? node : node.ownerDocument;
- var isHTML = doc.type === 'html';
- if (nodeFilter) {
- node = nodeFilter(node);
- if (node) {
- if (typeof node == 'string') {
- buf.push(node);
- return;
- }
- } else {
- return;
- }
- //buf.sort.apply(attrs, attributeSorter);
- }
- switch (node.nodeType) {
- case ELEMENT_NODE:
- var attrs = node.attributes;
- var len = attrs.length;
- var child = node.firstChild;
- var nodeName = node.tagName;
- var prefixedNodeName = nodeName;
- if (!isHTML && !node.prefix && node.namespaceURI) {
- var defaultNS;
- // lookup current default ns from `xmlns` attribute
- for (var ai = 0; ai < attrs.length; ai++) {
- if (attrs.item(ai).name === 'xmlns') {
- defaultNS = attrs.item(ai).value;
- break;
- }
- }
- if (!defaultNS) {
- // lookup current default ns in visibleNamespaces
- for (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) {
- var namespace = visibleNamespaces[nsi];
- if (namespace.prefix === '' && namespace.namespace === node.namespaceURI) {
- defaultNS = namespace.namespace;
- break;
- }
- }
- }
- if (defaultNS !== node.namespaceURI) {
- for (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) {
- var namespace = visibleNamespaces[nsi];
- if (namespace.namespace === node.namespaceURI) {
- if (namespace.prefix) {
- prefixedNodeName = namespace.prefix + ':' + nodeName;
- }
- break;
- }
- }
- }
- }
- buf.push('<', prefixedNodeName);
- for (var i = 0; i < len; i++) {
- // add namespaces for attributes
- var attr = attrs.item(i);
- if (attr.prefix == 'xmlns') {
- visibleNamespaces.push({
- prefix: attr.localName,
- namespace: attr.value,
- });
- } else if (attr.nodeName == 'xmlns') {
- visibleNamespaces.push({ prefix: '', namespace: attr.value });
- }
- }
- for (var i = 0; i < len; i++) {
- var attr = attrs.item(i);
- if (needNamespaceDefine(attr, isHTML, visibleNamespaces)) {
- var prefix = attr.prefix || '';
- var uri = attr.namespaceURI;
- addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : 'xmlns', uri);
- visibleNamespaces.push({ prefix: prefix, namespace: uri });
- }
- serializeToString(attr, buf, nodeFilter, visibleNamespaces);
- }
- // add namespace for current node
- if (nodeName === prefixedNodeName && needNamespaceDefine(node, isHTML, visibleNamespaces)) {
- var prefix = node.prefix || '';
- var uri = node.namespaceURI;
- addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : 'xmlns', uri);
- visibleNamespaces.push({ prefix: prefix, namespace: uri });
- }
- // in XML elements can be closed when they have no children
- var canCloseTag = !child;
- if (canCloseTag && (isHTML || node.namespaceURI === NAMESPACE.HTML)) {
- // in HTML (doc or ns) only void elements can be closed right away
- canCloseTag = isHTMLVoidElement(nodeName);
- }
- if (canCloseTag) {
- buf.push('/>');
- } else {
- buf.push('>');
- //if is cdata child node
- if (isHTML && isHTMLRawTextElement(nodeName)) {
- while (child) {
- if (child.data) {
- buf.push(child.data);
- } else {
- serializeToString(child, buf, nodeFilter, visibleNamespaces.slice());
- }
- child = child.nextSibling;
- }
- } else {
- while (child) {
- serializeToString(child, buf, nodeFilter, visibleNamespaces.slice());
- child = child.nextSibling;
- }
- }
- buf.push('</', prefixedNodeName, '>');
- }
- // remove added visible namespaces
- //visibleNamespaces.length = startVisibleNamespaces;
- return;
- case DOCUMENT_NODE:
- case DOCUMENT_FRAGMENT_NODE:
- var child = node.firstChild;
- while (child) {
- serializeToString(child, buf, nodeFilter, visibleNamespaces.slice());
- child = child.nextSibling;
- }
- return;
- case ATTRIBUTE_NODE:
- return addSerializedAttribute(buf, node.name, node.value);
- case TEXT_NODE:
- /*
- * The ampersand character (&) and the left angle bracket (<) must not appear in their literal form,
- * except when used as markup delimiters, or within a comment, a processing instruction,
- * or a CDATA section.
- * If they are needed elsewhere, they must be escaped using either numeric character
- * references or the strings `&` and `<` respectively.
- * The right angle bracket (>) may be represented using the string " > ",
- * and must, for compatibility, be escaped using either `>`,
- * or a character reference when it appears in the string `]]>` in content,
- * when that string is not marking the end of a CDATA section.
- *
- * In the content of elements, character data is any string of characters which does not
- * contain the start-delimiter of any markup and does not include the CDATA-section-close
- * delimiter, `]]>`.
- *
- * @see https://www.w3.org/TR/xml/#NT-CharData
- * @see https://w3c.github.io/DOM-Parsing/#xml-serializing-a-text-node
- */
- return buf.push(node.data.replace(/[<&>]/g, _xmlEncoder));
- case CDATA_SECTION_NODE:
- return buf.push(g.CDATA_START, node.data, g.CDATA_END);
- case COMMENT_NODE:
- return buf.push(g.COMMENT_START, node.data, g.COMMENT_END);
- case DOCUMENT_TYPE_NODE:
- var pubid = node.publicId;
- var sysid = node.systemId;
- buf.push(g.DOCTYPE_DECL_START, ' ', node.name);
- if (pubid) {
- buf.push(' ', g.PUBLIC, ' ', pubid);
- if (sysid && sysid !== '.') {
- buf.push(' ', sysid);
- }
- } else if (sysid && sysid !== '.') {
- buf.push(' ', g.SYSTEM, ' ', sysid);
- }
- if (node.internalSubset) {
- buf.push(' [', node.internalSubset, ']');
- }
- buf.push('>');
- return;
- case PROCESSING_INSTRUCTION_NODE:
- return buf.push('<?', node.target, ' ', node.data, '?>');
- case ENTITY_REFERENCE_NODE:
- return buf.push('&', node.nodeName, ';');
- //case ENTITY_NODE:
- //case NOTATION_NODE:
- default:
- buf.push('??', node.nodeName);
- }
- }
- function importNode(doc, node, deep) {
- var node2;
- switch (node.nodeType) {
- case ELEMENT_NODE:
- node2 = node.cloneNode(false);
- node2.ownerDocument = doc;
- //var attrs = node2.attributes;
- //var len = attrs.length;
- //for(var i=0;i<len;i++){
- //node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));
- //}
- case DOCUMENT_FRAGMENT_NODE:
- break;
- case ATTRIBUTE_NODE:
- deep = true;
- break;
- //case ENTITY_REFERENCE_NODE:
- //case PROCESSING_INSTRUCTION_NODE:
- ////case TEXT_NODE:
- //case CDATA_SECTION_NODE:
- //case COMMENT_NODE:
- // deep = false;
- // break;
- //case DOCUMENT_NODE:
- //case DOCUMENT_TYPE_NODE:
- //cannot be imported.
- //case ENTITY_NODE:
- //case NOTATION_NODE:
- //can not hit in level3
- //default:throw e;
- }
- if (!node2) {
- node2 = node.cloneNode(false); //false
- }
- node2.ownerDocument = doc;
- node2.parentNode = null;
- if (deep) {
- var child = node.firstChild;
- while (child) {
- node2.appendChild(importNode(doc, child, deep));
- child = child.nextSibling;
- }
- }
- return node2;
- }
- /**
- * Creates a copy of a node from an existing one.
- *
- * @param {Document} doc
- * The Document object representing the document that the new node will belong to.
- * @param {Node} node
- * The node to clone.
- * @param {boolean} deep
- * If true, the contents of the node are recursively copied.
- * If false, only the node itself (and its attributes, if it is an element) are copied.
- * @returns {Node}
- * Returns the newly created copy of the node.
- * @throws {DOMException}
- * May throw a DOMException if operations within setAttributeNode or appendChild (which are
- * potentially invoked in this function) do not meet their specific constraints.
- */
- function cloneNode(doc, node, deep) {
- var node2 = new node.constructor(PDC);
- for (var n in node) {
- if (hasOwn(node, n)) {
- var v = node[n];
- if (typeof v != 'object') {
- if (v != node2[n]) {
- node2[n] = v;
- }
- }
- }
- }
- if (node.childNodes) {
- node2.childNodes = new NodeList();
- }
- node2.ownerDocument = doc;
- switch (node2.nodeType) {
- case ELEMENT_NODE:
- var attrs = node.attributes;
- var attrs2 = (node2.attributes = new NamedNodeMap());
- var len = attrs.length;
- attrs2._ownerElement = node2;
- for (var i = 0; i < len; i++) {
- node2.setAttributeNode(cloneNode(doc, attrs.item(i), true));
- }
- break;
- case ATTRIBUTE_NODE:
- deep = true;
- }
- if (deep) {
- var child = node.firstChild;
- while (child) {
- node2.appendChild(cloneNode(doc, child, deep));
- child = child.nextSibling;
- }
- }
- return node2;
- }
- function __set__(object, key, value) {
- object[key] = value;
- }
- //do dynamic
- try {
- if (Object.defineProperty) {
- Object.defineProperty(LiveNodeList.prototype, 'length', {
- get: function () {
- _updateLiveList(this);
- return this.$$length;
- },
- });
- Object.defineProperty(Node.prototype, 'textContent', {
- get: function () {
- return getTextContent(this);
- },
- set: function (data) {
- switch (this.nodeType) {
- case ELEMENT_NODE:
- case DOCUMENT_FRAGMENT_NODE:
- while (this.firstChild) {
- this.removeChild(this.firstChild);
- }
- if (data || String(data)) {
- this.appendChild(this.ownerDocument.createTextNode(data));
- }
- break;
- default:
- this.data = data;
- this.value = data;
- this.nodeValue = data;
- }
- },
- });
- function getTextContent(node) {
- switch (node.nodeType) {
- case ELEMENT_NODE:
- case DOCUMENT_FRAGMENT_NODE:
- var buf = [];
- node = node.firstChild;
- while (node) {
- if (node.nodeType !== 7 && node.nodeType !== 8) {
- buf.push(getTextContent(node));
- }
- node = node.nextSibling;
- }
- return buf.join('');
- default:
- return node.nodeValue;
- }
- }
- __set__ = function (object, key, value) {
- //console.log(value)
- object['$$' + key] = value;
- };
- }
- } catch (e) {
- //ie8
- }
- exports._updateLiveList = _updateLiveList;
- exports.Attr = Attr;
- exports.CDATASection = CDATASection;
- exports.CharacterData = CharacterData;
- exports.Comment = Comment;
- exports.Document = Document;
- exports.DocumentFragment = DocumentFragment;
- exports.DocumentType = DocumentType;
- exports.DOMImplementation = DOMImplementation;
- exports.Element = Element;
- exports.Entity = Entity;
- exports.EntityReference = EntityReference;
- exports.LiveNodeList = LiveNodeList;
- exports.NamedNodeMap = NamedNodeMap;
- exports.Node = Node;
- exports.NodeList = NodeList;
- exports.Notation = Notation;
- exports.Text = Text;
- exports.ProcessingInstruction = ProcessingInstruction;
- exports.XMLSerializer = XMLSerializer;
|