Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80684 views
1
var core = require("../level1/core").dom.level1.core;
2
var defineGetter = require('../utils').defineGetter;
3
var defineSetter = require('../utils').defineSetter;
4
5
// modify cloned instance for more info check: https://github.com/tmpvar/jsdom/issues/325
6
core = Object.create(core);
7
8
var INVALID_STATE_ERR = core.INVALID_STATE_ERR = 11,
9
SYNTAX_ERR = core.SYNTAX_ERR = 12,
10
INVALID_MODIFICATION_ERR = core.INVALID_MODIFICATION_ERR = 13,
11
NAMESPACE_ERR = core.NAMESPACE_ERR = 14,
12
INVALID_ACCESS_ERR = core.INVALID_ACCESS_ERR = 15,
13
ns = {
14
validate : function(ns, URI) {
15
if (!ns) {
16
throw new core.DOMException(core.INVALID_CHARACTER_ERR, "namespace is undefined");
17
}
18
19
if(ns.match(/[^0-9a-z\.:\-_]/i) !== null) {
20
throw new core.DOMException(core.INVALID_CHARACTER_ERR, ns);
21
}
22
23
var msg = false, parts = ns.split(':');
24
if (ns === 'xmlns' &&
25
URI !== "http://www.w3.org/2000/xmlns/")
26
{
27
msg = "localName is 'xmlns' but the namespaceURI is invalid";
28
29
} else if (ns === "xml" &&
30
URI !== "http://www.w3.org/XML/1998/namespace")
31
{
32
msg = "localName is 'xml' but the namespaceURI is invalid";
33
34
} else if (ns[ns.length-1] === ':') {
35
msg = "Namespace seperator found with no localName";
36
37
} else if (ns[0] === ':') {
38
msg = "Namespace seperator found, without a prefix";
39
40
} else if (parts.length > 2) {
41
msg = "Too many namespace seperators";
42
43
}
44
45
if (msg) {
46
throw new core.DOMException(NAMESPACE_ERR, msg + " (" + ns + "@" + URI + ")");
47
}
48
}
49
};
50
51
core.exceptionMessages['NAMESPACE_ERR'] = "Invalid namespace";
52
53
core.DOMImplementation.prototype.createDocumentType = function(/* String */ qualifiedName,
54
/* String */ publicId,
55
/* String */ systemId)
56
{
57
ns.validate(qualifiedName);
58
var doctype = new core.DocumentType(null, qualifiedName);
59
doctype._publicId = publicId ? publicId : '';
60
doctype._systemId = systemId ? systemId : '';
61
return doctype;
62
};
63
64
/**
65
Creates an XML Document object of the specified type with its document element.
66
HTML-only DOM implementations do not need to implement this method.
67
*/
68
core.DOMImplementation.prototype.createDocument = function(/* String */ namespaceURI,
69
/* String */ qualifiedName,
70
/* DocumentType */ doctype)
71
{
72
if (qualifiedName || namespaceURI) {
73
ns.validate(qualifiedName, namespaceURI);
74
}
75
76
if (doctype && doctype._ownerDocument !== null) {
77
throw new core.DOMException(core.WRONG_DOCUMENT_ERR);
78
}
79
80
if (qualifiedName && qualifiedName.indexOf(':') > -1 && !namespaceURI) {
81
throw new core.DOMException(NAMESPACE_ERR);
82
}
83
84
var document = new core.Document();
85
86
if (doctype) {
87
document.doctype = doctype;
88
doctype._ownerDocument = document;
89
document.appendChild(doctype);
90
} else {
91
document.doctype = null;
92
}
93
94
if (doctype && !doctype.entities) {
95
doctype.entities = new core.EntityNodeMap();
96
}
97
98
document._ownerDocument = document;
99
100
if (qualifiedName) {
101
var docElement = document.createElementNS(namespaceURI, qualifiedName);
102
document.appendChild(docElement);
103
}
104
105
return document;
106
};
107
108
defineGetter(core.Node.prototype, "ownerDocument", function() {
109
return this._ownerDocument || null;
110
});
111
112
core.Node.prototype.isSupported = function(/* string */ feature,
113
/* string */ version)
114
{
115
return this._ownerDocument.implementation.hasFeature(feature, version);
116
};
117
118
core.Node.prototype._namespaceURI = null;
119
defineGetter(core.Node.prototype, "namespaceURI", function() {
120
return this._namespaceURI || null;
121
});
122
123
defineSetter(core.Node.prototype, "namespaceURI", function(value) {
124
this._namespaceURI = value;
125
});
126
127
defineGetter(core.Node.prototype, "prefix", function() {
128
return this._prefix || null;
129
});
130
131
defineSetter(core.Node.prototype, "prefix", function(value) {
132
133
if (this.readonly) {
134
throw new core.DOMException(core.NO_MODIFICATION_ALLOWED_ERR);
135
}
136
137
ns.validate(value, this._namespaceURI);
138
139
if ((this._created && !this._namespaceURI) ||
140
this._prefix === "xmlns" ||
141
(!this._prefix && this._created))
142
{
143
throw new core.DOMException(core.NAMESPACE_ERR);
144
}
145
146
if (this._localName) {
147
this._nodeName = value + ':' + this._localName;
148
}
149
150
this._prefix = value;
151
});
152
153
defineGetter(core.Node.prototype, "localName", function() {
154
return this._localName || null;
155
});
156
157
/* return boolean */
158
core.Node.prototype.hasAttributes = function() {
159
return (this.nodeType === this.ELEMENT_NODE &&
160
this._attributes &&
161
this._attributes.length > 0);
162
};
163
164
core.NamedNodeMap.prototype.getNamedItemNS = function(/* string */ namespaceURI,
165
/* string */ localName)
166
{
167
if (this._nsStore[namespaceURI] && this._nsStore[namespaceURI][localName]) {
168
return this._nsStore[namespaceURI][localName];
169
}
170
return null;
171
};
172
173
core.NamedNodeMap.prototype.setNamedItemNS = function(/* Node */ arg)
174
{
175
if (this._readonly) {
176
throw new core.DOMException(core.NO_MODIFICATION_ALLOWED_ERR);
177
}
178
179
var owner = this._ownerDocument;
180
if (this._parentNode &&
181
this._parentNode._parentNode &&
182
this._parentNode._parentNode.nodeType === owner.ENTITY_NODE)
183
{
184
throw new core.DOMException(core.NO_MODIFICATION_ALLOWED_ERR);
185
}
186
187
if (this._ownerDocument !== arg.ownerDocument) {
188
throw new core.DOMException(core.WRONG_DOCUMENT_ERR);
189
}
190
191
if (arg._ownerElement) {
192
throw new core.DOMException(core.INUSE_ATTRIBUTE_ERR);
193
}
194
195
// readonly
196
if (this._readonly === true) {
197
throw new core.DOMException(core.NO_MODIFICATION_ALLOWED_ERR);
198
}
199
200
201
if (!this._nsStore[arg.namespaceURI]) {
202
this._nsStore[arg.namespaceURI] = {};
203
}
204
var existing = null;
205
if (this._nsStore[arg.namespaceURI][arg.localName]) {
206
var existing = this._nsStore[arg.namespaceURI][arg.localName];
207
}
208
209
this._nsStore[arg.namespaceURI][arg.localName] = arg;
210
211
arg._specified = true;
212
arg._ownerDocument = this._ownerDocument;
213
214
return this.setNamedItem(arg);
215
};
216
217
core.NamedNodeMap.prototype.removeNamedItemNS = function(/*string */ namespaceURI,
218
/* string */ localName)
219
{
220
221
if (this.readonly) {
222
throw new core.DOMException(core.NO_MODIFICATION_ALLOWED_ERR);
223
}
224
225
226
var parent = this._parentNode,
227
found = null,
228
defaults,
229
clone,
230
defaultEl,
231
defaultAttr;
232
233
if (this._parentNode &&
234
this._parentNode._parentNode &&
235
this._parentNode._parentNode.nodeType === this._ownerDocument.ENTITY_NODE)
236
{
237
throw new core.DOMException(core.NO_MODIFICATION_ALLOWED_ERR);
238
}
239
240
if (this._nsStore[namespaceURI] &&
241
this._nsStore[namespaceURI][localName])
242
{
243
found = this._nsStore[namespaceURI][localName];
244
this.removeNamedItem(found.qualifiedName);
245
delete this._nsStore[namespaceURI][localName];
246
}
247
248
if (!found) {
249
throw new core.DOMException(core.NOT_FOUND_ERR);
250
}
251
252
if (parent.ownerDocument.doctype && parent.ownerDocument.doctype._attributes) {
253
defaults = parent.ownerDocument.doctype._attributes;
254
defaultEl = defaults.getNamedItemNS(parent._namespaceURI, parent._localName);
255
}
256
257
if (defaultEl) {
258
defaultAttr = defaultEl._attributes.getNamedItemNS(namespaceURI, localName);
259
260
if (defaultAttr) {
261
clone = defaultAttr.cloneNode(true);
262
clone._created = false;
263
clone._namespaceURI = found._namespaceURI;
264
clone._nodeName = found.name;
265
clone._localName = found._localName;
266
clone._prefix = found._prefix
267
this.setNamedItemNS(clone);
268
clone._created = true;
269
clone._specified = false;
270
}
271
}
272
273
return found;
274
};
275
276
defineGetter(core.Attr.prototype, "ownerElement", function() {
277
return this._ownerElement || null;
278
});
279
280
281
core.Node.prototype._prefix = false;
282
283
defineSetter(core.Node.prototype, "qualifiedName", function(qualifiedName) {
284
ns.validate(qualifiedName, this._namespaceURI);
285
qualifiedName = qualifiedName || "";
286
this._localName = qualifiedName.split(":")[1] || null;
287
this.prefix = qualifiedName.split(":")[0] || null;
288
this._nodeName = qualifiedName;
289
});
290
291
defineGetter(core.Node.prototype, "qualifiedName", function() {
292
return this._nodeName;
293
});
294
295
core.NamedNodeMap.prototype._map = function(fn) {
296
var ret = [], l = this.length, i = 0, node;
297
for(i; i<l; i++) {
298
node = this.item(i);
299
if (fn && fn(node)) {
300
ret.push(node);
301
}
302
}
303
return ret;
304
};
305
306
core.Element.prototype.getAttribute = function(/* string */ name)
307
{
308
var attr = this.getAttributeNode(name);
309
return attr && attr.value;
310
};
311
312
core.Element.prototype.getAttributeNode = function(/* string */ name)
313
{
314
return this._attributes.$getNoNS(name);
315
};
316
317
core.Element.prototype.removeAttribute = function(/* string */ name)
318
{
319
return this._attributes.$removeNoNS(name);
320
};
321
322
core.Element.prototype.getAttributeNS = function(/* string */ namespaceURI,
323
/* string */ localName)
324
{
325
if (namespaceURI === "") {
326
namespaceURI = null;
327
}
328
329
var attr = this._attributes.$getNode(namespaceURI, localName);
330
return attr && attr.value;
331
};
332
333
core.Element.prototype.setAttribute = function(/* string */ name,
334
/* string */ value)
335
{
336
this._attributes.$setNoNS(name, value);
337
};
338
339
core.Element.prototype.setAttributeNS = function(/* string */ namespaceURI,
340
/* string */ qualifiedName,
341
/* string */ value)
342
{
343
if (namespaceURI === "") {
344
namespaceURI = null;
345
}
346
347
var s = qualifiedName.split(':'),
348
local = s.pop(),
349
prefix = s.pop() || null,
350
attr;
351
352
ns.validate(qualifiedName, namespaceURI);
353
354
if (prefix !== null && !namespaceURI) {
355
throw new core.DOMException(core.NAMESPACE_ERR);
356
}
357
358
if (prefix === "xml" &&
359
namespaceURI !== "http://www.w3.org/XML/1998/namespace") {
360
throw new core.DOMException(core.NAMESPACE_ERR);
361
}
362
363
if (prefix === "xmlns" && namespaceURI !== "http://www.w3.org/2000/xmlns/") {
364
throw new core.DOMException(core.NAMESPACE_ERR);
365
}
366
367
this._attributes.$set(local, value, qualifiedName, prefix, namespaceURI);
368
};
369
370
core.Element.prototype.removeAttributeNS = function(/* string */ namespaceURI,
371
/* string */ localName)
372
{
373
if (namespaceURI === "") {
374
namespaceURI = null;
375
}
376
377
this._attributes.$remove(namespaceURI, localName);
378
};
379
380
core.Element.prototype.getAttributeNodeNS = function(/* string */ namespaceURI,
381
/* string */ localName)
382
{
383
if (namespaceURI === "") {
384
namespaceURI = null;
385
}
386
387
return this._attributes.$getNode(namespaceURI, localName);
388
};
389
core.Element.prototype._created = false;
390
391
core.Element.prototype.setAttributeNodeNS = function(/* Attr */ newAttr)
392
{
393
if (newAttr.ownerElement) {
394
throw new core.DOMException(core.INUSE_ATTRIBUTE_ERR);
395
}
396
397
return this._attributes.$setNode(newAttr);
398
};
399
400
core.Element.prototype.getElementsByTagNameNS = function(/* String */ namespaceURI,
401
/* String */ localName)
402
{
403
var nsPrefixCache = {};
404
405
function filterByTagName(child) {
406
if (child.nodeType && child.nodeType === this.ENTITY_REFERENCE_NODE) {
407
child = child._entity;
408
}
409
410
var localMatch = child.localName === localName,
411
nsMatch = child.namespaceURI === namespaceURI;
412
413
if ((localMatch || localName === "*") &&
414
(nsMatch || namespaceURI === "*"))
415
{
416
if (child.nodeType === child.ELEMENT_NODE) {
417
return true;
418
}
419
}
420
return false;
421
}
422
423
return new core.NodeList(this.ownerDocument || this,
424
core.mapper(this, filterByTagName));
425
};
426
427
core.Element.prototype.hasAttribute = function(/* string */name)
428
{
429
if (!this._attributes) {
430
return false;
431
}
432
433
return !!this._attributes.$getNoNS(name);
434
};
435
436
core.Element.prototype.hasAttributeNS = function(/* string */namespaceURI,
437
/* string */localName)
438
{
439
if (namespaceURI === "") {
440
namespaceURI = null;
441
}
442
443
return (this._attributes.getNamedItemNS(namespaceURI, localName) ||
444
this.hasAttribute(localName));
445
};
446
447
defineGetter(core.DocumentType.prototype, "publicId", function() {
448
return this._publicId || "";
449
});
450
451
defineGetter(core.DocumentType.prototype, "systemId", function() {
452
return this._systemId || "";
453
});
454
455
defineGetter(core.DocumentType.prototype, "internalSubset", function() {
456
return this._internalSubset || null;
457
});
458
459
core.Document.prototype.importNode = function(/* Node */ importedNode,
460
/* bool */ deep)
461
{
462
if (importedNode && importedNode.nodeType) {
463
if (importedNode.nodeType === this.DOCUMENT_NODE ||
464
importedNode.nodeType === this.DOCUMENT_TYPE_NODE) {
465
throw new core.DOMException(core.NOT_SUPPORTED_ERR);
466
}
467
}
468
469
var self = this,
470
newNode = importedNode.cloneNode(deep, function(a, b) {
471
b._namespaceURI = a._namespaceURI;
472
b._nodeName = a._nodeName;
473
b._localName = a._localName;
474
}),
475
defaults = false,
476
defaultEl;
477
478
if (this.doctype && this.doctype._attributes) {
479
defaults = this.doctype._attributes;
480
}
481
482
function lastChance(el) {
483
var attr, defaultEl, i, len;
484
485
el._ownerDocument = self;
486
if (el.id) {
487
if (!self._ids) {self._ids = {};}
488
if (!self._ids[el.id]) {self._ids[el.id] = [];}
489
self._ids[el.id].push(el);
490
}
491
if (el._attributes) {
492
var drop = [];
493
el._attributes._ownerDocument = self;
494
for (i=0,len=el._attributes.length; i < len; i++) {
495
attr = el._attributes[i];
496
// Attributes nodes that were expressing default values in the
497
// original document must not be copied over. Record them.
498
if (!attr._specified) {
499
drop.push(attr);
500
continue;
501
}
502
503
attr._ownerDocument = self;
504
}
505
506
// Remove obsolete default nodes.
507
for(i = 0; i < drop.length; ++i) {
508
el._attributes.$removeNode(drop[i]);
509
}
510
511
}
512
if (defaults) {
513
514
defaultEl = defaults.getNamedItemNS(el._namespaceURI,
515
el._localName);
516
517
// TODO: This could use some love
518
if (defaultEl) {
519
for(i = 0; i < defaultEl._attributes.length; ++i) {
520
var defaultAttr = defaultEl._attributes[i];
521
if (!el.hasAttributeNS(defaultAttr.namespaceURL,
522
defaultAttr.localName))
523
{
524
var clone = defaultAttr.cloneNode(true);
525
clone._namespaceURI = defaultAttr._namespaceURI;
526
clone._prefix = defaultAttr._prefix;
527
clone._localName = defaultAttr._localName;
528
el.setAttributeNodeNS(clone);
529
clone._specified = false;
530
}
531
}
532
}
533
}
534
535
}
536
537
if (deep) {
538
core.visitTree(newNode, lastChance);
539
}
540
else {
541
lastChance(newNode);
542
}
543
544
if (newNode.nodeType == newNode.ATTRIBUTE_NODE) {
545
newNode._specified = true;
546
}
547
548
return newNode;
549
};
550
551
core.Document.prototype.createElementNS = function(/* string */ namespaceURI,
552
/* string */ qualifiedName)
553
{
554
var parts = qualifiedName.split(':'),
555
element, prefix;
556
557
if (parts.length > 1 && !namespaceURI) {
558
throw new core.DOMException(core.NAMESPACE_ERR);
559
}
560
561
ns.validate(qualifiedName, namespaceURI);
562
element = this.createElement(qualifiedName),
563
564
element._created = false;
565
566
element._namespaceURI = namespaceURI;
567
element._nodeName = qualifiedName;
568
element._localName = parts.pop();
569
570
if (parts.length > 0) {
571
prefix = parts.pop();
572
element.prefix = prefix;
573
}
574
575
element._created = true;
576
return element;
577
};
578
579
core.Document.prototype.createAttributeNS = function(/* string */ namespaceURI,
580
/* string */ qualifiedName)
581
{
582
var attribute, parts = qualifiedName.split(':');
583
584
if (parts.length > 1 && !namespaceURI) {
585
throw new core.DOMException(core.NAMESPACE_ERR,
586
"Prefix specified without namespaceURI (" + qualifiedName + ")");
587
}
588
589
590
ns.validate(qualifiedName, namespaceURI);
591
592
attribute = this.createAttribute(qualifiedName);
593
attribute.namespaceURI = namespaceURI;
594
attribute.qualifiedName = qualifiedName;
595
596
attribute._localName = parts.pop();
597
attribute._prefix = (parts.length > 0) ? parts.pop() : null;
598
return attribute;
599
};
600
601
core.Document.prototype.getElementsByTagNameNS = function(/* String */ namespaceURI,
602
/* String */ localName)
603
{
604
return core.Element.prototype.getElementsByTagNameNS.call(this,
605
namespaceURI,
606
localName);
607
};
608
609
defineSetter(core.Element.prototype, "id", function(id) {
610
this.setAttribute("id", id);
611
});
612
613
defineGetter(core.Element.prototype, "id", function() {
614
return this.getAttribute("id");
615
});
616
617
core.Document.prototype.getElementById = function(id) {
618
// return the first element
619
return (this._ids && this._ids[id] && this._ids[id].length > 0 ? this._ids[id][0] : null);
620
};
621
622
623
exports.dom =
624
{
625
level2 : {
626
core : core
627
}
628
};
629
630