@xmldom/xmldom 0.9.0-beta.1 → 0.9.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/dom.js CHANGED
@@ -1,27 +1,33 @@
1
- var conventions = require("./conventions");
1
+ 'use strict';
2
+
3
+ var conventions = require('./conventions');
4
+ var find = conventions.find;
5
+ var hasDefaultHTMLNamespace = conventions.hasDefaultHTMLNamespace;
6
+ var isHTMLMimeType = conventions.isHTMLMimeType;
2
7
  var isHTMLRawTextElement = conventions.isHTMLRawTextElement;
3
8
  var isHTMLVoidElement = conventions.isHTMLVoidElement;
4
9
  var MIME_TYPE = conventions.MIME_TYPE;
5
10
  var NAMESPACE = conventions.NAMESPACE;
11
+ var g = require('./grammar');
6
12
 
7
13
  /**
8
- * A prerequisite for `[].filter`, to drop elements that are empty
14
+ * A prerequisite for `[].filter`, to drop elements that are empty.
15
+ *
9
16
  * @param {string} input
10
17
  * @returns {boolean}
11
18
  */
12
- function notEmptyString (input) {
13
- return input !== ''
19
+ function notEmptyString(input) {
20
+ return input !== '';
14
21
  }
15
22
  /**
16
- * @see https://infra.spec.whatwg.org/#split-on-ascii-whitespace
17
- * @see https://infra.spec.whatwg.org/#ascii-whitespace
18
- *
19
23
  * @param {string} input
20
24
  * @returns {string[]} (can be empty)
25
+ * @see https://infra.spec.whatwg.org/#split-on-ascii-whitespace
26
+ * @see https://infra.spec.whatwg.org/#ascii-whitespace
21
27
  */
22
28
  function splitOnASCIIWhitespace(input) {
23
29
  // U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, U+0020 SPACE
24
- return input ? input.split(/[\t\n\f\r ]+/).filter(notEmptyString) : []
30
+ return input ? input.split(/[\t\n\f\r ]+/).filter(notEmptyString) : [];
25
31
  }
26
32
 
27
33
  /**
@@ -31,7 +37,7 @@ function splitOnASCIIWhitespace(input) {
31
37
  * @param {string} element
32
38
  * @returns {Record<string, boolean | undefined>}
33
39
  */
34
- function orderedSetReducer (current, element) {
40
+ function orderedSetReducer(current, element) {
35
41
  if (!current.hasOwnProperty(element)) {
36
42
  current[element] = true;
37
43
  }
@@ -39,14 +45,14 @@ function orderedSetReducer (current, element) {
39
45
  }
40
46
 
41
47
  /**
42
- * @see https://infra.spec.whatwg.org/#ordered-set
43
48
  * @param {string} input
44
49
  * @returns {string[]}
50
+ * @see https://infra.spec.whatwg.org/#ordered-set
45
51
  */
46
52
  function toOrderedSet(input) {
47
53
  if (!input) return [];
48
54
  var list = splitOnASCIIWhitespace(input);
49
- return Object.keys(list.reduce(orderedSetReducer, {}))
55
+ return Object.keys(list.reduce(orderedSetReducer, {}));
50
56
  }
51
57
 
52
58
  /**
@@ -56,15 +62,62 @@ function toOrderedSet(input) {
56
62
  * @param {any[]} list
57
63
  * @returns {function(any): boolean}
58
64
  */
59
- function arrayIncludes (list) {
60
- return function(element) {
65
+ function arrayIncludes(list) {
66
+ return function (element) {
61
67
  return list && list.indexOf(element) !== -1;
68
+ };
69
+ }
70
+
71
+ /**
72
+ * @param {string} qualifiedName
73
+ * @throws {DOMException}
74
+ * @see https://dom.spec.whatwg.org/#validate
75
+ */
76
+ function validateQualifiedName(qualifiedName) {
77
+ if (!g.QName_exact.test(qualifiedName)) {
78
+ throw new DOMException(INVALID_CHARACTER_ERR, 'invalid character in qualified name "' + qualifiedName + '"');
62
79
  }
63
80
  }
64
81
 
65
- function copy(src,dest){
66
- for(var p in src){
67
- dest[p] = src[p];
82
+ /**
83
+ * @param {string | null} namespace
84
+ * @param {string} qualifiedName
85
+ * @returns {[namespace: string | null, prefix: string | null, localName: string]}
86
+ * @see https://dom.spec.whatwg.org/#validate-and-extract
87
+ */
88
+ function validateAndExtract(namespace, qualifiedName) {
89
+ validateQualifiedName(qualifiedName);
90
+ namespace = namespace || null;
91
+ /**
92
+ * @type {string | null}
93
+ */
94
+ var prefix = null;
95
+ var localName = qualifiedName;
96
+ if (qualifiedName.indexOf(':') >= 0) {
97
+ var splitResult = qualifiedName.split(':');
98
+ prefix = splitResult[0];
99
+ localName = splitResult[1];
100
+ }
101
+ if (prefix !== null && namespace === null) {
102
+ throw new DOMException(NAMESPACE_ERR, 'prefix is non-null and namespace is null');
103
+ }
104
+ if (prefix === 'xml' && namespace !== conventions.NAMESPACE.XML) {
105
+ throw new DOMException(NAMESPACE_ERR, 'prefix is "xml" and namespace is not the XML namespace');
106
+ }
107
+ if ((prefix === 'xmlns' || qualifiedName === 'xmlns') && namespace !== conventions.NAMESPACE.XMLNS) {
108
+ throw new DOMException(NAMESPACE_ERR, 'either qualifiedName or prefix is "xmlns" and namespace is not the XMLNS namespace');
109
+ }
110
+ if (namespace === conventions.NAMESPACE.XMLNS && prefix !== 'xmlns' && qualifiedName !== 'xmlns') {
111
+ throw new DOMException(NAMESPACE_ERR, 'namespace is the XMLNS namespace and neither qualifiedName nor prefix is "xmlns"');
112
+ }
113
+ return [namespace, prefix, localName];
114
+ }
115
+
116
+ function copy(src, dest) {
117
+ for (var p in src) {
118
+ if (Object.prototype.hasOwnProperty.call(src, p)) {
119
+ dest[p] = src[p];
120
+ }
68
121
  }
69
122
  }
70
123
 
@@ -72,330 +125,471 @@ function copy(src,dest){
72
125
  ^\w+\.prototype\.([_\w]+)\s*=\s*((?:.*\{\s*?[\r\n][\s\S]*?^})|\S.*?(?=[;\r\n]));?
73
126
  ^\w+\.prototype\.([_\w]+)\s*=\s*(\S.*?(?=[;\r\n]));?
74
127
  */
75
- function _extends(Class,Super){
128
+ function _extends(Class, Super) {
76
129
  var pt = Class.prototype;
77
- if(!(pt instanceof Super)){
78
- function t(){};
130
+ if (!(pt instanceof Super)) {
131
+ function t() {}
79
132
  t.prototype = Super.prototype;
80
133
  t = new t();
81
- copy(pt,t);
134
+ copy(pt, t);
82
135
  Class.prototype = pt = t;
83
136
  }
84
- if(pt.constructor != Class){
85
- if(typeof Class != 'function'){
86
- console.error("unknown Class:"+Class)
137
+ if (pt.constructor != Class) {
138
+ if (typeof Class != 'function') {
139
+ console.error('unknown Class:' + Class);
87
140
  }
88
- pt.constructor = Class
141
+ pt.constructor = Class;
89
142
  }
90
143
  }
91
144
 
92
145
  // Node Types
93
- var NodeType = {}
94
- var ELEMENT_NODE = NodeType.ELEMENT_NODE = 1;
95
- var ATTRIBUTE_NODE = NodeType.ATTRIBUTE_NODE = 2;
96
- var TEXT_NODE = NodeType.TEXT_NODE = 3;
97
- var CDATA_SECTION_NODE = NodeType.CDATA_SECTION_NODE = 4;
98
- var ENTITY_REFERENCE_NODE = NodeType.ENTITY_REFERENCE_NODE = 5;
99
- var ENTITY_NODE = NodeType.ENTITY_NODE = 6;
100
- var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;
101
- var COMMENT_NODE = NodeType.COMMENT_NODE = 8;
102
- var DOCUMENT_NODE = NodeType.DOCUMENT_NODE = 9;
103
- var DOCUMENT_TYPE_NODE = NodeType.DOCUMENT_TYPE_NODE = 10;
104
- var DOCUMENT_FRAGMENT_NODE = NodeType.DOCUMENT_FRAGMENT_NODE = 11;
105
- var NOTATION_NODE = NodeType.NOTATION_NODE = 12;
146
+ var NodeType = {};
147
+ var ELEMENT_NODE = (NodeType.ELEMENT_NODE = 1);
148
+ var ATTRIBUTE_NODE = (NodeType.ATTRIBUTE_NODE = 2);
149
+ var TEXT_NODE = (NodeType.TEXT_NODE = 3);
150
+ var CDATA_SECTION_NODE = (NodeType.CDATA_SECTION_NODE = 4);
151
+ var ENTITY_REFERENCE_NODE = (NodeType.ENTITY_REFERENCE_NODE = 5);
152
+ var ENTITY_NODE = (NodeType.ENTITY_NODE = 6);
153
+ var PROCESSING_INSTRUCTION_NODE = (NodeType.PROCESSING_INSTRUCTION_NODE = 7);
154
+ var COMMENT_NODE = (NodeType.COMMENT_NODE = 8);
155
+ var DOCUMENT_NODE = (NodeType.DOCUMENT_NODE = 9);
156
+ var DOCUMENT_TYPE_NODE = (NodeType.DOCUMENT_TYPE_NODE = 10);
157
+ var DOCUMENT_FRAGMENT_NODE = (NodeType.DOCUMENT_FRAGMENT_NODE = 11);
158
+ var NOTATION_NODE = (NodeType.NOTATION_NODE = 12);
106
159
 
107
160
  // ExceptionCode
108
- var ExceptionCode = {}
161
+ var ExceptionCode = {};
109
162
  var ExceptionMessage = {};
110
- var INDEX_SIZE_ERR = ExceptionCode.INDEX_SIZE_ERR = ((ExceptionMessage[1]="Index size error"),1);
111
- var DOMSTRING_SIZE_ERR = ExceptionCode.DOMSTRING_SIZE_ERR = ((ExceptionMessage[2]="DOMString size error"),2);
112
- var HIERARCHY_REQUEST_ERR = ExceptionCode.HIERARCHY_REQUEST_ERR = ((ExceptionMessage[3]="Hierarchy request error"),3);
113
- var WRONG_DOCUMENT_ERR = ExceptionCode.WRONG_DOCUMENT_ERR = ((ExceptionMessage[4]="Wrong document"),4);
114
- var INVALID_CHARACTER_ERR = ExceptionCode.INVALID_CHARACTER_ERR = ((ExceptionMessage[5]="Invalid character"),5);
115
- var NO_DATA_ALLOWED_ERR = ExceptionCode.NO_DATA_ALLOWED_ERR = ((ExceptionMessage[6]="No data allowed"),6);
116
- var NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = ((ExceptionMessage[7]="No modification allowed"),7);
117
- var NOT_FOUND_ERR = ExceptionCode.NOT_FOUND_ERR = ((ExceptionMessage[8]="Not found"),8);
118
- var NOT_SUPPORTED_ERR = ExceptionCode.NOT_SUPPORTED_ERR = ((ExceptionMessage[9]="Not supported"),9);
119
- var INUSE_ATTRIBUTE_ERR = ExceptionCode.INUSE_ATTRIBUTE_ERR = ((ExceptionMessage[10]="Attribute in use"),10);
163
+ var INDEX_SIZE_ERR = (ExceptionCode.INDEX_SIZE_ERR = ((ExceptionMessage[1] = 'Index size error'), 1));
164
+ var DOMSTRING_SIZE_ERR = (ExceptionCode.DOMSTRING_SIZE_ERR = ((ExceptionMessage[2] = 'DOMString size error'), 2));
165
+ var HIERARCHY_REQUEST_ERR = (ExceptionCode.HIERARCHY_REQUEST_ERR = ((ExceptionMessage[3] = 'Hierarchy request error'), 3));
166
+ var WRONG_DOCUMENT_ERR = (ExceptionCode.WRONG_DOCUMENT_ERR = ((ExceptionMessage[4] = 'Wrong document'), 4));
167
+ var INVALID_CHARACTER_ERR = (ExceptionCode.INVALID_CHARACTER_ERR = ((ExceptionMessage[5] = 'Invalid character'), 5));
168
+ var NO_DATA_ALLOWED_ERR = (ExceptionCode.NO_DATA_ALLOWED_ERR = ((ExceptionMessage[6] = 'No data allowed'), 6));
169
+ var NO_MODIFICATION_ALLOWED_ERR = (ExceptionCode.NO_MODIFICATION_ALLOWED_ERR =
170
+ ((ExceptionMessage[7] = 'No modification allowed'), 7));
171
+ var NOT_FOUND_ERR = (ExceptionCode.NOT_FOUND_ERR = ((ExceptionMessage[8] = 'Not found'), 8));
172
+ var NOT_SUPPORTED_ERR = (ExceptionCode.NOT_SUPPORTED_ERR = ((ExceptionMessage[9] = 'Not supported'), 9));
173
+ var INUSE_ATTRIBUTE_ERR = (ExceptionCode.INUSE_ATTRIBUTE_ERR = ((ExceptionMessage[10] = 'Attribute in use'), 10));
120
174
  //level2
121
- var INVALID_STATE_ERR = ExceptionCode.INVALID_STATE_ERR = ((ExceptionMessage[11]="Invalid state"),11);
122
- var SYNTAX_ERR = ExceptionCode.SYNTAX_ERR = ((ExceptionMessage[12]="Syntax error"),12);
123
- var INVALID_MODIFICATION_ERR = ExceptionCode.INVALID_MODIFICATION_ERR = ((ExceptionMessage[13]="Invalid modification"),13);
124
- var NAMESPACE_ERR = ExceptionCode.NAMESPACE_ERR = ((ExceptionMessage[14]="Invalid namespace"),14);
125
- var INVALID_ACCESS_ERR = ExceptionCode.INVALID_ACCESS_ERR = ((ExceptionMessage[15]="Invalid access"),15);
175
+ var INVALID_STATE_ERR = (ExceptionCode.INVALID_STATE_ERR = ((ExceptionMessage[11] = 'Invalid state'), 11));
176
+ var SYNTAX_ERR = (ExceptionCode.SYNTAX_ERR = ((ExceptionMessage[12] = 'Syntax error'), 12));
177
+ var INVALID_MODIFICATION_ERR = (ExceptionCode.INVALID_MODIFICATION_ERR = ((ExceptionMessage[13] = 'Invalid modification'), 13));
178
+ var NAMESPACE_ERR = (ExceptionCode.NAMESPACE_ERR = ((ExceptionMessage[14] = 'Invalid namespace'), 14));
179
+ var INVALID_ACCESS_ERR = (ExceptionCode.INVALID_ACCESS_ERR = ((ExceptionMessage[15] = 'Invalid access'), 15));
180
+
181
+ // compareDocumentPosition bitmask results
182
+ var DocumentPosition = {};
183
+ var DOCUMENT_POSITION_DISCONNECTED = (DocumentPosition.DOCUMENT_POSITION_DISCONNECTED = 1);
184
+ var DOCUMENT_POSITION_PRECEDING = (DocumentPosition.DOCUMENT_POSITION_PRECEDING = 2);
185
+ var DOCUMENT_POSITION_FOLLOWING = (DocumentPosition.DOCUMENT_POSITION_FOLLOWING = 4);
186
+ var DOCUMENT_POSITION_CONTAINS = (DocumentPosition.DOCUMENT_POSITION_CONTAINS = 8);
187
+ var DOCUMENT_POSITION_CONTAINED_BY = (DocumentPosition.DOCUMENT_POSITION_CONTAINED_BY = 16);
188
+ var DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = (DocumentPosition.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 32);
189
+
190
+ //helper functions for compareDocumentPosition
191
+ /**
192
+ * Construct a parent chain for a node.
193
+ *
194
+ * @param {Node} node
195
+ * The start node.
196
+ * @returns {Node[]} The parent chain.
197
+ */
198
+ function parentChain(node) {
199
+ var chain = [];
200
+ while (node.parentNode || node.ownerElement) {
201
+ node = node.parentNode || node.ownerElement;
202
+ chain.unshift(node);
203
+ }
204
+ return chain;
205
+ }
206
+
207
+ /**
208
+ * Find the common ancestor in two parent chains.
209
+ *
210
+ * @param {Node[]} a
211
+ * A parent chain.
212
+ * @param {Node[]} b
213
+ * A parent chain.
214
+ * @returns {Node} The common ancestor if it exists.
215
+ */
216
+ function commonAncestor(a, b) {
217
+ if (b.length < a.length) return commonAncestor(b, a);
218
+ var c = null;
219
+ for (var n in a) {
220
+ if (a[n] !== b[n]) return c;
221
+ c = a[n];
222
+ }
223
+ return c;
224
+ }
225
+
226
+ /**
227
+ * Comparing unrelated nodes must be consistent, so we assign a guid to the compared docs for
228
+ * further reference.
229
+ *
230
+ * @param {Document} doc
231
+ * The document.
232
+ * @returns {string} The document's guid.
233
+ */
234
+ function docGUID(doc) {
235
+ if (!doc.guid) doc.guid = Math.random();
236
+ return doc.guid;
237
+ }
238
+ //-- end of helper functions
126
239
 
127
240
  /**
128
- * DOM Level 2
129
- * Object DOMException
241
+ * DOM Level 2 Object DOMException.
242
+ *
130
243
  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html
131
244
  * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html
132
245
  */
133
246
  function DOMException(code, message) {
134
- if(message instanceof Error){
247
+ if (message instanceof Error) {
135
248
  var error = message;
136
- }else{
249
+ } else {
137
250
  error = this;
138
251
  Error.call(this, ExceptionMessage[code]);
139
252
  this.message = ExceptionMessage[code];
140
- if(Error.captureStackTrace) Error.captureStackTrace(this, DOMException);
253
+ if (Error.captureStackTrace) Error.captureStackTrace(this, DOMException);
141
254
  }
142
255
  error.code = code;
143
- if(message) this.message = this.message + ": " + message;
256
+ if (message) this.message = this.message + ': ' + message;
144
257
  return error;
145
- };
258
+ }
146
259
  DOMException.prototype = Error.prototype;
147
- copy(ExceptionCode,DOMException)
260
+ copy(ExceptionCode, DOMException);
148
261
 
149
262
  /**
150
- * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
151
- * 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.
263
+ * The NodeList interface provides the abstraction of an ordered collection of nodes,
264
+ * without defining or constraining how this collection is implemented.
265
+ * NodeList objects in the DOM are live.
152
266
  * The items in the NodeList are accessible via an integral index, starting from 0.
267
+ *
268
+ * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
153
269
  */
154
- function NodeList() {
155
- };
270
+ function NodeList() {}
156
271
  NodeList.prototype = {
157
272
  /**
158
- * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.
273
+ * The number of nodes in the list. The range of valid child node indices is 0 to length-1
274
+ * inclusive.
275
+ *
159
276
  * @standard level1
160
277
  */
161
- length:0,
278
+ length: 0,
162
279
  /**
163
- * Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns null.
164
- * @standard level1
165
- * @param index unsigned long
166
- * Index into the collection.
167
- * @return Node
168
- * The node at the indexth position in the NodeList, or null if that is not a valid index.
280
+ * Returns the item at `index`. If index is greater than or equal to the number of nodes in
281
+ * the list, this returns null.
282
+ *
283
+ * @param index
284
+ * Unsigned long Index into the collection.
285
+ * @returns The node at position `index` in the NodeList,
286
+ * or null if that is not a valid index.
169
287
  */
170
- item: function(index) {
171
- return this[index] || null;
288
+ item: function (index) {
289
+ return index >= 0 && index < this.length ? this[index] : null;
172
290
  },
173
291
  toString: function (nodeFilter) {
174
- for(var buf = [], i = 0;i<this.length;i++){
175
- serializeToString(this[i], buf, nodeFilter)
292
+ for (var buf = [], i = 0; i < this.length; i++) {
293
+ serializeToString(this[i], buf, nodeFilter);
176
294
  }
177
- return buf.join('')
178
- }
295
+ return buf.join('');
296
+ },
297
+ /**
298
+ * @param {function (Node):boolean} predicate
299
+ * @returns {Node[]}
300
+ * @private
301
+ */
302
+ filter: function (predicate) {
303
+ return Array.prototype.filter.call(this, predicate);
304
+ },
305
+ /**
306
+ * @param {Node} item
307
+ * @returns {number}
308
+ * @private
309
+ */
310
+ indexOf: function (item) {
311
+ return Array.prototype.indexOf.call(this, item);
312
+ },
179
313
  };
180
314
 
181
- function LiveNodeList(node,refresh){
315
+ function LiveNodeList(node, refresh) {
182
316
  this._node = node;
183
- this._refresh = refresh
317
+ this._refresh = refresh;
184
318
  _updateLiveList(this);
185
319
  }
186
- function _updateLiveList(list){
320
+ function _updateLiveList(list) {
187
321
  var inc = list._node._inc || list._node.ownerDocument._inc;
188
- if(list._inc != inc){
322
+ if (list._inc !== inc) {
189
323
  var ls = list._refresh(list._node);
190
- //console.log(ls.length)
191
- __set__(list,'length',ls.length);
192
- copy(ls,list);
324
+ __set__(list, 'length', ls.length);
325
+ if (!list.$$length || ls.length < list.$$length) {
326
+ for (var i = ls.length; i in list; i++) {
327
+ if (Object.prototype.hasOwnProperty.call(list, i)) {
328
+ delete list[i];
329
+ }
330
+ }
331
+ }
332
+ copy(ls, list);
193
333
  list._inc = inc;
194
334
  }
195
335
  }
196
- LiveNodeList.prototype.item = function(i){
336
+ LiveNodeList.prototype.item = function (i) {
197
337
  _updateLiveList(this);
198
- return this[i];
199
- }
338
+ return this[i] || null;
339
+ };
200
340
 
201
- _extends(LiveNodeList,NodeList);
341
+ _extends(LiveNodeList, NodeList);
202
342
 
203
343
  /**
204
- * Objects implementing the NamedNodeMap interface are used
205
- * to represent collections of nodes that can be accessed by name.
344
+ * Objects implementing the NamedNodeMap interface are used to represent collections of nodes
345
+ * that can be accessed by name.
206
346
  * Note that NamedNodeMap does not inherit from NodeList;
207
347
  * NamedNodeMaps are not maintained in any particular order.
208
- * Objects contained in an object implementing NamedNodeMap may also be accessed by an ordinal index,
348
+ * Objects contained in an object implementing NamedNodeMap may also be accessed by an ordinal
349
+ * index,
209
350
  * but this is simply to allow convenient enumeration of the contents of a NamedNodeMap,
210
351
  * and does not imply that the DOM specifies an order to these Nodes.
211
352
  * NamedNodeMap objects in the DOM are live.
212
353
  * used for attributes or DocumentType entities
354
+ *
355
+ * This implementation only supports property indices, but does not support named properties,
356
+ * as specified in the living standard.
357
+ *
358
+ * @see https://dom.spec.whatwg.org/#interface-namednodemap
359
+ * @see https://webidl.spec.whatwg.org/#dfn-supported-property-names
213
360
  */
214
- function NamedNodeMap() {
215
- };
361
+ function NamedNodeMap() {}
216
362
 
217
- function _findNodeIndex(list,node){
218
- var i = list.length;
219
- while(i--){
220
- if(list[i] === node){return i}
363
+ function _findNodeIndex(list, node) {
364
+ var i = 0;
365
+ while (i < list.length) {
366
+ if (list[i] === node) {
367
+ return i;
368
+ }
369
+ i++;
221
370
  }
222
371
  }
223
372
 
224
- function _addNamedNode(el,list,newAttr,oldAttr){
225
- if(oldAttr){
226
- list[_findNodeIndex(list,oldAttr)] = newAttr;
227
- }else{
228
- list[list.length++] = newAttr;
373
+ function _addNamedNode(el, list, newAttr, oldAttr) {
374
+ if (oldAttr) {
375
+ list[_findNodeIndex(list, oldAttr)] = newAttr;
376
+ } else {
377
+ list[list.length] = newAttr;
378
+ list.length++;
229
379
  }
230
- if(el){
380
+ if (el) {
231
381
  newAttr.ownerElement = el;
232
382
  var doc = el.ownerDocument;
233
- if(doc){
234
- oldAttr && _onRemoveAttribute(doc,el,oldAttr);
235
- _onAddAttribute(doc,el,newAttr);
383
+ if (doc) {
384
+ oldAttr && _onRemoveAttribute(doc, el, oldAttr);
385
+ _onAddAttribute(doc, el, newAttr);
236
386
  }
237
387
  }
238
388
  }
239
- function _removeNamedNode(el,list,attr){
389
+ function _removeNamedNode(el, list, attr) {
240
390
  //console.log('remove attr:'+attr)
241
- var i = _findNodeIndex(list,attr);
242
- if(i>=0){
243
- var lastIndex = list.length-1
244
- while(i<lastIndex){
245
- list[i] = list[++i]
391
+ var i = _findNodeIndex(list, attr);
392
+ if (i >= 0) {
393
+ var lastIndex = list.length - 1;
394
+ while (i <= lastIndex) {
395
+ list[i] = list[++i];
246
396
  }
247
397
  list.length = lastIndex;
248
- if(el){
398
+ if (el) {
249
399
  var doc = el.ownerDocument;
250
- if(doc){
251
- _onRemoveAttribute(doc,el,attr);
252
- attr.ownerElement = null;
400
+ if (doc) {
401
+ _onRemoveAttribute(doc, el, attr);
253
402
  }
403
+ attr.ownerElement = null;
254
404
  }
255
- }else{
256
- throw DOMException(NOT_FOUND_ERR,new Error(el.tagName+'@'+attr))
257
405
  }
258
406
  }
259
407
  NamedNodeMap.prototype = {
260
- length:0,
261
- item:NodeList.prototype.item,
262
- getNamedItem: function(key) {
263
- // if(key.indexOf(':')>0 || key == 'xmlns'){
264
- // return null;
265
- // }
266
- //console.log()
267
- var i = this.length;
268
- while(i--){
408
+ length: 0,
409
+ item: NodeList.prototype.item,
410
+
411
+ /**
412
+ * get an attribute by name (lower case in case of HTML namespace and document)
413
+ *
414
+ * @param {string} localName
415
+ * @returns {Attr | null}
416
+ * @see https://dom.spec.whatwg.org/#concept-element-attributes-get-by-name
417
+ */
418
+ getNamedItem: function (localName) {
419
+ if (this._ownerElement && this._ownerElement._isInHTMLDocumentAndNamespace()) {
420
+ localName = localName.toLowerCase();
421
+ }
422
+ var i = 0;
423
+ while (i < this.length) {
269
424
  var attr = this[i];
270
- //console.log(attr.nodeName,key)
271
- if(attr.nodeName == key){
425
+ if (attr.nodeName === localName) {
272
426
  return attr;
273
427
  }
428
+ i++;
274
429
  }
430
+ return null;
275
431
  },
276
- setNamedItem: function(attr) {
432
+
433
+ /**
434
+ * Set an attribute.
435
+ *
436
+ * @param {Attr} attr
437
+ * @returns {Attr | null}
438
+ * @see https://dom.spec.whatwg.org/#concept-element-attributes-set
439
+ */
440
+ setNamedItem: function (attr) {
277
441
  var el = attr.ownerElement;
278
- if(el && el!=this._ownerElement){
442
+ if (el && el !== this._ownerElement) {
279
443
  throw new DOMException(INUSE_ATTRIBUTE_ERR);
280
444
  }
281
- var oldAttr = this.getNamedItem(attr.nodeName);
282
- _addNamedNode(this._ownerElement,this,attr,oldAttr);
283
- return oldAttr;
284
- },
285
- /* returns Node */
286
- setNamedItemNS: function(attr) {// raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR
287
- var el = attr.ownerElement, oldAttr;
288
- if(el && el!=this._ownerElement){
289
- throw new DOMException(INUSE_ATTRIBUTE_ERR);
445
+ var oldAttr = this.getNamedItemNS(attr.namespaceURI, attr.localName);
446
+ if (oldAttr === attr) {
447
+ return attr;
290
448
  }
291
- oldAttr = this.getNamedItemNS(attr.namespaceURI,attr.localName);
292
- _addNamedNode(this._ownerElement,this,attr,oldAttr);
449
+ _addNamedNode(this._ownerElement, this, attr, oldAttr);
293
450
  return oldAttr;
294
451
  },
295
452
 
296
- /* returns Node */
297
- removeNamedItem: function(key) {
298
- var attr = this.getNamedItem(key);
299
- _removeNamedNode(this._ownerElement,this,attr);
300
- return attr;
301
-
453
+ /**
454
+ * Set an attribute.
455
+ *
456
+ * @param {Attr} attr
457
+ * @returns {Attr | null}
458
+ * @see https://dom.spec.whatwg.org/#concept-element-attributes-set
459
+ */
460
+ setNamedItemNS: function (attr) {
461
+ return this.setNamedItem(attr);
462
+ },
302
463
 
303
- },// raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR
464
+ /**
465
+ * remove an attribute by name (lower case in case of HTML namespace and document)
466
+ *
467
+ * @param {string} localName
468
+ * @returns {Attr | null}
469
+ * @see https://dom.spec.whatwg.org/#dom-namednodemap-removenameditem
470
+ * @see https://dom.spec.whatwg.org/#concept-element-attributes-remove-by-name
471
+ */
472
+ removeNamedItem: function (localName) {
473
+ var attr = this.getNamedItem(localName);
474
+ if (!attr) {
475
+ throw new DOMException(NOT_FOUND_ERR, localName);
476
+ }
477
+ _removeNamedNode(this._ownerElement, this, attr);
478
+ return attr;
479
+ },
304
480
 
305
- //for level2
306
- removeNamedItemNS:function(namespaceURI,localName){
307
- var attr = this.getNamedItemNS(namespaceURI,localName);
308
- _removeNamedNode(this._ownerElement,this,attr);
481
+ /**
482
+ * Remove an attribute by namespace and local name.
483
+ *
484
+ * @param {string | null} namespaceURI
485
+ * @param {string} localName
486
+ * @returns {Attr | null}
487
+ * @see https://dom.spec.whatwg.org/#dom-namednodemap-removenameditemns
488
+ * @see https://dom.spec.whatwg.org/#concept-element-attributes-remove-by-namespace
489
+ */
490
+ removeNamedItemNS: function (namespaceURI, localName) {
491
+ var attr = this.getNamedItemNS(namespaceURI, localName);
492
+ if (!attr) {
493
+ throw new DOMException(NOT_FOUND_ERR, namespaceURI ? namespaceURI + ' : ' + localName : localName);
494
+ }
495
+ _removeNamedNode(this._ownerElement, this, attr);
309
496
  return attr;
310
497
  },
311
- getNamedItemNS: function(namespaceURI, localName) {
312
- var i = this.length;
313
- while(i--){
498
+
499
+ /**
500
+ * Get an attribute by namespace and local name.
501
+ *
502
+ * @param {string | null} namespaceURI
503
+ * @param {string} localName
504
+ * @returns {Attr | null}
505
+ * @see https://dom.spec.whatwg.org/#concept-element-attributes-get-by-namespace
506
+ */
507
+ getNamedItemNS: function (namespaceURI, localName) {
508
+ if (!namespaceURI) {
509
+ namespaceURI = null;
510
+ }
511
+ var i = 0;
512
+ while (i < this.length) {
314
513
  var node = this[i];
315
- if(node.localName == localName && node.namespaceURI == namespaceURI){
514
+ if (node.localName === localName && node.namespaceURI === namespaceURI) {
316
515
  return node;
317
516
  }
517
+ i++;
318
518
  }
319
519
  return null;
320
- }
520
+ },
321
521
  };
322
522
 
323
523
  /**
324
- * The DOMImplementation interface represents an object providing methods
325
- * which are not dependent on any particular document.
524
+ * The DOMImplementation interface represents an object providing methods which are not
525
+ * dependent on any particular document.
326
526
  * Such an object is returned by the `Document.implementation` property.
327
527
  *
328
- * __The individual methods describe the differences compared to the specs.__
329
- *
330
- * @constructor
528
+ * **The individual methods describe the differences compared to the specs**.
331
529
  *
530
+ * @class
332
531
  * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation MDN
333
- * @see https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490 DOM Level 1 Core (Initial)
532
+ * @see https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490 DOM Level 1 Core
533
+ * (Initial)
334
534
  * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-102161490 DOM Level 2 Core
335
535
  * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-102161490 DOM Level 3 Core
336
536
  * @see https://dom.spec.whatwg.org/#domimplementation DOM Living Standard
337
537
  */
338
- function DOMImplementation() {
339
- }
538
+ function DOMImplementation() {}
340
539
 
341
540
  DOMImplementation.prototype = {
342
541
  /**
343
- * The DOMImplementation.hasFeature() method returns a Boolean flag indicating if a given feature is supported.
542
+ * The DOMImplementation.hasFeature() method returns a Boolean flag indicating if a given
543
+ * feature is supported.
344
544
  * The different implementations fairly diverged in what kind of features were reported.
345
- * The latest version of the spec settled to force this method to always return true, where the functionality was accurate and in use.
346
- *
347
- * @deprecated It is deprecated and modern browsers return true in all cases.
545
+ * The latest version of the spec settled to force this method to always return true,
546
+ * where the functionality was accurate and in use.
348
547
  *
548
+ * @deprecated
549
+ * It is deprecated and modern browsers return true in all cases.
349
550
  * @param {string} feature
350
551
  * @param {string} [version]
351
- * @returns {boolean} always true
352
- *
552
+ * @returns {boolean} Always true.
353
553
  * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/hasFeature MDN
354
554
  * @see https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-5CED94D7 DOM Level 1 Core
355
555
  * @see https://dom.spec.whatwg.org/#dom-domimplementation-hasfeature DOM Living Standard
356
556
  */
357
- hasFeature: function(feature, version) {
358
- return true;
557
+ hasFeature: function (feature, version) {
558
+ return true;
359
559
  },
360
560
  /**
361
561
  * Creates an XML Document object of the specified type with its document element.
362
562
  *
363
563
  * __It behaves slightly different from the description in the living standard__:
364
- * - There is no interface/class `XMLDocument`, it returns a `Document` instance (with it's `type` set to `'xml'`).
564
+ * - There is no interface/class `XMLDocument`, it returns a `Document`
565
+ * instance (with it's `type` set to `'xml'`).
365
566
  * - `encoding`, `mode`, `origin`, `url` fields are currently not declared.
366
- * - The methods provided by this implementation are not validating names or qualified names.
367
- * (They are only validated by the SAX parser when calling `DOMParser.parseFromString`)
368
567
  *
369
568
  * @param {string | null} namespaceURI
370
569
  * @param {string} qualifiedName
371
570
  * @param {DocumentType | null} [doctype=null]
372
- * @returns {Document} the XML document
373
- *
374
- * @see #createHTMLDocument
375
- *
571
+ * @returns {Document} The XML document.
572
+ * @see {@link #createHTMLDocument}
376
573
  * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocument MDN
377
- * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocument DOM Level 2 Core (initial)
378
- * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument DOM Level 2 Core
379
- *
380
- * @see https://dom.spec.whatwg.org/#validate-and-extract DOM: Validate and extract
381
- * @see https://www.w3.org/TR/xml/#NT-NameStartChar XML Spec: Names
382
- * @see https://www.w3.org/TR/xml-names/#ns-qualnames XML Namespaces: Qualified names
574
+ * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocument DOM
575
+ * Level 2 Core (initial)
576
+ * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument DOM Level 2 Core
383
577
  */
384
- createDocument: function(namespaceURI, qualifiedName, doctype){
578
+ createDocument: function (namespaceURI, qualifiedName, doctype) {
385
579
  var contentType = MIME_TYPE.XML_APPLICATION;
386
580
  if (namespaceURI === NAMESPACE.HTML) {
387
581
  contentType = MIME_TYPE.XML_XHTML_APPLICATION;
388
582
  } else if (namespaceURI === NAMESPACE.SVG) {
389
- contentType = MIME_TYPE.XML_SVG_IMAGE
583
+ contentType = MIME_TYPE.XML_SVG_IMAGE;
390
584
  }
391
- var doc = new Document({contentType: contentType});
585
+ var doc = new Document({ contentType: contentType });
392
586
  doc.implementation = this;
393
587
  doc.childNodes = new NodeList();
394
588
  doc.doctype = doctype || null;
395
- if (doctype){
589
+ if (doctype) {
396
590
  doc.appendChild(doctype);
397
591
  }
398
- if (qualifiedName){
592
+ if (qualifiedName) {
399
593
  var root = doc.createElementNS(namespaceURI, qualifiedName);
400
594
  doc.appendChild(root);
401
595
  }
@@ -405,30 +599,37 @@ DOMImplementation.prototype = {
405
599
  * Returns a doctype, with the given `qualifiedName`, `publicId`, and `systemId`.
406
600
  *
407
601
  * __This behavior is slightly different from the in the specs__:
408
- * - this implementation is not validating names or qualified names
409
- * (when parsing XML strings, the SAX parser takes care of that)
410
602
  * - `encoding`, `mode`, `origin`, `url` fields are currently not declared.
603
+ * - `publicId` and `systemId` contain the raw data including any possible quotes,
604
+ * so they can always be serialized back to the original value -
605
+ * `internalSubset` contains the raw string between `[` and `]` if present,
606
+ * but is not parsed or validated in any form.
411
607
  *
412
608
  * @param {string} qualifiedName
413
609
  * @param {string} [publicId]
414
610
  * @param {string} [systemId]
415
- * @returns {DocumentType} which can either be used with `DOMImplementation.createDocument` upon document creation
416
- * or can be put into the document via methods like `Node.insertBefore()` or `Node.replaceChild()`
417
- *
418
- * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocumentType MDN
419
- * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocType DOM Level 2 Core
420
- * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype DOM Living Standard
421
- *
422
- * @see https://dom.spec.whatwg.org/#validate-and-extract DOM: Validate and extract
423
- * @see https://www.w3.org/TR/xml/#NT-NameStartChar XML Spec: Names
424
- * @see https://www.w3.org/TR/xml-names/#ns-qualnames XML Namespaces: Qualified names
611
+ * @param {string} [internalSubset]
612
+ * (from DOM Level 2 Core)
613
+ * @returns {DocumentType} which can either be used with `DOMImplementation.createDocument`
614
+ * on document creation or can be put into the document via methods
615
+ * like `Node.insertBefore()` or `Node.replaceChild()`
616
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocumentType
617
+ * MDN
618
+ * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocType DOM
619
+ * Level 2 Core
620
+ * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype DOM Living
621
+ * Standard
622
+ * @see https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md#050
623
+ * @see https://www.w3.org/TR/DOM-Level-2-Core/#core-ID-Core-DocType-internalSubset
425
624
  */
426
- createDocumentType: function(qualifiedName, publicId, systemId){
625
+ createDocumentType: function (qualifiedName, publicId, systemId, internalSubset) {
626
+ validateQualifiedName(qualifiedName);
427
627
  var node = new DocumentType();
428
628
  node.name = qualifiedName;
429
629
  node.nodeName = qualifiedName;
430
630
  node.publicId = publicId || '';
431
631
  node.systemId = systemId || '';
632
+ node.internalSubset = internalSubset || '';
432
633
 
433
634
  return node;
434
635
  },
@@ -436,108 +637,110 @@ DOMImplementation.prototype = {
436
637
  * Returns an HTML document, that might already have a basic DOM structure.
437
638
  *
438
639
  * __It behaves slightly different from the description in the living standard__:
439
- * - If the first argument is `false` no initial nodes are added (steps 3-7 in the specs are omitted)
640
+ * - If the first argument is `false` no initial nodes are added (steps 3-7 in the specs are
641
+ * omitted)
440
642
  * - `encoding`, `mode`, `origin`, `url` fields are currently not declared.
441
643
  *
442
644
  * @param {string | false} [title]
443
- * @returns {Document} The HTML document
444
- *
645
+ * @returns {Document} The HTML document.
646
+ * @see {@link #createDocument}
445
647
  * @see https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument
446
648
  * @see https://dom.spec.whatwg.org/#html-document
447
649
  */
448
- createHTMLDocument: function(title) {
449
- var doc = new Document({contentType: MIME_TYPE.HTML})
450
- doc.implementation = this
451
- doc.childNodes = new NodeList()
650
+ createHTMLDocument: function (title) {
651
+ var doc = new Document({ contentType: MIME_TYPE.HTML });
652
+ doc.implementation = this;
653
+ doc.childNodes = new NodeList();
452
654
  if (title !== false) {
453
- doc.doctype = this.createDocumentType('html')
454
- doc.doctype.ownerDocument = this;
655
+ doc.doctype = this.createDocumentType('html');
656
+ doc.doctype.ownerDocument = doc;
455
657
  doc.appendChild(doc.doctype);
456
- var htmlNode = doc.createElement('html')
457
- doc.appendChild(htmlNode)
458
- var headNode = doc.createElement('head')
459
- htmlNode.appendChild(headNode)
658
+ var htmlNode = doc.createElement('html');
659
+ doc.appendChild(htmlNode);
660
+ var headNode = doc.createElement('head');
661
+ htmlNode.appendChild(headNode);
460
662
  if (typeof title === 'string') {
461
663
  var titleNode = doc.createElement('title');
462
- titleNode.appendChild(doc.createTextNode(title))
463
- headNode.appendChild(titleNode)
664
+ titleNode.appendChild(doc.createTextNode(title));
665
+ headNode.appendChild(titleNode);
464
666
  }
465
- htmlNode.appendChild(doc.createElement('body'))
667
+ htmlNode.appendChild(doc.createElement('body'));
466
668
  }
467
- return doc
468
- }
669
+ return doc;
670
+ },
469
671
  };
470
672
 
471
-
472
673
  /**
473
674
  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247
474
675
  */
475
- function Node() {
476
- };
676
+ function Node() {}
477
677
 
478
678
  Node.prototype = {
479
- firstChild : null,
480
- lastChild : null,
481
- previousSibling : null,
482
- nextSibling : null,
483
- attributes : null,
484
- parentNode : null,
485
- childNodes : null,
486
- ownerDocument : null,
487
- nodeValue : null,
488
- namespaceURI : null,
489
- prefix : null,
490
- localName : null,
679
+ firstChild: null,
680
+ lastChild: null,
681
+ previousSibling: null,
682
+ nextSibling: null,
683
+ attributes: null,
684
+ parentNode: null,
685
+ childNodes: null,
686
+ ownerDocument: null,
687
+ nodeValue: null,
688
+ namespaceURI: null,
689
+ prefix: null,
690
+ localName: null,
491
691
  // Modified in DOM Level 2:
492
- insertBefore:function(newChild, refChild){//raises
493
- return _insertBefore(this,newChild,refChild);
692
+ insertBefore: function (newChild, refChild) {
693
+ //raises
694
+ return _insertBefore(this, newChild, refChild);
494
695
  },
495
- replaceChild:function(newChild, oldChild){//raises
496
- this.insertBefore(newChild,oldChild);
497
- if(oldChild){
696
+ replaceChild: function (newChild, oldChild) {
697
+ //raises
698
+ _insertBefore(this, newChild, oldChild, assertPreReplacementValidityInDocument);
699
+ if (oldChild) {
498
700
  this.removeChild(oldChild);
499
701
  }
500
702
  },
501
- removeChild:function(oldChild){
502
- return _removeChild(this,oldChild);
703
+ removeChild: function (oldChild) {
704
+ return _removeChild(this, oldChild);
503
705
  },
504
- appendChild:function(newChild){
505
- return this.insertBefore(newChild,null);
706
+ appendChild: function (newChild) {
707
+ return this.insertBefore(newChild, null);
506
708
  },
507
- hasChildNodes:function(){
709
+ hasChildNodes: function () {
508
710
  return this.firstChild != null;
509
711
  },
510
- cloneNode:function(deep){
511
- return cloneNode(this.ownerDocument||this,this,deep);
712
+ cloneNode: function (deep) {
713
+ return cloneNode(this.ownerDocument || this, this, deep);
512
714
  },
513
715
  // Modified in DOM Level 2:
514
- normalize:function(){
716
+ normalize: function () {
515
717
  var child = this.firstChild;
516
- while(child){
718
+ while (child) {
517
719
  var next = child.nextSibling;
518
- if(next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE){
720
+ if (next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE) {
519
721
  this.removeChild(next);
520
722
  child.appendData(next.data);
521
- }else{
723
+ } else {
522
724
  child.normalize();
523
725
  child = next;
524
726
  }
525
727
  }
526
728
  },
527
- // Introduced in DOM Level 2:
528
- isSupported:function(feature, version){
529
- return this.ownerDocument.implementation.hasFeature(feature,version);
729
+ // Introduced in DOM Level 2:
730
+ isSupported: function (feature, version) {
731
+ return this.ownerDocument.implementation.hasFeature(feature, version);
732
+ },
733
+ // Introduced in DOM Level 2:
734
+ hasAttributes: function () {
735
+ return this.attributes.length > 0;
530
736
  },
531
- // Introduced in DOM Level 2:
532
- hasAttributes:function(){
533
- return this.attributes.length>0;
534
- },
535
737
  /**
536
738
  * Look up the prefix associated to the given namespace URI, starting from this node.
537
739
  * **The default namespace declarations are ignored by this method.**
538
740
  * See Namespace Prefix Lookup for details on the algorithm used by this method.
539
741
  *
540
- * _Note: The implementation seems to be incomplete when compared to the algorithm described in the specs._
742
+ * _Note: The implementation seems to be incomplete when compared to the algorithm described
743
+ * in the specs._.
541
744
  *
542
745
  * @param {string | null} namespaceURI
543
746
  * @returns {string | null}
@@ -546,70 +749,128 @@ Node.prototype = {
546
749
  * @see https://dom.spec.whatwg.org/#dom-node-lookupprefix
547
750
  * @see https://github.com/xmldom/xmldom/issues/322
548
751
  */
549
- lookupPrefix:function(namespaceURI){
550
- var el = this;
551
- while(el){
552
- var map = el._nsMap;
553
- //console.dir(map)
554
- if(map){
555
- for(var n in map){
556
- if(map[n] == namespaceURI){
557
- return n;
558
- }
559
- }
560
- }
561
- el = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;
562
- }
563
- return null;
564
- },
565
- // Introduced in DOM Level 3:
566
- lookupNamespaceURI:function(prefix){
567
- var el = this;
568
- while(el){
569
- var map = el._nsMap;
570
- //console.dir(map)
571
- if(map){
572
- if(prefix in map){
573
- return map[prefix] ;
574
- }
575
- }
576
- el = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;
577
- }
578
- return null;
579
- },
580
- // Introduced in DOM Level 3:
581
- isDefaultNamespace:function(namespaceURI){
582
- var prefix = this.lookupPrefix(namespaceURI);
583
- return prefix == null;
584
- }
752
+ lookupPrefix: function (namespaceURI) {
753
+ var el = this;
754
+ while (el) {
755
+ var map = el._nsMap;
756
+ //console.dir(map)
757
+ if (map) {
758
+ for (var n in map) {
759
+ if (Object.prototype.hasOwnProperty.call(map, n) && map[n] === namespaceURI) {
760
+ return n;
761
+ }
762
+ }
763
+ }
764
+ el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode;
765
+ }
766
+ return null;
767
+ },
768
+ // Introduced in DOM Level 3:
769
+ lookupNamespaceURI: function (prefix) {
770
+ var el = this;
771
+ while (el) {
772
+ var map = el._nsMap;
773
+ //console.dir(map)
774
+ if (map) {
775
+ if (Object.prototype.hasOwnProperty.call(map, prefix)) {
776
+ return map[prefix];
777
+ }
778
+ }
779
+ el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode;
780
+ }
781
+ return null;
782
+ },
783
+ // Introduced in DOM Level 3:
784
+ isDefaultNamespace: function (namespaceURI) {
785
+ var prefix = this.lookupPrefix(namespaceURI);
786
+ return prefix == null;
787
+ },
788
+ // Introduced in DOM Level 3:
789
+ /**
790
+ * Compares the reference node with a node with regard to their position in the document and
791
+ * according to the document order.
792
+ *
793
+ * @param {Node} other
794
+ * The node to compare the reference node to.
795
+ * @returns {number} Returns how the node is positioned relatively to the reference node
796
+ * according to the bitmask. 0 if reference node and given node are the
797
+ * same.
798
+ * @see https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Node3-compareDocumentPosition
799
+ */
800
+ compareDocumentPosition: function (other) {
801
+ if (this === other) return 0;
802
+ var node1 = other;
803
+ var node2 = this;
804
+ var attr1 = null;
805
+ var attr2 = null;
806
+ if (node1 instanceof Attr) {
807
+ attr1 = node1;
808
+ node1 = attr1.ownerElement;
809
+ }
810
+ if (node2 instanceof Attr) {
811
+ attr2 = node2;
812
+ node2 = attr2.ownerElement;
813
+ if (attr1 && node1 && node2 === node1) {
814
+ for (var i = 0, attr; (attr = node2.attributes[i]); i++) {
815
+ if (attr === attr1) return DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC + DOCUMENT_POSITION_PRECEDING;
816
+ if (attr === attr2) return DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC + DOCUMENT_POSITION_FOLLOWING;
817
+ }
818
+ }
819
+ }
820
+ if (!node1 || !node2 || node2.ownerDocument !== node1.ownerDocument) {
821
+ return (
822
+ DOCUMENT_POSITION_DISCONNECTED +
823
+ DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
824
+ (docGUID(node2.ownerDocument) > docGUID(node1.ownerDocument) ? DOCUMENT_POSITION_FOLLOWING : DOCUMENT_POSITION_PRECEDING)
825
+ );
826
+ }
827
+ var chain1 = parentChain(node1);
828
+ var chain2 = parentChain(node2);
829
+ if ((!attr1 && chain2.indexOf(node1) >= 0) || (attr2 && node1 === node2)) {
830
+ return DOCUMENT_POSITION_CONTAINS + DOCUMENT_POSITION_PRECEDING;
831
+ }
832
+ if ((!attr2 && chain1.indexOf(node2) >= 0) || (attr1 && node1 === node2)) {
833
+ return DOCUMENT_POSITION_CONTAINED_BY + DOCUMENT_POSITION_FOLLOWING;
834
+ }
835
+ var ca = commonAncestor(chain2, chain1);
836
+ for (var n in ca.childNodes) {
837
+ var child = ca.childNodes[n];
838
+ if (child === node2) return DOCUMENT_POSITION_FOLLOWING;
839
+ if (child === node1) return DOCUMENT_POSITION_PRECEDING;
840
+ if (chain2.indexOf(child) >= 0) return DOCUMENT_POSITION_FOLLOWING;
841
+ if (chain1.indexOf(child) >= 0) return DOCUMENT_POSITION_PRECEDING;
842
+ }
843
+ return 0;
844
+ },
585
845
  };
586
846
 
587
-
588
- function _xmlEncoder(c){
589
- return c == '<' && '&lt;' ||
590
- c == '>' && '&gt;' ||
591
- c == '&' && '&amp;' ||
592
- c == '"' && '&quot;' ||
593
- '&#'+c.charCodeAt()+';'
847
+ function _xmlEncoder(c) {
848
+ return (
849
+ (c == '<' && '&lt;') || (c == '>' && '&gt;') || (c == '&' && '&amp;') || (c == '"' && '&quot;') || '&#' + c.charCodeAt() + ';'
850
+ );
594
851
  }
595
852
 
596
-
597
- copy(NodeType,Node);
598
- copy(NodeType,Node.prototype);
853
+ copy(NodeType, Node);
854
+ copy(NodeType, Node.prototype);
855
+ copy(DocumentPosition, Node);
856
+ copy(DocumentPosition, Node.prototype);
599
857
 
600
858
  /**
601
- * @param callback return true for continue,false for break
602
- * @return boolean true: break visit;
859
+ * @param callback
860
+ * Return true for continue,false for break.
861
+ * @returns boolean true: break visit;
603
862
  */
604
- function _visitNode(node,callback){
605
- if(callback(node)){
863
+ function _visitNode(node, callback) {
864
+ if (callback(node)) {
606
865
  return true;
607
866
  }
608
- if(node = node.firstChild){
609
- do{
610
- if(_visitNode(node,callback)){return true}
611
- }while(node=node.nextSibling)
612
- }
867
+ if ((node = node.firstChild)) {
868
+ do {
869
+ if (_visitNode(node, callback)) {
870
+ return true;
871
+ }
872
+ } while ((node = node.nextSibling));
873
+ }
613
874
  }
614
875
 
615
876
  /**
@@ -622,55 +883,52 @@ function _visitNode(node,callback){
622
883
  * It should usually be created using `new DOMImplementation().createDocument(...)`
623
884
  * or `new DOMImplementation().createHTMLDocument(...)`.
624
885
  *
625
- * The constructor is considered a private API and offers to initially set the `contentType` property
626
- * via it's options parameter.
886
+ * The constructor is considered a private API and offers to initially set the `contentType`
887
+ * property via it's options parameter.
627
888
  *
889
+ * @class
628
890
  * @param {DocumentOptions} [options]
629
891
  * @private
630
- * @constructor
631
- *
632
892
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Document
633
893
  * @see https://dom.spec.whatwg.org/#interface-document
634
894
  */
635
- function Document(options){
895
+ function Document(options) {
636
896
  var opt = options || {};
897
+ this.ownerDocument = this;
637
898
  /**
638
899
  * The mime type of the document is determined at creation time and can not be modified.
639
900
  *
640
901
  * @type {string}
641
- * @readonly
642
- *
643
902
  * @see https://dom.spec.whatwg.org/#concept-document-content-type
644
- * @see DOMImplementation
645
- * @see MIME_TYPE
903
+ * @see {@link DOMImplementation}
904
+ * @see {@link MIME_TYPE}
905
+ * @readonly
646
906
  */
647
- this.contentType = opt.contentType || MIME_TYPE.XML_APPLICATION
907
+ this.contentType = opt.contentType || MIME_TYPE.XML_APPLICATION;
648
908
  /**
649
- *
650
909
  * @type {'html' | 'xml'}
651
- * @readonly
652
- *
653
910
  * @see https://dom.spec.whatwg.org/#concept-document-type
654
- * @see DOMImplementation
911
+ * @see {@link DOMImplementation}
912
+ * @readonly
655
913
  */
656
- this.type = MIME_TYPE.isHTML(this.contentType) ? 'html' : 'xml'
914
+ this.type = isHTMLMimeType(this.contentType) ? 'html' : 'xml';
657
915
  }
658
916
 
659
- function _onAddAttribute(doc,el,newAttr){
917
+ function _onAddAttribute(doc, el, newAttr) {
660
918
  doc && doc._inc++;
661
- var ns = newAttr.namespaceURI ;
662
- if(ns === NAMESPACE.XMLNS){
919
+ var ns = newAttr.namespaceURI;
920
+ if (ns === NAMESPACE.XMLNS) {
663
921
  //update namespace
664
- el._nsMap[newAttr.prefix?newAttr.localName:''] = newAttr.value
922
+ el._nsMap[newAttr.prefix ? newAttr.localName : ''] = newAttr.value;
665
923
  }
666
924
  }
667
925
 
668
- function _onRemoveAttribute(doc,el,newAttr,remove){
926
+ function _onRemoveAttribute(doc, el, newAttr, remove) {
669
927
  doc && doc._inc++;
670
- var ns = newAttr.namespaceURI ;
671
- if(ns === NAMESPACE.XMLNS){
928
+ var ns = newAttr.namespaceURI;
929
+ if (ns === NAMESPACE.XMLNS) {
672
930
  //update namespace
673
- delete el._nsMap[newAttr.prefix?newAttr.localName:'']
931
+ delete el._nsMap[newAttr.prefix ? newAttr.localName : ''];
674
932
  }
675
933
  }
676
934
 
@@ -678,16 +936,15 @@ function _onRemoveAttribute(doc,el,newAttr,remove){
678
936
  * Updates `el.childNodes`, updating the indexed items and it's `length`.
679
937
  * Passing `newChild` means it will be appended.
680
938
  * Otherwise it's assumed that an item has been removed,
681
- * and `el.firstNode` and it's `.nextSibling` are used
682
- * to walk the current list of child nodes.
939
+ * and `el.firstNode` and it's `.nextSibling` are used to walk the current list of child nodes.
683
940
  *
684
941
  * @param {Document} doc
685
942
  * @param {Node} el
686
943
  * @param {Node} [newChild]
687
944
  * @private
688
945
  */
689
- function _onUpdateChild (doc, el, newChild) {
690
- if(doc && doc._inc){
946
+ function _onUpdateChild(doc, el, newChild) {
947
+ if (doc && doc._inc) {
691
948
  doc._inc++;
692
949
  //update childNodes
693
950
  var cs = el.childNodes;
@@ -710,89 +967,377 @@ function _onUpdateChild (doc, el, newChild) {
710
967
  * Removes the connections between `parentNode` and `child`
711
968
  * and any existing `child.previousSibling` or `child.nextSibling`.
712
969
  *
713
- * @see https://github.com/xmldom/xmldom/issues/135
714
- * @see https://github.com/xmldom/xmldom/issues/145
715
- *
716
970
  * @param {Node} parentNode
717
971
  * @param {Node} child
718
- * @returns {Node} the child that was removed.
972
+ * @returns {Node} The child that was removed.
719
973
  * @private
974
+ * @see https://github.com/xmldom/xmldom/issues/135
975
+ * @see https://github.com/xmldom/xmldom/issues/145
720
976
  */
721
- function _removeChild (parentNode, child) {
722
- var previous = child.previousSibling;
723
- var next = child.nextSibling;
724
- if (previous) {
725
- previous.nextSibling = next;
977
+ function _removeChild(parentNode, child) {
978
+ if (parentNode !== child.parentNode) {
979
+ throw new DOMException(NOT_FOUND_ERR, "child's parent is not parent");
980
+ }
981
+ //var index = parentNode.childNodes.
982
+ var oldPreviousSibling = child.previousSibling;
983
+ var oldNextSibling = child.nextSibling;
984
+ if (oldPreviousSibling) {
985
+ oldPreviousSibling.nextSibling = oldNextSibling;
726
986
  } else {
727
- parentNode.firstChild = next;
987
+ parentNode.firstChild = oldNextSibling;
728
988
  }
729
- if (next) {
730
- next.previousSibling = previous;
989
+ if (oldNextSibling) {
990
+ oldNextSibling.previousSibling = oldPreviousSibling;
731
991
  } else {
732
- parentNode.lastChild = previous;
992
+ parentNode.lastChild = oldPreviousSibling;
733
993
  }
994
+ _onUpdateChild(parentNode.ownerDocument, parentNode);
734
995
  child.parentNode = null;
735
996
  child.previousSibling = null;
736
997
  child.nextSibling = null;
737
- _onUpdateChild(parentNode.ownerDocument, parentNode);
738
998
  return child;
739
999
  }
1000
+
740
1001
  /**
741
- * preformance key(refChild == null)
1002
+ * Returns `true` if `node` can be a parent for insertion.
1003
+ *
1004
+ * @param {Node} node
1005
+ * @returns {boolean}
742
1006
  */
743
- function _insertBefore(parentNode,newChild,nextChild){
744
- var cp = newChild.parentNode;
745
- if(cp){
746
- cp.removeChild(newChild);//remove and update
1007
+ function hasValidParentNodeType(node) {
1008
+ return (
1009
+ node &&
1010
+ (node.nodeType === Node.DOCUMENT_NODE || node.nodeType === Node.DOCUMENT_FRAGMENT_NODE || node.nodeType === Node.ELEMENT_NODE)
1011
+ );
1012
+ }
1013
+
1014
+ /**
1015
+ * Returns `true` if `node` can be inserted according to it's `nodeType`.
1016
+ *
1017
+ * @param {Node} node
1018
+ * @returns {boolean}
1019
+ */
1020
+ function hasInsertableNodeType(node) {
1021
+ return (
1022
+ node &&
1023
+ (isElementNode(node) ||
1024
+ isTextNode(node) ||
1025
+ isDocTypeNode(node) ||
1026
+ node.nodeType === Node.DOCUMENT_FRAGMENT_NODE ||
1027
+ node.nodeType === Node.COMMENT_NODE ||
1028
+ node.nodeType === Node.PROCESSING_INSTRUCTION_NODE)
1029
+ );
1030
+ }
1031
+
1032
+ /**
1033
+ * Returns true if `node` is a DOCTYPE node.
1034
+ *
1035
+ * @param {Node} node
1036
+ * @returns {boolean}
1037
+ */
1038
+ function isDocTypeNode(node) {
1039
+ return node && node.nodeType === Node.DOCUMENT_TYPE_NODE;
1040
+ }
1041
+
1042
+ /**
1043
+ * Returns true if the node is an element.
1044
+ *
1045
+ * @param {Node} node
1046
+ * @returns {boolean}
1047
+ */
1048
+ function isElementNode(node) {
1049
+ return node && node.nodeType === Node.ELEMENT_NODE;
1050
+ }
1051
+ /**
1052
+ * Returns true if `node` is a text node.
1053
+ *
1054
+ * @param {Node} node
1055
+ * @returns {boolean}
1056
+ */
1057
+ function isTextNode(node) {
1058
+ return node && node.nodeType === Node.TEXT_NODE;
1059
+ }
1060
+
1061
+ /**
1062
+ * Check if en element node can be inserted before `child`, or at the end if child is falsy,
1063
+ * according to the presence and position of a doctype node on the same level.
1064
+ *
1065
+ * @param {Document} doc
1066
+ * The document node.
1067
+ * @param {Node} child
1068
+ * The node that would become the nextSibling if the element would be inserted.
1069
+ * @returns {boolean} `true` if an element can be inserted before child.
1070
+ * @private
1071
+ */
1072
+ function isElementInsertionPossible(doc, child) {
1073
+ var parentChildNodes = doc.childNodes || [];
1074
+ if (find(parentChildNodes, isElementNode) || isDocTypeNode(child)) {
1075
+ return false;
747
1076
  }
748
- if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
749
- var newFirst = newChild.firstChild;
1077
+ var docTypeNode = find(parentChildNodes, isDocTypeNode);
1078
+ return !(child && docTypeNode && parentChildNodes.indexOf(docTypeNode) > parentChildNodes.indexOf(child));
1079
+ }
1080
+
1081
+ /**
1082
+ * Check if en element node can be inserted before `child`, or at the end if child is falsy,
1083
+ * according to the presence and position of a doctype node on the same level.
1084
+ *
1085
+ * @param {Node} doc
1086
+ * The document node.
1087
+ * @param {Node} child
1088
+ * The node that would become the nextSibling if the element would be inserted.
1089
+ * @returns {boolean} `true` if an element can be inserted before child.
1090
+ * @private
1091
+ */
1092
+ function isElementReplacementPossible(doc, child) {
1093
+ var parentChildNodes = doc.childNodes || [];
1094
+
1095
+ function hasElementChildThatIsNotChild(node) {
1096
+ return isElementNode(node) && node !== child;
1097
+ }
1098
+
1099
+ if (find(parentChildNodes, hasElementChildThatIsNotChild)) {
1100
+ return false;
1101
+ }
1102
+ var docTypeNode = find(parentChildNodes, isDocTypeNode);
1103
+ return !(child && docTypeNode && parentChildNodes.indexOf(docTypeNode) > parentChildNodes.indexOf(child));
1104
+ }
1105
+
1106
+ /**
1107
+ * @param {Node} parent
1108
+ * The parent node to insert `node` into.
1109
+ * @param {Node} node
1110
+ * The node to insert.
1111
+ * @param {Node=} child
1112
+ * the node that should become the `nextSibling` of `node`
1113
+ * @returns {Node}
1114
+ * @throws {DOMException}
1115
+ * For several node combinations that would create a DOM that is not well-formed.
1116
+ * @throws {DOMException}
1117
+ * If `child` is provided but is not a child of `parent`.
1118
+ * @private
1119
+ * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
1120
+ * @see https://dom.spec.whatwg.org/#concept-node-replace
1121
+ */
1122
+ function assertPreInsertionValidity1to5(parent, node, child) {
1123
+ // 1. If `parent` is not a Document, DocumentFragment, or Element node, then throw a "HierarchyRequestError" DOMException.
1124
+ if (!hasValidParentNodeType(parent)) {
1125
+ throw new DOMException(HIERARCHY_REQUEST_ERR, 'Unexpected parent node type ' + parent.nodeType);
1126
+ }
1127
+ // 2. If `node` is a host-including inclusive ancestor of `parent`, then throw a "HierarchyRequestError" DOMException.
1128
+ // not implemented!
1129
+ // 3. If `child` is non-null and its parent is not `parent`, then throw a "NotFoundError" DOMException.
1130
+ if (child && child.parentNode !== parent) {
1131
+ throw new DOMException(NOT_FOUND_ERR, 'child not in parent');
1132
+ }
1133
+ if (
1134
+ // 4. If `node` is not a DocumentFragment, DocumentType, Element, or CharacterData node, then throw a "HierarchyRequestError" DOMException.
1135
+ !hasInsertableNodeType(node) ||
1136
+ // 5. If either `node` is a Text node and `parent` is a document,
1137
+ // the sax parser currently adds top level text nodes, this will be fixed in 0.9.0
1138
+ // || (node.nodeType === Node.TEXT_NODE && parent.nodeType === Node.DOCUMENT_NODE)
1139
+ // or `node` is a doctype and `parent` is not a document, then throw a "HierarchyRequestError" DOMException.
1140
+ (isDocTypeNode(node) && parent.nodeType !== Node.DOCUMENT_NODE)
1141
+ ) {
1142
+ throw new DOMException(
1143
+ HIERARCHY_REQUEST_ERR,
1144
+ 'Unexpected node type ' + node.nodeType + ' for parent node type ' + parent.nodeType
1145
+ );
1146
+ }
1147
+ }
1148
+
1149
+ /**
1150
+ * @param {Document} parent
1151
+ * The parent node to insert `node` into.
1152
+ * @param {Node} node
1153
+ * The node to insert.
1154
+ * @param {Node | undefined} child
1155
+ * the node that should become the `nextSibling` of `node`
1156
+ * @returns {Node}
1157
+ * @throws {DOMException}
1158
+ * For several node combinations that would create a DOM that is not well-formed.
1159
+ * @throws {DOMException}
1160
+ * If `child` is provided but is not a child of `parent`.
1161
+ * @private
1162
+ * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
1163
+ * @see https://dom.spec.whatwg.org/#concept-node-replace
1164
+ */
1165
+ function assertPreInsertionValidityInDocument(parent, node, child) {
1166
+ var parentChildNodes = parent.childNodes || [];
1167
+ var nodeChildNodes = node.childNodes || [];
1168
+
1169
+ // DocumentFragment
1170
+ if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
1171
+ var nodeChildElements = nodeChildNodes.filter(isElementNode);
1172
+ // If node has more than one element child or has a Text node child.
1173
+ if (nodeChildElements.length > 1 || find(nodeChildNodes, isTextNode)) {
1174
+ throw new DOMException(HIERARCHY_REQUEST_ERR, 'More than one element or text in fragment');
1175
+ }
1176
+ // Otherwise, if `node` has one element child and either `parent` has an element child,
1177
+ // `child` is a doctype, or `child` is non-null and a doctype is following `child`.
1178
+ if (nodeChildElements.length === 1 && !isElementInsertionPossible(parent, child)) {
1179
+ throw new DOMException(HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype');
1180
+ }
1181
+ }
1182
+ // Element
1183
+ if (isElementNode(node)) {
1184
+ // `parent` has an element child, `child` is a doctype,
1185
+ // or `child` is non-null and a doctype is following `child`.
1186
+ if (!isElementInsertionPossible(parent, child)) {
1187
+ throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one element can be added and only after doctype');
1188
+ }
1189
+ }
1190
+ // DocumentType
1191
+ if (isDocTypeNode(node)) {
1192
+ // `parent` has a doctype child,
1193
+ if (find(parentChildNodes, isDocTypeNode)) {
1194
+ throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one doctype is allowed');
1195
+ }
1196
+ var parentElementChild = find(parentChildNodes, isElementNode);
1197
+ // `child` is non-null and an element is preceding `child`,
1198
+ if (child && parentChildNodes.indexOf(parentElementChild) < parentChildNodes.indexOf(child)) {
1199
+ throw new DOMException(HIERARCHY_REQUEST_ERR, 'Doctype can only be inserted before an element');
1200
+ }
1201
+ // or `child` is null and `parent` has an element child.
1202
+ if (!child && parentElementChild) {
1203
+ throw new DOMException(HIERARCHY_REQUEST_ERR, 'Doctype can not be appended since element is present');
1204
+ }
1205
+ }
1206
+ }
1207
+
1208
+ /**
1209
+ * @param {Document} parent
1210
+ * The parent node to insert `node` into.
1211
+ * @param {Node} node
1212
+ * The node to insert.
1213
+ * @param {Node | undefined} child
1214
+ * the node that should become the `nextSibling` of `node`
1215
+ * @returns {Node}
1216
+ * @throws {DOMException}
1217
+ * For several node combinations that would create a DOM that is not well-formed.
1218
+ * @throws {DOMException}
1219
+ * If `child` is provided but is not a child of `parent`.
1220
+ * @private
1221
+ * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
1222
+ * @see https://dom.spec.whatwg.org/#concept-node-replace
1223
+ */
1224
+ function assertPreReplacementValidityInDocument(parent, node, child) {
1225
+ var parentChildNodes = parent.childNodes || [];
1226
+ var nodeChildNodes = node.childNodes || [];
1227
+
1228
+ // DocumentFragment
1229
+ if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
1230
+ var nodeChildElements = nodeChildNodes.filter(isElementNode);
1231
+ // If `node` has more than one element child or has a Text node child.
1232
+ if (nodeChildElements.length > 1 || find(nodeChildNodes, isTextNode)) {
1233
+ throw new DOMException(HIERARCHY_REQUEST_ERR, 'More than one element or text in fragment');
1234
+ }
1235
+ // Otherwise, if `node` has one element child and either `parent` has an element child that is not `child` or a doctype is following `child`.
1236
+ if (nodeChildElements.length === 1 && !isElementReplacementPossible(parent, child)) {
1237
+ throw new DOMException(HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype');
1238
+ }
1239
+ }
1240
+ // Element
1241
+ if (isElementNode(node)) {
1242
+ // `parent` has an element child that is not `child` or a doctype is following `child`.
1243
+ if (!isElementReplacementPossible(parent, child)) {
1244
+ throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one element can be added and only after doctype');
1245
+ }
1246
+ }
1247
+ // DocumentType
1248
+ if (isDocTypeNode(node)) {
1249
+ function hasDoctypeChildThatIsNotChild(node) {
1250
+ return isDocTypeNode(node) && node !== child;
1251
+ }
1252
+
1253
+ // `parent` has a doctype child that is not `child`,
1254
+ if (find(parentChildNodes, hasDoctypeChildThatIsNotChild)) {
1255
+ throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one doctype is allowed');
1256
+ }
1257
+ var parentElementChild = find(parentChildNodes, isElementNode);
1258
+ // or an element is preceding `child`.
1259
+ if (child && parentChildNodes.indexOf(parentElementChild) < parentChildNodes.indexOf(child)) {
1260
+ throw new DOMException(HIERARCHY_REQUEST_ERR, 'Doctype can only be inserted before an element');
1261
+ }
1262
+ }
1263
+ }
1264
+
1265
+ /**
1266
+ * @param {Node} parent
1267
+ * The parent node to insert `node` into.
1268
+ * @param {Node} node
1269
+ * The node to insert.
1270
+ * @param {Node=} child
1271
+ * the node that should become the `nextSibling` of `node`
1272
+ * @returns {Node}
1273
+ * @throws {DOMException}
1274
+ * For several node combinations that would create a DOM that is not well-formed.
1275
+ * @throws {DOMException}
1276
+ * If `child` is provided but is not a child of `parent`.
1277
+ * @private
1278
+ * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
1279
+ */
1280
+ function _insertBefore(parent, node, child, _inDocumentAssertion) {
1281
+ // To ensure pre-insertion validity of a node into a parent before a child, run these steps:
1282
+ assertPreInsertionValidity1to5(parent, node, child);
1283
+
1284
+ // If parent is a document, and any of the statements below, switched on the interface node implements,
1285
+ // are true, then throw a "HierarchyRequestError" DOMException.
1286
+ if (parent.nodeType === Node.DOCUMENT_NODE) {
1287
+ (_inDocumentAssertion || assertPreInsertionValidityInDocument)(parent, node, child);
1288
+ }
1289
+
1290
+ var cp = node.parentNode;
1291
+ if (cp) {
1292
+ cp.removeChild(node); //remove and update
1293
+ }
1294
+ if (node.nodeType === DOCUMENT_FRAGMENT_NODE) {
1295
+ var newFirst = node.firstChild;
750
1296
  if (newFirst == null) {
751
- return newChild;
1297
+ return node;
752
1298
  }
753
- var newLast = newChild.lastChild;
754
- }else{
755
- newFirst = newLast = newChild;
1299
+ var newLast = node.lastChild;
1300
+ } else {
1301
+ newFirst = newLast = node;
756
1302
  }
757
- var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;
1303
+ var pre = child ? child.previousSibling : parent.lastChild;
758
1304
 
759
1305
  newFirst.previousSibling = pre;
760
- newLast.nextSibling = nextChild;
1306
+ newLast.nextSibling = child;
761
1307
 
762
-
763
- if(pre){
1308
+ if (pre) {
764
1309
  pre.nextSibling = newFirst;
765
- }else{
766
- parentNode.firstChild = newFirst;
1310
+ } else {
1311
+ parent.firstChild = newFirst;
767
1312
  }
768
- if(nextChild == null){
769
- parentNode.lastChild = newLast;
770
- }else{
771
- nextChild.previousSibling = newLast;
1313
+ if (child == null) {
1314
+ parent.lastChild = newLast;
1315
+ } else {
1316
+ child.previousSibling = newLast;
772
1317
  }
773
- do{
774
- newFirst.parentNode = parentNode;
775
- }while(newFirst !== newLast && (newFirst= newFirst.nextSibling))
776
- _onUpdateChild(parentNode.ownerDocument||parentNode,parentNode);
777
- //console.log(parentNode.lastChild.nextSibling == null)
778
- if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
779
- newChild.firstChild = newChild.lastChild = null;
1318
+ do {
1319
+ newFirst.parentNode = parent;
1320
+ } while (newFirst !== newLast && (newFirst = newFirst.nextSibling));
1321
+ _onUpdateChild(parent.ownerDocument || parent, parent);
1322
+ //console.log(parent.lastChild.nextSibling == null)
1323
+ if (node.nodeType == DOCUMENT_FRAGMENT_NODE) {
1324
+ node.firstChild = node.lastChild = null;
780
1325
  }
781
- return newChild;
1326
+ return node;
782
1327
  }
783
1328
 
784
1329
  /**
785
1330
  * Appends `newChild` to `parentNode`.
786
1331
  * If `newChild` is already connected to a `parentNode` it is first removed from it.
787
1332
  *
788
- * @see https://github.com/xmldom/xmldom/issues/135
789
- * @see https://github.com/xmldom/xmldom/issues/145
790
1333
  * @param {Node} parentNode
791
1334
  * @param {Node} newChild
792
1335
  * @returns {Node}
793
1336
  * @private
1337
+ * @see https://github.com/xmldom/xmldom/issues/135
1338
+ * @see https://github.com/xmldom/xmldom/issues/145
794
1339
  */
795
- function _appendSingleChild (parentNode, newChild) {
1340
+ function _appendSingleChild(parentNode, newChild) {
796
1341
  if (newChild.parentNode) {
797
1342
  newChild.parentNode.removeChild(newChild);
798
1343
  }
@@ -811,97 +1356,114 @@ function _appendSingleChild (parentNode, newChild) {
811
1356
 
812
1357
  Document.prototype = {
813
1358
  /**
814
- * The implementation that created this document
815
- * @readonly
1359
+ * The implementation that created this document.
1360
+ *
816
1361
  * @type DOMImplementation
1362
+ * @readonly
817
1363
  */
818
- implementation : null,
819
- nodeName : '#document',
820
- nodeType : DOCUMENT_NODE,
1364
+ implementation: null,
1365
+ nodeName: '#document',
1366
+ nodeType: DOCUMENT_NODE,
821
1367
  /**
822
1368
  * The DocumentType node of the document.
823
1369
  *
824
- * @readonly
825
1370
  * @type DocumentType
1371
+ * @readonly
826
1372
  */
827
- doctype : null,
828
- documentElement : null,
829
- _inc : 1,
1373
+ doctype: null,
1374
+ documentElement: null,
1375
+ _inc: 1,
830
1376
 
831
- insertBefore : function(newChild, refChild){//raises
832
- if(newChild.nodeType == DOCUMENT_FRAGMENT_NODE){
1377
+ insertBefore: function (newChild, refChild) {
1378
+ //raises
1379
+ if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
833
1380
  var child = newChild.firstChild;
834
- while(child){
1381
+ while (child) {
835
1382
  var next = child.nextSibling;
836
- this.insertBefore(child,refChild);
1383
+ this.insertBefore(child, refChild);
837
1384
  child = next;
838
1385
  }
839
1386
  return newChild;
840
1387
  }
841
- if(this.documentElement == null && newChild.nodeType == ELEMENT_NODE){
1388
+ _insertBefore(this, newChild, refChild);
1389
+ newChild.ownerDocument = this;
1390
+ if (this.documentElement === null && newChild.nodeType === ELEMENT_NODE) {
842
1391
  this.documentElement = newChild;
843
1392
  }
844
1393
 
845
- return _insertBefore(this,newChild,refChild),(newChild.ownerDocument = this),newChild;
1394
+ return newChild;
846
1395
  },
847
- removeChild : function(oldChild){
848
- if(this.documentElement == oldChild){
1396
+ removeChild: function (oldChild) {
1397
+ var removed = _removeChild(this, oldChild);
1398
+ if (removed === this.documentElement) {
849
1399
  this.documentElement = null;
850
1400
  }
851
- return _removeChild(this,oldChild);
1401
+ return removed;
1402
+ },
1403
+ replaceChild: function (newChild, oldChild) {
1404
+ //raises
1405
+ _insertBefore(this, newChild, oldChild, assertPreReplacementValidityInDocument);
1406
+ newChild.ownerDocument = this;
1407
+ if (oldChild) {
1408
+ this.removeChild(oldChild);
1409
+ }
1410
+ if (isElementNode(newChild)) {
1411
+ this.documentElement = newChild;
1412
+ }
852
1413
  },
853
1414
  // Introduced in DOM Level 2:
854
- importNode : function(importedNode,deep){
855
- return importNode(this,importedNode,deep);
1415
+ importNode: function (importedNode, deep) {
1416
+ return importNode(this, importedNode, deep);
856
1417
  },
857
1418
  // Introduced in DOM Level 2:
858
- getElementById : function(id){
1419
+ getElementById: function (id) {
859
1420
  var rtv = null;
860
- _visitNode(this.documentElement,function(node){
861
- if(node.nodeType == ELEMENT_NODE){
862
- if(node.getAttribute('id') == id){
1421
+ _visitNode(this.documentElement, function (node) {
1422
+ if (node.nodeType == ELEMENT_NODE) {
1423
+ if (node.getAttribute('id') == id) {
863
1424
  rtv = node;
864
1425
  return true;
865
1426
  }
866
1427
  }
867
- })
1428
+ });
868
1429
  return rtv;
869
1430
  },
870
1431
 
871
1432
  /**
872
- * The `getElementsByClassName` method of `Document` interface returns an array-like object
873
- * of all child elements which have **all** of the given class name(s).
874
- *
875
- * Returns an empty list if `classeNames` is an empty string or only contains HTML white space characters.
1433
+ * The `getElementsByClassName` method of `Document` interface returns an array-like object of
1434
+ * all child elements which have **all** of the given class name(s).
876
1435
  *
1436
+ * Returns an empty list if `classeNames` is an empty string or only contains HTML white space
1437
+ * characters.
877
1438
  *
878
1439
  * Warning: This is a live LiveNodeList.
879
1440
  * Changes in the DOM will reflect in the array as the changes occur.
880
1441
  * If an element selected by this array no longer qualifies for the selector,
881
1442
  * it will automatically be removed. Be aware of this for iteration purposes.
882
1443
  *
883
- * @param {string} classNames is a string representing the class name(s) to match; multiple class names are separated by (ASCII-)whitespace
884
- *
1444
+ * @param {string} classNames
1445
+ * Is a string representing the class name(s) to match; multiple class names are separated by
1446
+ * (ASCII-)whitespace.
885
1447
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName
886
1448
  * @see https://dom.spec.whatwg.org/#concept-getelementsbyclassname
887
1449
  */
888
- getElementsByClassName: function(classNames) {
889
- var classNamesSet = toOrderedSet(classNames)
890
- return new LiveNodeList(this, function(base) {
1450
+ getElementsByClassName: function (classNames) {
1451
+ var classNamesSet = toOrderedSet(classNames);
1452
+ return new LiveNodeList(this, function (base) {
891
1453
  var ls = [];
892
1454
  if (classNamesSet.length > 0) {
893
- _visitNode(base.documentElement, function(node) {
894
- if(node !== base && node.nodeType === ELEMENT_NODE) {
895
- var nodeClassNames = node.getAttribute('class')
1455
+ _visitNode(base.documentElement, function (node) {
1456
+ if (node !== base && node.nodeType === ELEMENT_NODE) {
1457
+ var nodeClassNames = node.getAttribute('class');
896
1458
  // can be null if the attribute does not exist
897
1459
  if (nodeClassNames) {
898
1460
  // before splitting and iterating just compare them for the most common case
899
1461
  var matches = classNames === nodeClassNames;
900
1462
  if (!matches) {
901
- var nodeClassNamesSet = toOrderedSet(nodeClassNames)
902
- matches = classNamesSet.every(arrayIncludes(nodeClassNamesSet))
1463
+ var nodeClassNamesSet = toOrderedSet(nodeClassNames);
1464
+ matches = classNamesSet.every(arrayIncludes(nodeClassNamesSet));
903
1465
  }
904
- if(matches) {
1466
+ if (matches) {
905
1467
  ls.push(node);
906
1468
  }
907
1469
  }
@@ -918,65 +1480,64 @@ Document.prototype = {
918
1480
  * otherwise no transformation is being applied.
919
1481
  * When `contentType` implies the HTML namespace, it will be set as `namespaceURI`.
920
1482
  *
921
- * __This implementation differs from the specification:__
922
- * - The provided name is not checked against the `Name` production,
923
- * so no related error will be thrown.
1483
+ * __This implementation differs from the specification:__ - The provided name is not checked
1484
+ * against the `Name` production,
1485
+ * so no related error will be thrown.
924
1486
  * - There is no interface `HTMLElement`, it is always an `Element`.
925
1487
  * - There is no support for a second argument to indicate using custom elements.
926
1488
  *
927
1489
  * @param {string} tagName
928
- * @return {Element}
929
- *
1490
+ * @returns {Element}
930
1491
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement
931
1492
  * @see https://dom.spec.whatwg.org/#dom-document-createelement
932
1493
  * @see https://dom.spec.whatwg.org/#concept-create-element
933
1494
  */
934
- createElement : function(tagName){
1495
+ createElement: function (tagName) {
935
1496
  var node = new Element();
936
1497
  node.ownerDocument = this;
937
1498
  if (this.type === 'html') {
938
- tagName = tagName.toLowerCase()
1499
+ tagName = tagName.toLowerCase();
939
1500
  }
940
- if (MIME_TYPE.hasDefaultHTMLNamespace(this.contentType)) {
941
- node.namespaceURI = NAMESPACE.HTML
1501
+ if (hasDefaultHTMLNamespace(this.contentType)) {
1502
+ node.namespaceURI = NAMESPACE.HTML;
942
1503
  }
943
1504
  node.nodeName = tagName;
944
1505
  node.tagName = tagName;
945
1506
  node.localName = tagName;
946
1507
  node.childNodes = new NodeList();
947
- var attrs = node.attributes = new NamedNodeMap();
1508
+ var attrs = (node.attributes = new NamedNodeMap());
948
1509
  attrs._ownerElement = node;
949
1510
  return node;
950
1511
  },
951
- createDocumentFragment : function(){
1512
+ createDocumentFragment: function () {
952
1513
  var node = new DocumentFragment();
953
1514
  node.ownerDocument = this;
954
1515
  node.childNodes = new NodeList();
955
1516
  return node;
956
1517
  },
957
- createTextNode : function(data){
1518
+ createTextNode: function (data) {
958
1519
  var node = new Text();
959
1520
  node.ownerDocument = this;
960
- node.appendData(data)
1521
+ node.appendData(data);
961
1522
  return node;
962
1523
  },
963
- createComment : function(data){
1524
+ createComment: function (data) {
964
1525
  var node = new Comment();
965
1526
  node.ownerDocument = this;
966
- node.appendData(data)
1527
+ node.appendData(data);
967
1528
  return node;
968
1529
  },
969
- createCDATASection : function(data){
1530
+ createCDATASection: function (data) {
970
1531
  var node = new CDATASection();
971
1532
  node.ownerDocument = this;
972
- node.appendData(data)
1533
+ node.appendData(data);
973
1534
  return node;
974
1535
  },
975
- createProcessingInstruction : function(target,data){
1536
+ createProcessingInstruction: function (target, data) {
976
1537
  var node = new ProcessingInstruction();
977
1538
  node.ownerDocument = this;
978
- node.tagName = node.target = target;
979
- node.nodeValue= node.data = data;
1539
+ node.nodeName = node.target = target;
1540
+ node.nodeValue = node.data = data;
980
1541
  return node;
981
1542
  },
982
1543
  /**
@@ -984,153 +1545,188 @@ Document.prototype = {
984
1545
  * In HTML Documents `localName` is the lower cased `name`,
985
1546
  * otherwise no transformation is being applied.
986
1547
  *
987
- * __This implementation differs from the specification:__
988
- * - The provided name is not checked against the `Name` production,
989
- * so no related error will be thrown.
1548
+ * __This implementation differs from the specification:__ - The provided name is not checked
1549
+ * against the `Name` production,
1550
+ * so no related error will be thrown.
990
1551
  *
991
1552
  * @param {string} name
992
- * @return {Attr}
993
- *
1553
+ * @returns {Attr}
994
1554
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createAttribute
995
1555
  * @see https://dom.spec.whatwg.org/#dom-document-createattribute
996
1556
  */
997
- createAttribute: function(name){
1557
+ createAttribute: function (name) {
1558
+ if (!g.QName_exact.test(name)) {
1559
+ throw new DOMException(INVALID_CHARACTER_ERR, 'invalid character in name "' + name + '"');
1560
+ }
998
1561
  if (this.type === 'html') {
999
- name = name.toLowerCase()
1562
+ name = name.toLowerCase();
1000
1563
  }
1001
1564
  return this._createAttribute(name);
1002
1565
  },
1003
- _createAttribute: function(name){
1566
+ _createAttribute: function (name) {
1004
1567
  var node = new Attr();
1005
1568
  node.ownerDocument = this;
1006
1569
  node.name = name;
1007
- node.nodeName = name;
1570
+ node.nodeName = name;
1008
1571
  node.localName = name;
1009
1572
  node.specified = true;
1010
1573
  return node;
1011
1574
  },
1012
- createEntityReference : function(name){
1575
+ createEntityReference: function (name) {
1013
1576
  var node = new EntityReference();
1014
- node.ownerDocument = this;
1015
- node.nodeName = name;
1577
+ node.ownerDocument = this;
1578
+ node.nodeName = name;
1016
1579
  return node;
1017
1580
  },
1018
1581
  // Introduced in DOM Level 2:
1019
- createElementNS : function(namespaceURI,qualifiedName){
1582
+ createElementNS: function (namespaceURI, qualifiedName) {
1583
+ var validated = validateAndExtract(namespaceURI, qualifiedName);
1020
1584
  var node = new Element();
1021
- var pl = qualifiedName.split(':');
1022
- var attrs = node.attributes = new NamedNodeMap();
1585
+ var attrs = (node.attributes = new NamedNodeMap());
1023
1586
  node.childNodes = new NodeList();
1024
1587
  node.ownerDocument = this;
1025
1588
  node.nodeName = qualifiedName;
1026
1589
  node.tagName = qualifiedName;
1027
- node.namespaceURI = namespaceURI;
1028
- if(pl.length == 2){
1029
- node.prefix = pl[0];
1030
- node.localName = pl[1];
1031
- }else{
1032
- //el.prefix = null;
1033
- node.localName = qualifiedName;
1034
- }
1590
+ node.namespaceURI = validated[0];
1591
+ node.prefix = validated[1];
1592
+ node.localName = validated[2];
1035
1593
  attrs._ownerElement = node;
1036
1594
  return node;
1037
1595
  },
1038
1596
  // Introduced in DOM Level 2:
1039
- createAttributeNS : function(namespaceURI,qualifiedName){
1597
+ createAttributeNS: function (namespaceURI, qualifiedName) {
1598
+ var validated = validateAndExtract(namespaceURI, qualifiedName);
1040
1599
  var node = new Attr();
1041
1600
  var pl = qualifiedName.split(':');
1042
1601
  node.ownerDocument = this;
1043
1602
  node.nodeName = qualifiedName;
1044
1603
  node.name = qualifiedName;
1045
- node.namespaceURI = namespaceURI;
1046
1604
  node.specified = true;
1047
- if(pl.length == 2){
1048
- node.prefix = pl[0];
1049
- node.localName = pl[1];
1050
- }else{
1051
- //el.prefix = null;
1052
- node.localName = qualifiedName;
1053
- }
1605
+ node.namespaceURI = validated[0];
1606
+ node.prefix = validated[1];
1607
+ node.localName = validated[2];
1054
1608
  return node;
1055
- }
1609
+ },
1056
1610
  };
1057
- _extends(Document,Node);
1058
-
1611
+ _extends(Document, Node);
1059
1612
 
1060
1613
  function Element() {
1061
1614
  this._nsMap = {};
1062
- };
1615
+ }
1063
1616
  Element.prototype = {
1064
- nodeType : ELEMENT_NODE,
1617
+ nodeType: ELEMENT_NODE,
1065
1618
  getQualifiedName: function () {
1066
- return this.prefix ? this.prefix+':'+this.localName : this.localName
1619
+ return this.prefix ? this.prefix + ':' + this.localName : this.localName;
1067
1620
  },
1068
1621
  _isInHTMLDocumentAndNamespace: function () {
1069
1622
  return this.ownerDocument.type === 'html' && this.namespaceURI === NAMESPACE.HTML;
1070
1623
  },
1071
- hasAttribute : function(name){
1072
- return this.getAttributeNode(name)!=null;
1624
+ hasAttribute: function (name) {
1625
+ return !!this.getAttributeNode(name);
1073
1626
  },
1074
- getAttribute : function(name){
1627
+ /**
1628
+ * Returns element’s first attribute whose qualified name is `name`, and `null`
1629
+ * if there is no such attribute.
1630
+ *
1631
+ * @param {string} name
1632
+ * @returns {string | null}
1633
+ */
1634
+ getAttribute: function (name) {
1075
1635
  var attr = this.getAttributeNode(name);
1076
- return attr && attr.value || '';
1636
+ return attr ? attr.value : null;
1077
1637
  },
1078
- getAttributeNode : function(name){
1638
+ getAttributeNode: function (name) {
1079
1639
  if (this._isInHTMLDocumentAndNamespace()) {
1080
- name = name.toLowerCase()
1640
+ name = name.toLowerCase();
1081
1641
  }
1082
1642
  return this.attributes.getNamedItem(name);
1083
1643
  },
1084
- setAttribute : function(name, value){
1644
+ /**
1645
+ * Sets the value of element’s first attribute whose qualified name is qualifiedName to value.
1646
+ *
1647
+ * @param {string} name
1648
+ * @param {string} value
1649
+ */
1650
+ setAttribute: function (name, value) {
1085
1651
  if (this._isInHTMLDocumentAndNamespace()) {
1086
- name = name.toLowerCase()
1652
+ name = name.toLowerCase();
1653
+ }
1654
+ var attr = this.getAttributeNode(name);
1655
+ if (attr) {
1656
+ attr.value = attr.nodeValue = '' + value;
1657
+ } else {
1658
+ attr = this.ownerDocument._createAttribute(name);
1659
+ attr.value = attr.nodeValue = '' + value;
1660
+ this.setAttributeNode(attr);
1087
1661
  }
1088
- var attr = this.ownerDocument._createAttribute(name)
1089
- attr.value = attr.nodeValue = "" + value;
1090
- this.setAttributeNode(attr)
1091
1662
  },
1092
- removeAttribute : function(name){
1093
- var attr = this.getAttributeNode(name)
1663
+ removeAttribute: function (name) {
1664
+ var attr = this.getAttributeNode(name);
1094
1665
  attr && this.removeAttributeNode(attr);
1095
1666
  },
1096
1667
 
1097
1668
  // four real operation method
1098
- appendChild:function(newChild){
1099
- if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
1100
- return this.insertBefore(newChild,null);
1101
- }else{
1102
- return _appendSingleChild(this,newChild);
1669
+ appendChild: function (newChild) {
1670
+ if (newChild.nodeType === DOCUMENT_FRAGMENT_NODE) {
1671
+ return this.insertBefore(newChild, null);
1672
+ } else {
1673
+ return _appendSingleChild(this, newChild);
1103
1674
  }
1104
1675
  },
1105
- setAttributeNode : function(newAttr){
1676
+ setAttributeNode: function (newAttr) {
1106
1677
  return this.attributes.setNamedItem(newAttr);
1107
1678
  },
1108
- setAttributeNodeNS : function(newAttr){
1679
+ setAttributeNodeNS: function (newAttr) {
1109
1680
  return this.attributes.setNamedItemNS(newAttr);
1110
1681
  },
1111
- removeAttributeNode : function(oldAttr){
1682
+ removeAttributeNode: function (oldAttr) {
1112
1683
  //console.log(this == oldAttr.ownerElement)
1113
1684
  return this.attributes.removeNamedItem(oldAttr.nodeName);
1114
1685
  },
1115
1686
  //get real attribute name,and remove it by removeAttributeNode
1116
- removeAttributeNS : function(namespaceURI, localName){
1687
+ removeAttributeNS: function (namespaceURI, localName) {
1117
1688
  var old = this.getAttributeNodeNS(namespaceURI, localName);
1118
1689
  old && this.removeAttributeNode(old);
1119
1690
  },
1120
1691
 
1121
- hasAttributeNS : function(namespaceURI, localName){
1122
- return this.getAttributeNodeNS(namespaceURI, localName)!=null;
1692
+ hasAttributeNS: function (namespaceURI, localName) {
1693
+ return this.getAttributeNodeNS(namespaceURI, localName) != null;
1123
1694
  },
1124
- getAttributeNS : function(namespaceURI, localName){
1695
+ /**
1696
+ * Returns element’s attribute whose namespace is `namespaceURI` and local name is
1697
+ * `localName`,
1698
+ * or `null` if there is no such attribute.
1699
+ *
1700
+ * @param {string} namespaceURI
1701
+ * @param {string} localName
1702
+ * @returns {string | null}
1703
+ */
1704
+ getAttributeNS: function (namespaceURI, localName) {
1125
1705
  var attr = this.getAttributeNodeNS(namespaceURI, localName);
1126
- return attr && attr.value || '';
1706
+ return attr ? attr.value : null;
1127
1707
  },
1128
- setAttributeNS : function(namespaceURI, qualifiedName, value){
1129
- var attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);
1130
- attr.value = attr.nodeValue = "" + value;
1131
- this.setAttributeNode(attr)
1708
+ /**
1709
+ * Sets the value of element’s attribute whose namespace is `namespaceURI` and local name is
1710
+ * `localName` to value.
1711
+ *
1712
+ * @param {string} namespaceURI
1713
+ * @param {string} qualifiedName
1714
+ * @param {string} value
1715
+ * @see https://dom.spec.whatwg.org/#dom-element-setattributens
1716
+ */
1717
+ setAttributeNS: function (namespaceURI, qualifiedName, value) {
1718
+ var validated = validateAndExtract(namespaceURI, qualifiedName);
1719
+ var localName = validated[2];
1720
+ var attr = this.getAttributeNodeNS(namespaceURI, localName);
1721
+ if (attr) {
1722
+ attr.value = attr.nodeValue = '' + value;
1723
+ } else {
1724
+ attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);
1725
+ attr.value = attr.nodeValue = '' + value;
1726
+ this.setAttributeNode(attr);
1727
+ }
1132
1728
  },
1133
- getAttributeNodeNS : function(namespaceURI, localName){
1729
+ getAttributeNodeNS: function (namespaceURI, localName) {
1134
1730
  return this.attributes.getNamedItemNS(namespaceURI, localName);
1135
1731
  },
1136
1732
 
@@ -1145,8 +1741,8 @@ Element.prototype = {
1145
1741
  *
1146
1742
  * When called on an HTML element in an HTML document,
1147
1743
  * `getElementsByTagName` lower-cases the argument before searching for it.
1148
- * This is undesirable when trying to match camel-cased SVG elements
1149
- * (such as `<linearGradient>`) in an HTML document.
1744
+ * This is undesirable when trying to match camel-cased SVG elements (such as
1745
+ * `<linearGradient>`) in an HTML document.
1150
1746
  * Instead, use `Element.getElementsByTagNameNS()`,
1151
1747
  * which preserves the capitalization of the tag name.
1152
1748
  *
@@ -1154,28 +1750,25 @@ Element.prototype = {
1154
1750
  * except that it only searches for elements that are descendants of the specified element.
1155
1751
  *
1156
1752
  * @param {string} qualifiedName
1157
- * @return {LiveNodeList}
1158
- *
1753
+ * @returns {LiveNodeList}
1159
1754
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByTagName
1160
1755
  * @see https://dom.spec.whatwg.org/#concept-getelementsbytagname
1161
1756
  */
1162
- getElementsByTagName : function(qualifiedName){
1163
- var isHTMLDocument = (this.nodeType === DOCUMENT_NODE ? this : this.ownerDocument).type === 'html'
1164
- var lowerQualifiedName = qualifiedName.toLowerCase()
1165
- return new LiveNodeList(this,function(base){
1757
+ getElementsByTagName: function (qualifiedName) {
1758
+ var isHTMLDocument = (this.nodeType === DOCUMENT_NODE ? this : this.ownerDocument).type === 'html';
1759
+ var lowerQualifiedName = qualifiedName.toLowerCase();
1760
+ return new LiveNodeList(this, function (base) {
1166
1761
  var ls = [];
1167
- _visitNode(base, function(node) {
1168
- if (node === base || node.nodeType !== ELEMENT_NODE) {
1169
- return
1762
+ _visitNode(base, function (node) {
1763
+ if (node === base || node.nodeType !== ELEMENT_NODE) {
1764
+ return;
1170
1765
  }
1171
1766
  if (qualifiedName === '*') {
1172
1767
  ls.push(node);
1173
1768
  } else {
1174
1769
  var nodeQualifiedName = node.getQualifiedName();
1175
- var matchingQName = isHTMLDocument && node.namespaceURI === NAMESPACE.HTML
1176
- ? lowerQualifiedName
1177
- : qualifiedName
1178
- if(nodeQualifiedName === matchingQName){
1770
+ var matchingQName = isHTMLDocument && node.namespaceURI === NAMESPACE.HTML ? lowerQualifiedName : qualifiedName;
1771
+ if (nodeQualifiedName === matchingQName) {
1179
1772
  ls.push(node);
1180
1773
  }
1181
1774
  }
@@ -1183,149 +1776,141 @@ Element.prototype = {
1183
1776
  return ls;
1184
1777
  });
1185
1778
  },
1186
- getElementsByTagNameNS : function(namespaceURI, localName){
1187
- return new LiveNodeList(this,function(base){
1779
+ getElementsByTagNameNS: function (namespaceURI, localName) {
1780
+ return new LiveNodeList(this, function (base) {
1188
1781
  var ls = [];
1189
- _visitNode(base,function(node){
1190
- if(node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)){
1782
+ _visitNode(base, function (node) {
1783
+ if (
1784
+ node !== base &&
1785
+ node.nodeType === ELEMENT_NODE &&
1786
+ (namespaceURI === '*' || node.namespaceURI === namespaceURI) &&
1787
+ (localName === '*' || node.localName == localName)
1788
+ ) {
1191
1789
  ls.push(node);
1192
1790
  }
1193
1791
  });
1194
1792
  return ls;
1195
-
1196
1793
  });
1197
- }
1794
+ },
1198
1795
  };
1199
1796
  Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;
1200
1797
  Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;
1201
1798
 
1202
-
1203
- _extends(Element,Node);
1799
+ _extends(Element, Node);
1204
1800
  function Attr() {
1205
- };
1801
+ this.namespaceURI = null;
1802
+ this.prefix = null;
1803
+ this.ownerElement = null;
1804
+ }
1206
1805
  Attr.prototype.nodeType = ATTRIBUTE_NODE;
1207
- _extends(Attr,Node);
1208
-
1806
+ _extends(Attr, Node);
1209
1807
 
1210
- function CharacterData() {
1211
- };
1808
+ function CharacterData() {}
1212
1809
  CharacterData.prototype = {
1213
- data : '',
1214
- substringData : function(offset, count) {
1215
- return this.data.substring(offset, offset+count);
1810
+ data: '',
1811
+ substringData: function (offset, count) {
1812
+ return this.data.substring(offset, offset + count);
1216
1813
  },
1217
- appendData: function(text) {
1218
- text = this.data+text;
1814
+ appendData: function (text) {
1815
+ text = this.data + text;
1219
1816
  this.nodeValue = this.data = text;
1220
1817
  this.length = text.length;
1221
1818
  },
1222
- insertData: function(offset,text) {
1223
- this.replaceData(offset,0,text);
1224
-
1819
+ insertData: function (offset, text) {
1820
+ this.replaceData(offset, 0, text);
1225
1821
  },
1226
- appendChild:function(newChild){
1227
- throw new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR])
1822
+ appendChild: function (newChild) {
1823
+ throw new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR]);
1228
1824
  },
1229
- deleteData: function(offset, count) {
1230
- this.replaceData(offset,count,"");
1825
+ deleteData: function (offset, count) {
1826
+ this.replaceData(offset, count, '');
1231
1827
  },
1232
- replaceData: function(offset, count, text) {
1233
- var start = this.data.substring(0,offset);
1234
- var end = this.data.substring(offset+count);
1828
+ replaceData: function (offset, count, text) {
1829
+ var start = this.data.substring(0, offset);
1830
+ var end = this.data.substring(offset + count);
1235
1831
  text = start + text + end;
1236
1832
  this.nodeValue = this.data = text;
1237
1833
  this.length = text.length;
1238
- }
1239
- }
1240
- _extends(CharacterData,Node);
1241
- function Text() {
1834
+ },
1242
1835
  };
1836
+ _extends(CharacterData, Node);
1837
+ function Text() {}
1243
1838
  Text.prototype = {
1244
- nodeName : "#text",
1245
- nodeType : TEXT_NODE,
1246
- splitText : function(offset) {
1839
+ nodeName: '#text',
1840
+ nodeType: TEXT_NODE,
1841
+ splitText: function (offset) {
1247
1842
  var text = this.data;
1248
1843
  var newText = text.substring(offset);
1249
1844
  text = text.substring(0, offset);
1250
1845
  this.data = this.nodeValue = text;
1251
1846
  this.length = text.length;
1252
1847
  var newNode = this.ownerDocument.createTextNode(newText);
1253
- if(this.parentNode){
1848
+ if (this.parentNode) {
1254
1849
  this.parentNode.insertBefore(newNode, this.nextSibling);
1255
1850
  }
1256
1851
  return newNode;
1257
- }
1258
- }
1259
- _extends(Text,CharacterData);
1260
- function Comment() {
1852
+ },
1261
1853
  };
1854
+ _extends(Text, CharacterData);
1855
+ function Comment() {}
1262
1856
  Comment.prototype = {
1263
- nodeName : "#comment",
1264
- nodeType : COMMENT_NODE
1265
- }
1266
- _extends(Comment,CharacterData);
1267
-
1268
- function CDATASection() {
1857
+ nodeName: '#comment',
1858
+ nodeType: COMMENT_NODE,
1269
1859
  };
1270
- CDATASection.prototype = {
1271
- nodeName : "#cdata-section",
1272
- nodeType : CDATA_SECTION_NODE
1273
- }
1274
- _extends(CDATASection,CharacterData);
1275
-
1860
+ _extends(Comment, CharacterData);
1276
1861
 
1277
- function DocumentType() {
1862
+ function CDATASection() {}
1863
+ CDATASection.prototype = {
1864
+ nodeName: '#cdata-section',
1865
+ nodeType: CDATA_SECTION_NODE,
1278
1866
  };
1867
+ _extends(CDATASection, CharacterData);
1868
+
1869
+ function DocumentType() {}
1279
1870
  DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
1280
- _extends(DocumentType,Node);
1871
+ _extends(DocumentType, Node);
1281
1872
 
1282
- function Notation() {
1283
- };
1873
+ function Notation() {}
1284
1874
  Notation.prototype.nodeType = NOTATION_NODE;
1285
- _extends(Notation,Node);
1875
+ _extends(Notation, Node);
1286
1876
 
1287
- function Entity() {
1288
- };
1877
+ function Entity() {}
1289
1878
  Entity.prototype.nodeType = ENTITY_NODE;
1290
- _extends(Entity,Node);
1879
+ _extends(Entity, Node);
1291
1880
 
1292
- function EntityReference() {
1293
- };
1881
+ function EntityReference() {}
1294
1882
  EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
1295
- _extends(EntityReference,Node);
1296
-
1297
- function DocumentFragment() {
1298
- };
1299
- DocumentFragment.prototype.nodeName = "#document-fragment";
1300
- DocumentFragment.prototype.nodeType = DOCUMENT_FRAGMENT_NODE;
1301
- _extends(DocumentFragment,Node);
1883
+ _extends(EntityReference, Node);
1302
1884
 
1885
+ function DocumentFragment() {}
1886
+ DocumentFragment.prototype.nodeName = '#document-fragment';
1887
+ DocumentFragment.prototype.nodeType = DOCUMENT_FRAGMENT_NODE;
1888
+ _extends(DocumentFragment, Node);
1303
1889
 
1304
- function ProcessingInstruction() {
1305
- }
1890
+ function ProcessingInstruction() {}
1306
1891
  ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
1307
- _extends(ProcessingInstruction,Node);
1308
- function XMLSerializer(){}
1892
+ _extends(ProcessingInstruction, Node);
1893
+ function XMLSerializer() {}
1309
1894
  XMLSerializer.prototype.serializeToString = function (node, nodeFilter) {
1310
1895
  return nodeSerializeToString.call(node, nodeFilter);
1311
- }
1896
+ };
1312
1897
  Node.prototype.toString = nodeSerializeToString;
1313
1898
  function nodeSerializeToString(nodeFilter) {
1314
1899
  var buf = [];
1315
- var refNode = this.nodeType === DOCUMENT_NODE && this.documentElement || this;
1900
+ var refNode = (this.nodeType === DOCUMENT_NODE && this.documentElement) || this;
1316
1901
  var prefix = refNode.prefix;
1317
1902
  var uri = refNode.namespaceURI;
1318
1903
 
1319
- if(uri && prefix == null){
1904
+ if (uri && prefix == null) {
1320
1905
  var prefix = refNode.lookupPrefix(uri);
1321
- if(prefix == null){
1322
- var visibleNamespaces=[
1323
- {namespace:uri,prefix:null}
1324
- //{namespace:uri,prefix:''}
1325
- ]
1906
+ if (prefix == null) {
1907
+ var visibleNamespaces = [
1908
+ { namespace: uri, prefix: null },
1909
+ //{namespace:uri,prefix:''}
1910
+ ];
1326
1911
  }
1327
1912
  }
1328
- serializeToString(this,buf,nodeFilter,visibleNamespaces);
1913
+ serializeToString(this, buf, nodeFilter, visibleNamespaces);
1329
1914
  return buf.join('');
1330
1915
  }
1331
1916
 
@@ -1342,11 +1927,11 @@ function needNamespaceDefine(node, isHTML, visibleNamespaces) {
1342
1927
  if (!uri) {
1343
1928
  return false;
1344
1929
  }
1345
- if (prefix === "xml" && uri === NAMESPACE.XML || uri === NAMESPACE.XMLNS) {
1930
+ if ((prefix === 'xml' && uri === NAMESPACE.XML) || uri === NAMESPACE.XMLNS) {
1346
1931
  return false;
1347
1932
  }
1348
1933
 
1349
- var i = visibleNamespaces.length
1934
+ var i = visibleNamespaces.length;
1350
1935
  while (i--) {
1351
1936
  var ns = visibleNamespaces[i];
1352
1937
  // get namespace prefix
@@ -1357,247 +1942,249 @@ function needNamespaceDefine(node, isHTML, visibleNamespaces) {
1357
1942
  return true;
1358
1943
  }
1359
1944
  /**
1360
- * Well-formed constraint: No < in Attribute Values
1945
+ * Literal whitespace other than space that appear in attribute values are serialized as
1946
+ * their entity references, so they will be preserved.
1947
+ * (In contrast to whitespace literals in the input which are normalized to spaces).
1948
+ *
1949
+ * Well-formed constraint: No < in Attribute Values:
1361
1950
  * > The replacement text of any entity referred to directly or indirectly
1362
1951
  * > in an attribute value must not contain a <.
1952
+ *
1363
1953
  * @see https://www.w3.org/TR/xml11/#CleanAttrVals
1364
1954
  * @see https://www.w3.org/TR/xml11/#NT-AttValue
1365
- *
1366
- * Literal whitespace other than space that appear in attribute values
1367
- * are serialized as their entity references, so they will be preserved.
1368
- * (In contrast to whitespace literals in the input which are normalized to spaces)
1369
1955
  * @see https://www.w3.org/TR/xml11/#AVNormalize
1370
1956
  * @see https://w3c.github.io/DOM-Parsing/#serializing-an-element-s-attributes
1957
+ * @prettierignore
1371
1958
  */
1372
1959
  function addSerializedAttribute(buf, qualifiedName, value) {
1373
- buf.push(' ', qualifiedName, '="', value.replace(/[<>&"\t\n\r]/g, _xmlEncoder), '"')
1960
+ buf.push(' ', qualifiedName, '="', value.replace(/[<>&"\t\n\r]/g, _xmlEncoder), '"');
1374
1961
  }
1375
1962
 
1376
- function serializeToString (node, buf, nodeFilter, visibleNamespaces) {
1963
+ function serializeToString(node, buf, nodeFilter, visibleNamespaces) {
1377
1964
  if (!visibleNamespaces) {
1378
1965
  visibleNamespaces = [];
1379
1966
  }
1380
- var doc = node.nodeType === DOCUMENT_NODE ? node : node.ownerDocument
1381
- var isHTML = doc.type === 'html'
1967
+ var doc = node.nodeType === DOCUMENT_NODE ? node : node.ownerDocument;
1968
+ var isHTML = doc.type === 'html';
1382
1969
 
1383
- if(nodeFilter){
1970
+ if (nodeFilter) {
1384
1971
  node = nodeFilter(node);
1385
- if(node){
1386
- if(typeof node == 'string'){
1972
+ if (node) {
1973
+ if (typeof node == 'string') {
1387
1974
  buf.push(node);
1388
1975
  return;
1389
1976
  }
1390
- }else{
1977
+ } else {
1391
1978
  return;
1392
1979
  }
1393
1980
  //buf.sort.apply(attrs, attributeSorter);
1394
1981
  }
1395
1982
 
1396
- switch(node.nodeType){
1397
- case ELEMENT_NODE:
1398
- var attrs = node.attributes;
1399
- var len = attrs.length;
1400
- var child = node.firstChild;
1401
- var nodeName = node.tagName;
1402
-
1403
- var prefixedNodeName = nodeName
1404
- if (!isHTML && !node.prefix && node.namespaceURI) {
1405
- var defaultNS
1406
- // lookup current default ns from `xmlns` attribute
1407
- for (var ai = 0; ai < attrs.length; ai++) {
1408
- if (attrs.item(ai).name === 'xmlns') {
1409
- defaultNS = attrs.item(ai).value
1410
- break
1983
+ switch (node.nodeType) {
1984
+ case ELEMENT_NODE:
1985
+ var attrs = node.attributes;
1986
+ var len = attrs.length;
1987
+ var child = node.firstChild;
1988
+ var nodeName = node.tagName;
1989
+
1990
+ var prefixedNodeName = nodeName;
1991
+ if (!isHTML && !node.prefix && node.namespaceURI) {
1992
+ var defaultNS;
1993
+ // lookup current default ns from `xmlns` attribute
1994
+ for (var ai = 0; ai < attrs.length; ai++) {
1995
+ if (attrs.item(ai).name === 'xmlns') {
1996
+ defaultNS = attrs.item(ai).value;
1997
+ break;
1998
+ }
1411
1999
  }
1412
- }
1413
- if (!defaultNS) {
1414
- // lookup current default ns in visibleNamespaces
1415
- for (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) {
1416
- var namespace = visibleNamespaces[nsi]
1417
- if (namespace.prefix === '' && namespace.namespace === node.namespaceURI) {
1418
- defaultNS = namespace.namespace
1419
- break
2000
+ if (!defaultNS) {
2001
+ // lookup current default ns in visibleNamespaces
2002
+ for (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) {
2003
+ var namespace = visibleNamespaces[nsi];
2004
+ if (namespace.prefix === '' && namespace.namespace === node.namespaceURI) {
2005
+ defaultNS = namespace.namespace;
2006
+ break;
2007
+ }
1420
2008
  }
1421
2009
  }
1422
- }
1423
- if (defaultNS !== node.namespaceURI) {
1424
- for (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) {
1425
- var namespace = visibleNamespaces[nsi]
1426
- if (namespace.namespace === node.namespaceURI) {
1427
- if (namespace.prefix) {
1428
- prefixedNodeName = namespace.prefix + ':' + nodeName
2010
+ if (defaultNS !== node.namespaceURI) {
2011
+ for (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) {
2012
+ var namespace = visibleNamespaces[nsi];
2013
+ if (namespace.namespace === node.namespaceURI) {
2014
+ if (namespace.prefix) {
2015
+ prefixedNodeName = namespace.prefix + ':' + nodeName;
2016
+ }
2017
+ break;
1429
2018
  }
1430
- break
1431
2019
  }
1432
2020
  }
1433
2021
  }
1434
- }
1435
-
1436
- buf.push('<', prefixedNodeName);
1437
2022
 
1438
- for(var i=0;i<len;i++){
1439
- // add namespaces for attributes
1440
- var attr = attrs.item(i);
1441
- if (attr.prefix == 'xmlns') {
1442
- visibleNamespaces.push({ prefix: attr.localName, namespace: attr.value });
1443
- }else if(attr.nodeName == 'xmlns'){
1444
- visibleNamespaces.push({ prefix: '', namespace: attr.value });
2023
+ buf.push('<', prefixedNodeName);
2024
+
2025
+ for (var i = 0; i < len; i++) {
2026
+ // add namespaces for attributes
2027
+ var attr = attrs.item(i);
2028
+ if (attr.prefix == 'xmlns') {
2029
+ visibleNamespaces.push({
2030
+ prefix: attr.localName,
2031
+ namespace: attr.value,
2032
+ });
2033
+ } else if (attr.nodeName == 'xmlns') {
2034
+ visibleNamespaces.push({ prefix: '', namespace: attr.value });
2035
+ }
1445
2036
  }
1446
- }
1447
2037
 
1448
- for(var i=0;i<len;i++){
1449
- var attr = attrs.item(i);
1450
- if (needNamespaceDefine(attr,isHTML, visibleNamespaces)) {
1451
- var prefix = attr.prefix||'';
1452
- var uri = attr.namespaceURI;
1453
- addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : "xmlns", uri);
1454
- visibleNamespaces.push({ prefix: prefix, namespace:uri });
2038
+ for (var i = 0; i < len; i++) {
2039
+ var attr = attrs.item(i);
2040
+ if (needNamespaceDefine(attr, isHTML, visibleNamespaces)) {
2041
+ var prefix = attr.prefix || '';
2042
+ var uri = attr.namespaceURI;
2043
+ addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : 'xmlns', uri);
2044
+ visibleNamespaces.push({ prefix: prefix, namespace: uri });
2045
+ }
2046
+ serializeToString(attr, buf, nodeFilter, visibleNamespaces);
1455
2047
  }
1456
- serializeToString(attr,buf,nodeFilter,visibleNamespaces);
1457
- }
1458
2048
 
1459
- // add namespace for current node
1460
- if (nodeName === prefixedNodeName && needNamespaceDefine(node, isHTML, visibleNamespaces)) {
1461
- var prefix = node.prefix||'';
1462
- var uri = node.namespaceURI;
1463
- addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : "xmlns", uri);
1464
- visibleNamespaces.push({ prefix: prefix, namespace:uri });
1465
- }
1466
- // in XML elements can be closed when they have no children
1467
- var canCloseTag = !child;
1468
- if (canCloseTag && (isHTML || NAMESPACE.isHTML(node.namespaceURI))) {
1469
- // in HTML (doc or ns) only void elements can be closed right away
1470
- canCloseTag = isHTMLVoidElement(nodeName)
1471
- }
1472
- if (canCloseTag) {
1473
- buf.push("/>");
1474
- } else {
1475
- buf.push(">");
1476
- //if is cdata child node
1477
- if (isHTML && isHTMLRawTextElement(nodeName)) {
1478
- while(child){
1479
- if(child.data){
1480
- buf.push(child.data);
1481
- }else{
2049
+ // add namespace for current node
2050
+ if (nodeName === prefixedNodeName && needNamespaceDefine(node, isHTML, visibleNamespaces)) {
2051
+ var prefix = node.prefix || '';
2052
+ var uri = node.namespaceURI;
2053
+ addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : 'xmlns', uri);
2054
+ visibleNamespaces.push({ prefix: prefix, namespace: uri });
2055
+ }
2056
+ // in XML elements can be closed when they have no children
2057
+ var canCloseTag = !child;
2058
+ if (canCloseTag && (isHTML || node.namespaceURI === NAMESPACE.HTML)) {
2059
+ // in HTML (doc or ns) only void elements can be closed right away
2060
+ canCloseTag = isHTMLVoidElement(nodeName);
2061
+ }
2062
+ if (canCloseTag) {
2063
+ buf.push('/>');
2064
+ } else {
2065
+ buf.push('>');
2066
+ //if is cdata child node
2067
+ if (isHTML && isHTMLRawTextElement(nodeName)) {
2068
+ while (child) {
2069
+ if (child.data) {
2070
+ buf.push(child.data);
2071
+ } else {
2072
+ serializeToString(child, buf, nodeFilter, visibleNamespaces.slice());
2073
+ }
2074
+ child = child.nextSibling;
2075
+ }
2076
+ } else {
2077
+ while (child) {
1482
2078
  serializeToString(child, buf, nodeFilter, visibleNamespaces.slice());
2079
+ child = child.nextSibling;
1483
2080
  }
1484
- child = child.nextSibling;
1485
2081
  }
1486
- } else {
1487
- while(child){
1488
- serializeToString(child, buf, nodeFilter, visibleNamespaces.slice());
1489
- child = child.nextSibling;
2082
+ buf.push('</', prefixedNodeName, '>');
2083
+ }
2084
+ // remove added visible namespaces
2085
+ //visibleNamespaces.length = startVisibleNamespaces;
2086
+ return;
2087
+ case DOCUMENT_NODE:
2088
+ case DOCUMENT_FRAGMENT_NODE:
2089
+ var child = node.firstChild;
2090
+ while (child) {
2091
+ serializeToString(child, buf, nodeFilter, visibleNamespaces.slice());
2092
+ child = child.nextSibling;
2093
+ }
2094
+ return;
2095
+ case ATTRIBUTE_NODE:
2096
+ return addSerializedAttribute(buf, node.name, node.value);
2097
+ case TEXT_NODE:
2098
+ /*
2099
+ * The ampersand character (&) and the left angle bracket (<) must not appear in their literal form,
2100
+ * except when used as markup delimiters, or within a comment, a processing instruction,
2101
+ * or a CDATA section.
2102
+ * If they are needed elsewhere, they must be escaped using either numeric character
2103
+ * references or the strings `&amp;` and `&lt;` respectively.
2104
+ * The right angle bracket (>) may be represented using the string " &gt; ",
2105
+ * and must, for compatibility, be escaped using either `&gt;`,
2106
+ * or a character reference when it appears in the string `]]>` in content,
2107
+ * when that string is not marking the end of a CDATA section.
2108
+ *
2109
+ * In the content of elements, character data is any string of characters which does not
2110
+ * contain the start-delimiter of any markup and does not include the CDATA-section-close
2111
+ * delimiter, `]]>`.
2112
+ *
2113
+ * @see https://www.w3.org/TR/xml/#NT-CharData
2114
+ * @see https://w3c.github.io/DOM-Parsing/#xml-serializing-a-text-node
2115
+ */
2116
+ return buf.push(node.data.replace(/[<&>]/g, _xmlEncoder));
2117
+ case CDATA_SECTION_NODE:
2118
+ return buf.push(g.CDATA_START, node.data, g.CDATA_END);
2119
+ case COMMENT_NODE:
2120
+ return buf.push(g.COMMENT_START, node.data, g.COMMENT_END);
2121
+ case DOCUMENT_TYPE_NODE:
2122
+ var pubid = node.publicId;
2123
+ var sysid = node.systemId;
2124
+ buf.push(g.DOCTYPE_DECL_START, ' ', node.name);
2125
+ if (pubid) {
2126
+ buf.push(' ', g.PUBLIC, ' ', pubid);
2127
+ if (sysid && sysid !== '.') {
2128
+ buf.push(' ', sysid);
1490
2129
  }
2130
+ } else if (sysid && sysid !== '.') {
2131
+ buf.push(' ', g.SYSTEM, ' ', sysid);
1491
2132
  }
1492
- buf.push("</", prefixedNodeName, ">");
1493
- }
1494
- // remove added visible namespaces
1495
- //visibleNamespaces.length = startVisibleNamespaces;
1496
- return;
1497
- case DOCUMENT_NODE:
1498
- case DOCUMENT_FRAGMENT_NODE:
1499
- var child = node.firstChild;
1500
- while(child){
1501
- serializeToString(child, buf, nodeFilter, visibleNamespaces.slice());
1502
- child = child.nextSibling;
1503
- }
1504
- return;
1505
- case ATTRIBUTE_NODE:
1506
- return addSerializedAttribute(buf, node.name, node.value);
1507
- case TEXT_NODE:
1508
- /**
1509
- * The ampersand character (&) and the left angle bracket (<) must not appear in their literal form,
1510
- * except when used as markup delimiters, or within a comment, a processing instruction, or a CDATA section.
1511
- * If they are needed elsewhere, they must be escaped using either numeric character references or the strings
1512
- * `&amp;` and `&lt;` respectively.
1513
- * The right angle bracket (>) may be represented using the string " &gt; ", and must, for compatibility,
1514
- * be escaped using either `&gt;` or a character reference when it appears in the string `]]>` in content,
1515
- * when that string is not marking the end of a CDATA section.
1516
- *
1517
- * In the content of elements, character data is any string of characters
1518
- * which does not contain the start-delimiter of any markup
1519
- * and does not include the CDATA-section-close delimiter, `]]>`.
1520
- *
1521
- * @see https://www.w3.org/TR/xml/#NT-CharData
1522
- * @see https://w3c.github.io/DOM-Parsing/#xml-serializing-a-text-node
1523
- */
1524
- return buf.push(node.data
1525
- .replace(/[<&>]/g,_xmlEncoder)
1526
- );
1527
- case CDATA_SECTION_NODE:
1528
- return buf.push( '<![CDATA[',node.data,']]>');
1529
- case COMMENT_NODE:
1530
- return buf.push( "<!--",node.data,"-->");
1531
- case DOCUMENT_TYPE_NODE:
1532
- var pubid = node.publicId;
1533
- var sysid = node.systemId;
1534
- buf.push('<!DOCTYPE ',node.name);
1535
- if(pubid){
1536
- buf.push(' PUBLIC ', pubid);
1537
- if (sysid && sysid!='.') {
1538
- buf.push(' ', sysid);
2133
+ if (node.internalSubset) {
2134
+ buf.push(' [', node.internalSubset, ']');
1539
2135
  }
1540
2136
  buf.push('>');
1541
- }else if(sysid && sysid!='.'){
1542
- buf.push(' SYSTEM ', sysid, '>');
1543
- }else{
1544
- var sub = node.internalSubset;
1545
- if(sub){
1546
- buf.push(" [",sub,"]");
1547
- }
1548
- buf.push(">");
1549
- }
1550
- return;
1551
- case PROCESSING_INSTRUCTION_NODE:
1552
- return buf.push( "<?",node.target," ",node.data,"?>");
1553
- case ENTITY_REFERENCE_NODE:
1554
- return buf.push( '&',node.nodeName,';');
1555
- //case ENTITY_NODE:
1556
- //case NOTATION_NODE:
1557
- default:
1558
- buf.push('??',node.nodeName);
2137
+ return;
2138
+ case PROCESSING_INSTRUCTION_NODE:
2139
+ return buf.push('<?', node.target, ' ', node.data, '?>');
2140
+ case ENTITY_REFERENCE_NODE:
2141
+ return buf.push('&', node.nodeName, ';');
2142
+ //case ENTITY_NODE:
2143
+ //case NOTATION_NODE:
2144
+ default:
2145
+ buf.push('??', node.nodeName);
1559
2146
  }
1560
2147
  }
1561
- function importNode(doc,node,deep){
2148
+ function importNode(doc, node, deep) {
1562
2149
  var node2;
1563
2150
  switch (node.nodeType) {
1564
- case ELEMENT_NODE:
1565
- node2 = node.cloneNode(false);
1566
- node2.ownerDocument = doc;
2151
+ case ELEMENT_NODE:
2152
+ node2 = node.cloneNode(false);
2153
+ node2.ownerDocument = doc;
1567
2154
  //var attrs = node2.attributes;
1568
2155
  //var len = attrs.length;
1569
2156
  //for(var i=0;i<len;i++){
1570
- //node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));
2157
+ //node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));
1571
2158
  //}
1572
- case DOCUMENT_FRAGMENT_NODE:
1573
- break;
1574
- case ATTRIBUTE_NODE:
1575
- deep = true;
1576
- break;
1577
- //case ENTITY_REFERENCE_NODE:
1578
- //case PROCESSING_INSTRUCTION_NODE:
1579
- ////case TEXT_NODE:
1580
- //case CDATA_SECTION_NODE:
1581
- //case COMMENT_NODE:
1582
- // deep = false;
1583
- // break;
1584
- //case DOCUMENT_NODE:
1585
- //case DOCUMENT_TYPE_NODE:
1586
- //cannot be imported.
1587
- //case ENTITY_NODE:
1588
- //case NOTATION_NODE:
1589
- //can not hit in level3
1590
- //default:throw e;
2159
+ case DOCUMENT_FRAGMENT_NODE:
2160
+ break;
2161
+ case ATTRIBUTE_NODE:
2162
+ deep = true;
2163
+ break;
2164
+ //case ENTITY_REFERENCE_NODE:
2165
+ //case PROCESSING_INSTRUCTION_NODE:
2166
+ ////case TEXT_NODE:
2167
+ //case CDATA_SECTION_NODE:
2168
+ //case COMMENT_NODE:
2169
+ // deep = false;
2170
+ // break;
2171
+ //case DOCUMENT_NODE:
2172
+ //case DOCUMENT_TYPE_NODE:
2173
+ //cannot be imported.
2174
+ //case ENTITY_NODE:
2175
+ //case NOTATION_NODE:
2176
+ //can not hit in level3
2177
+ //default:throw e;
1591
2178
  }
1592
- if(!node2){
1593
- node2 = node.cloneNode(false);//false
2179
+ if (!node2) {
2180
+ node2 = node.cloneNode(false); //false
1594
2181
  }
1595
2182
  node2.ownerDocument = doc;
1596
2183
  node2.parentNode = null;
1597
- if(deep){
2184
+ if (deep) {
1598
2185
  var child = node.firstChild;
1599
- while(child){
1600
- node2.appendChild(importNode(doc,child,deep));
2186
+ while (child) {
2187
+ node2.appendChild(importNode(doc, child, deep));
1601
2188
  child = child.nextSibling;
1602
2189
  }
1603
2190
  }
@@ -1606,112 +2193,119 @@ function importNode(doc,node,deep){
1606
2193
  //
1607
2194
  //var _relationMap = {firstChild:1,lastChild:1,previousSibling:1,nextSibling:1,
1608
2195
  // attributes:1,childNodes:1,parentNode:1,documentElement:1,doctype,};
1609
- function cloneNode(doc,node,deep){
2196
+ function cloneNode(doc, node, deep) {
1610
2197
  var node2 = new node.constructor();
1611
- for(var n in node){
1612
- var v = node[n];
1613
- if(typeof v != 'object' ){
1614
- if(v != node2[n]){
1615
- node2[n] = v;
2198
+ for (var n in node) {
2199
+ if (Object.prototype.hasOwnProperty.call(node, n)) {
2200
+ var v = node[n];
2201
+ if (typeof v != 'object') {
2202
+ if (v != node2[n]) {
2203
+ node2[n] = v;
2204
+ }
1616
2205
  }
1617
2206
  }
1618
2207
  }
1619
- if(node.childNodes){
2208
+ if (node.childNodes) {
1620
2209
  node2.childNodes = new NodeList();
1621
2210
  }
1622
2211
  node2.ownerDocument = doc;
1623
2212
  switch (node2.nodeType) {
1624
- case ELEMENT_NODE:
1625
- var attrs = node.attributes;
1626
- var attrs2 = node2.attributes = new NamedNodeMap();
1627
- var len = attrs.length
1628
- attrs2._ownerElement = node2;
1629
- for(var i=0;i<len;i++){
1630
- node2.setAttributeNode(cloneNode(doc,attrs.item(i),true));
1631
- }
1632
- break;;
1633
- case ATTRIBUTE_NODE:
1634
- deep = true;
2213
+ case ELEMENT_NODE:
2214
+ var attrs = node.attributes;
2215
+ var attrs2 = (node2.attributes = new NamedNodeMap());
2216
+ var len = attrs.length;
2217
+ attrs2._ownerElement = node2;
2218
+ for (var i = 0; i < len; i++) {
2219
+ node2.setAttributeNode(cloneNode(doc, attrs.item(i), true));
2220
+ }
2221
+ break;
2222
+ case ATTRIBUTE_NODE:
2223
+ deep = true;
1635
2224
  }
1636
- if(deep){
2225
+ if (deep) {
1637
2226
  var child = node.firstChild;
1638
- while(child){
1639
- node2.appendChild(cloneNode(doc,child,deep));
2227
+ while (child) {
2228
+ node2.appendChild(cloneNode(doc, child, deep));
1640
2229
  child = child.nextSibling;
1641
2230
  }
1642
2231
  }
1643
2232
  return node2;
1644
2233
  }
1645
2234
 
1646
- function __set__(object,key,value){
1647
- object[key] = value
2235
+ function __set__(object, key, value) {
2236
+ object[key] = value;
1648
2237
  }
1649
2238
  //do dynamic
1650
- try{
1651
- if(Object.defineProperty){
1652
- Object.defineProperty(LiveNodeList.prototype,'length',{
1653
- get:function(){
2239
+ try {
2240
+ if (Object.defineProperty) {
2241
+ Object.defineProperty(LiveNodeList.prototype, 'length', {
2242
+ get: function () {
1654
2243
  _updateLiveList(this);
1655
2244
  return this.$$length;
1656
- }
2245
+ },
1657
2246
  });
1658
2247
 
1659
- Object.defineProperty(Node.prototype,'textContent',{
1660
- get:function(){
2248
+ Object.defineProperty(Node.prototype, 'textContent', {
2249
+ get: function () {
1661
2250
  return getTextContent(this);
1662
2251
  },
1663
2252
 
1664
- set:function(data){
1665
- switch(this.nodeType){
2253
+ set: function (data) {
2254
+ switch (this.nodeType) {
2255
+ case ELEMENT_NODE:
2256
+ case DOCUMENT_FRAGMENT_NODE:
2257
+ while (this.firstChild) {
2258
+ this.removeChild(this.firstChild);
2259
+ }
2260
+ if (data || String(data)) {
2261
+ this.appendChild(this.ownerDocument.createTextNode(data));
2262
+ }
2263
+ break;
2264
+
2265
+ default:
2266
+ this.data = data;
2267
+ this.value = data;
2268
+ this.nodeValue = data;
2269
+ }
2270
+ },
2271
+ });
2272
+
2273
+ function getTextContent(node) {
2274
+ switch (node.nodeType) {
1666
2275
  case ELEMENT_NODE:
1667
2276
  case DOCUMENT_FRAGMENT_NODE:
1668
- while(this.firstChild){
1669
- this.removeChild(this.firstChild);
1670
- }
1671
- if(data || String(data)){
1672
- this.appendChild(this.ownerDocument.createTextNode(data));
2277
+ var buf = [];
2278
+ node = node.firstChild;
2279
+ while (node) {
2280
+ if (node.nodeType !== 7 && node.nodeType !== 8) {
2281
+ buf.push(getTextContent(node));
2282
+ }
2283
+ node = node.nextSibling;
1673
2284
  }
1674
- break;
1675
-
2285
+ return buf.join('');
1676
2286
  default:
1677
- this.data = data;
1678
- this.value = data;
1679
- this.nodeValue = data;
1680
- }
1681
- }
1682
- })
1683
-
1684
- function getTextContent(node){
1685
- switch(node.nodeType){
1686
- case ELEMENT_NODE:
1687
- case DOCUMENT_FRAGMENT_NODE:
1688
- var buf = [];
1689
- node = node.firstChild;
1690
- while(node){
1691
- if(node.nodeType!==7 && node.nodeType !==8){
1692
- buf.push(getTextContent(node));
1693
- }
1694
- node = node.nextSibling;
1695
- }
1696
- return buf.join('');
1697
- default:
1698
- return node.nodeValue;
2287
+ return node.nodeValue;
1699
2288
  }
1700
2289
  }
1701
2290
 
1702
- __set__ = function(object,key,value){
2291
+ __set__ = function (object, key, value) {
1703
2292
  //console.log(value)
1704
- object['$$'+key] = value
1705
- }
2293
+ object['$$' + key] = value;
2294
+ };
1706
2295
  }
1707
- }catch(e){//ie8
2296
+ } catch (e) {
2297
+ //ie8
1708
2298
  }
1709
2299
 
2300
+ exports._updateLiveList = _updateLiveList;
2301
+ exports.Attr = Attr;
1710
2302
  exports.Document = Document;
1711
2303
  exports.DocumentType = DocumentType;
1712
2304
  exports.DOMException = DOMException;
1713
2305
  exports.DOMImplementation = DOMImplementation;
1714
2306
  exports.Element = Element;
2307
+ exports.LiveNodeList = LiveNodeList;
2308
+ exports.NamedNodeMap = NamedNodeMap;
1715
2309
  exports.Node = Node;
1716
2310
  exports.NodeList = NodeList;
1717
2311
  exports.XMLSerializer = XMLSerializer;