1000 lines
30 KiB
JavaScript
1000 lines
30 KiB
JavaScript
// Generated by CoffeeScript 2.4.1
|
|
(function() {
|
|
var DocumentPosition, NodeType, XMLCData, XMLComment, XMLDeclaration, XMLDocType, XMLDummy, XMLElement, XMLNamedNodeMap, XMLNode, XMLNodeList, XMLProcessingInstruction, XMLRaw, XMLText, getValue, isEmpty, isFunction, isObject,
|
|
hasProp = {}.hasOwnProperty,
|
|
splice = [].splice;
|
|
|
|
({isObject, isFunction, isEmpty, getValue} = require('./Utility'));
|
|
|
|
XMLElement = null;
|
|
|
|
XMLCData = null;
|
|
|
|
XMLComment = null;
|
|
|
|
XMLDeclaration = null;
|
|
|
|
XMLDocType = null;
|
|
|
|
XMLRaw = null;
|
|
|
|
XMLText = null;
|
|
|
|
XMLProcessingInstruction = null;
|
|
|
|
XMLDummy = null;
|
|
|
|
NodeType = null;
|
|
|
|
XMLNodeList = null;
|
|
|
|
XMLNamedNodeMap = null;
|
|
|
|
DocumentPosition = null;
|
|
|
|
// Represents a generic XMl element
|
|
module.exports = XMLNode = (function() {
|
|
class XMLNode {
|
|
// Initializes a new instance of `XMLNode`
|
|
|
|
// `parent` the parent node
|
|
constructor(parent1) {
|
|
this.parent = parent1;
|
|
if (this.parent) {
|
|
this.options = this.parent.options;
|
|
this.stringify = this.parent.stringify;
|
|
}
|
|
this.value = null;
|
|
this.children = [];
|
|
this.baseURI = null;
|
|
// first execution, load dependencies that are otherwise
|
|
// circular (so we can't load them at the top)
|
|
if (!XMLElement) {
|
|
XMLElement = require('./XMLElement');
|
|
XMLCData = require('./XMLCData');
|
|
XMLComment = require('./XMLComment');
|
|
XMLDeclaration = require('./XMLDeclaration');
|
|
XMLDocType = require('./XMLDocType');
|
|
XMLRaw = require('./XMLRaw');
|
|
XMLText = require('./XMLText');
|
|
XMLProcessingInstruction = require('./XMLProcessingInstruction');
|
|
XMLDummy = require('./XMLDummy');
|
|
NodeType = require('./NodeType');
|
|
XMLNodeList = require('./XMLNodeList');
|
|
XMLNamedNodeMap = require('./XMLNamedNodeMap');
|
|
DocumentPosition = require('./DocumentPosition');
|
|
}
|
|
}
|
|
|
|
|
|
// Sets the parent node of this node and its children recursively
|
|
|
|
// `parent` the parent node
|
|
setParent(parent) {
|
|
var child, j, len, ref1, results;
|
|
this.parent = parent;
|
|
if (parent) {
|
|
this.options = parent.options;
|
|
this.stringify = parent.stringify;
|
|
}
|
|
ref1 = this.children;
|
|
results = [];
|
|
for (j = 0, len = ref1.length; j < len; j++) {
|
|
child = ref1[j];
|
|
results.push(child.setParent(this));
|
|
}
|
|
return results;
|
|
}
|
|
|
|
// Creates a child element node
|
|
|
|
// `name` node name or an object describing the XML tree
|
|
// `attributes` an object containing name/value pairs of attributes
|
|
// `text` element text
|
|
element(name, attributes, text) {
|
|
var childNode, item, j, k, key, lastChild, len, len1, val;
|
|
lastChild = null;
|
|
if (attributes === null && (text == null)) {
|
|
[attributes, text] = [{}, null];
|
|
}
|
|
if (attributes == null) {
|
|
attributes = {};
|
|
}
|
|
attributes = getValue(attributes);
|
|
// swap argument order: text <-> attributes
|
|
if (!isObject(attributes)) {
|
|
[text, attributes] = [attributes, text];
|
|
}
|
|
if (name != null) {
|
|
name = getValue(name);
|
|
}
|
|
// expand if array
|
|
if (Array.isArray(name)) {
|
|
for (j = 0, len = name.length; j < len; j++) {
|
|
item = name[j];
|
|
lastChild = this.element(item);
|
|
}
|
|
// evaluate if function
|
|
} else if (isFunction(name)) {
|
|
lastChild = this.element(name.apply());
|
|
// expand if object
|
|
} else if (isObject(name)) {
|
|
for (key in name) {
|
|
if (!hasProp.call(name, key)) continue;
|
|
val = name[key];
|
|
if (isFunction(val)) {
|
|
// evaluate if function
|
|
val = val.apply();
|
|
}
|
|
// assign attributes
|
|
if (!this.options.ignoreDecorators && this.stringify.convertAttKey && key.indexOf(this.stringify.convertAttKey) === 0) {
|
|
lastChild = this.attribute(key.substr(this.stringify.convertAttKey.length), val);
|
|
// skip empty arrays
|
|
} else if (!this.options.separateArrayItems && Array.isArray(val) && isEmpty(val)) {
|
|
lastChild = this.dummy();
|
|
// empty objects produce one node
|
|
} else if (isObject(val) && isEmpty(val)) {
|
|
lastChild = this.element(key);
|
|
// skip null and undefined nodes
|
|
} else if (!this.options.keepNullNodes && (val == null)) {
|
|
lastChild = this.dummy();
|
|
|
|
// expand list by creating child nodes
|
|
} else if (!this.options.separateArrayItems && Array.isArray(val)) {
|
|
for (k = 0, len1 = val.length; k < len1; k++) {
|
|
item = val[k];
|
|
childNode = {};
|
|
childNode[key] = item;
|
|
lastChild = this.element(childNode);
|
|
}
|
|
|
|
// expand child nodes under parent
|
|
} else if (isObject(val)) {
|
|
// if the key is #text expand child nodes under this node to support mixed content
|
|
if (!this.options.ignoreDecorators && this.stringify.convertTextKey && key.indexOf(this.stringify.convertTextKey) === 0) {
|
|
lastChild = this.element(val);
|
|
} else {
|
|
lastChild = this.element(key);
|
|
lastChild.element(val);
|
|
}
|
|
} else {
|
|
|
|
// text node
|
|
lastChild = this.element(key, val);
|
|
}
|
|
}
|
|
// skip null nodes
|
|
} else if (!this.options.keepNullNodes && text === null) {
|
|
lastChild = this.dummy();
|
|
} else {
|
|
// text node
|
|
if (!this.options.ignoreDecorators && this.stringify.convertTextKey && name.indexOf(this.stringify.convertTextKey) === 0) {
|
|
lastChild = this.text(text);
|
|
// cdata node
|
|
} else if (!this.options.ignoreDecorators && this.stringify.convertCDataKey && name.indexOf(this.stringify.convertCDataKey) === 0) {
|
|
lastChild = this.cdata(text);
|
|
// comment node
|
|
} else if (!this.options.ignoreDecorators && this.stringify.convertCommentKey && name.indexOf(this.stringify.convertCommentKey) === 0) {
|
|
lastChild = this.comment(text);
|
|
// raw text node
|
|
} else if (!this.options.ignoreDecorators && this.stringify.convertRawKey && name.indexOf(this.stringify.convertRawKey) === 0) {
|
|
lastChild = this.raw(text);
|
|
// processing instruction
|
|
} else if (!this.options.ignoreDecorators && this.stringify.convertPIKey && name.indexOf(this.stringify.convertPIKey) === 0) {
|
|
lastChild = this.instruction(name.substr(this.stringify.convertPIKey.length), text);
|
|
} else {
|
|
// element node
|
|
lastChild = this.node(name, attributes, text);
|
|
}
|
|
}
|
|
if (lastChild == null) {
|
|
throw new Error("Could not create any elements with: " + name + ". " + this.debugInfo());
|
|
}
|
|
return lastChild;
|
|
}
|
|
|
|
// Creates a child element node before the current node
|
|
|
|
// `name` node name or an object describing the XML tree
|
|
// `attributes` an object containing name/value pairs of attributes
|
|
// `text` element text
|
|
insertBefore(name, attributes, text) {
|
|
var child, i, newChild, refChild, removed;
|
|
// DOM level 1
|
|
// insertBefore(newChild, refChild) inserts the child node newChild before refChild
|
|
if (name != null ? name.type : void 0) {
|
|
newChild = name;
|
|
refChild = attributes;
|
|
newChild.setParent(this);
|
|
if (refChild) {
|
|
// temporarily remove children starting *with* refChild
|
|
i = children.indexOf(refChild);
|
|
removed = children.splice(i);
|
|
|
|
// add the new child
|
|
children.push(newChild);
|
|
|
|
// add back removed children after new child
|
|
Array.prototype.push.apply(children, removed);
|
|
} else {
|
|
children.push(newChild);
|
|
}
|
|
return newChild;
|
|
} else {
|
|
if (this.isRoot) {
|
|
throw new Error("Cannot insert elements at root level. " + this.debugInfo(name));
|
|
}
|
|
|
|
// temporarily remove children starting *with* this
|
|
i = this.parent.children.indexOf(this);
|
|
removed = this.parent.children.splice(i);
|
|
|
|
// add the new child
|
|
child = this.parent.element(name, attributes, text);
|
|
|
|
// add back removed children after new child
|
|
Array.prototype.push.apply(this.parent.children, removed);
|
|
return child;
|
|
}
|
|
}
|
|
|
|
// Creates a child element node after the current node
|
|
|
|
// `name` node name or an object describing the XML tree
|
|
// `attributes` an object containing name/value pairs of attributes
|
|
// `text` element text
|
|
insertAfter(name, attributes, text) {
|
|
var child, i, removed;
|
|
if (this.isRoot) {
|
|
throw new Error("Cannot insert elements at root level. " + this.debugInfo(name));
|
|
}
|
|
|
|
// temporarily remove children starting *after* this
|
|
i = this.parent.children.indexOf(this);
|
|
removed = this.parent.children.splice(i + 1);
|
|
|
|
// add the new child
|
|
child = this.parent.element(name, attributes, text);
|
|
|
|
// add back removed children after new child
|
|
Array.prototype.push.apply(this.parent.children, removed);
|
|
return child;
|
|
}
|
|
|
|
// Deletes a child element node
|
|
|
|
remove() {
|
|
var i, ref1;
|
|
if (this.isRoot) {
|
|
throw new Error("Cannot remove the root element. " + this.debugInfo());
|
|
}
|
|
i = this.parent.children.indexOf(this);
|
|
splice.apply(this.parent.children, [i, i - i + 1].concat(ref1 = [])), ref1;
|
|
return this.parent;
|
|
}
|
|
|
|
// Creates a node
|
|
|
|
// `name` name of the node
|
|
// `attributes` an object containing name/value pairs of attributes
|
|
// `text` element text
|
|
node(name, attributes, text) {
|
|
var child;
|
|
if (name != null) {
|
|
name = getValue(name);
|
|
}
|
|
attributes || (attributes = {});
|
|
attributes = getValue(attributes);
|
|
// swap argument order: text <-> attributes
|
|
if (!isObject(attributes)) {
|
|
[text, attributes] = [attributes, text];
|
|
}
|
|
child = new XMLElement(this, name, attributes);
|
|
if (text != null) {
|
|
child.text(text);
|
|
}
|
|
this.children.push(child);
|
|
return child;
|
|
}
|
|
|
|
// Creates a text node
|
|
|
|
// `value` element text
|
|
text(value) {
|
|
var child;
|
|
if (isObject(value)) {
|
|
this.element(value);
|
|
}
|
|
child = new XMLText(this, value);
|
|
this.children.push(child);
|
|
return this;
|
|
}
|
|
|
|
// Creates a CDATA node
|
|
|
|
// `value` element text without CDATA delimiters
|
|
cdata(value) {
|
|
var child;
|
|
child = new XMLCData(this, value);
|
|
this.children.push(child);
|
|
return this;
|
|
}
|
|
|
|
// Creates a comment node
|
|
|
|
// `value` comment text
|
|
comment(value) {
|
|
var child;
|
|
child = new XMLComment(this, value);
|
|
this.children.push(child);
|
|
return this;
|
|
}
|
|
|
|
// Creates a comment node before the current node
|
|
|
|
// `value` comment text
|
|
commentBefore(value) {
|
|
var child, i, removed;
|
|
// temporarily remove children starting *with* this
|
|
i = this.parent.children.indexOf(this);
|
|
removed = this.parent.children.splice(i);
|
|
// add the new child
|
|
child = this.parent.comment(value);
|
|
// add back removed children after new child
|
|
Array.prototype.push.apply(this.parent.children, removed);
|
|
return this;
|
|
}
|
|
|
|
// Creates a comment node after the current node
|
|
|
|
// `value` comment text
|
|
commentAfter(value) {
|
|
var child, i, removed;
|
|
// temporarily remove children starting *after* this
|
|
i = this.parent.children.indexOf(this);
|
|
removed = this.parent.children.splice(i + 1);
|
|
// add the new child
|
|
child = this.parent.comment(value);
|
|
// add back removed children after new child
|
|
Array.prototype.push.apply(this.parent.children, removed);
|
|
return this;
|
|
}
|
|
|
|
// Adds unescaped raw text
|
|
|
|
// `value` text
|
|
raw(value) {
|
|
var child;
|
|
child = new XMLRaw(this, value);
|
|
this.children.push(child);
|
|
return this;
|
|
}
|
|
|
|
// Adds a dummy node
|
|
dummy() {
|
|
var child;
|
|
child = new XMLDummy(this);
|
|
// Normally when a new node is created it is added to the child node collection.
|
|
// However, dummy nodes are never added to the XML tree. They are created while
|
|
// converting JS objects to XML nodes in order not to break the recursive function
|
|
// chain. They can be thought of as invisible nodes. They can be traversed through
|
|
// by using prev(), next(), up(), etc. functions but they do not exists in the tree.
|
|
|
|
// @children.push child
|
|
return child;
|
|
}
|
|
|
|
// Adds a processing instruction
|
|
|
|
// `target` instruction target
|
|
// `value` instruction value
|
|
instruction(target, value) {
|
|
var insTarget, insValue, instruction, j, len;
|
|
if (target != null) {
|
|
target = getValue(target);
|
|
}
|
|
if (value != null) {
|
|
value = getValue(value);
|
|
}
|
|
if (Array.isArray(target)) { // expand if array
|
|
for (j = 0, len = target.length; j < len; j++) {
|
|
insTarget = target[j];
|
|
this.instruction(insTarget);
|
|
}
|
|
} else if (isObject(target)) { // expand if object
|
|
for (insTarget in target) {
|
|
if (!hasProp.call(target, insTarget)) continue;
|
|
insValue = target[insTarget];
|
|
this.instruction(insTarget, insValue);
|
|
}
|
|
} else {
|
|
if (isFunction(value)) {
|
|
value = value.apply();
|
|
}
|
|
instruction = new XMLProcessingInstruction(this, target, value);
|
|
this.children.push(instruction);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
// Creates a processing instruction node before the current node
|
|
|
|
// `target` instruction target
|
|
// `value` instruction value
|
|
instructionBefore(target, value) {
|
|
var child, i, removed;
|
|
// temporarily remove children starting *with* this
|
|
i = this.parent.children.indexOf(this);
|
|
removed = this.parent.children.splice(i);
|
|
// add the new child
|
|
child = this.parent.instruction(target, value);
|
|
// add back removed children after new child
|
|
Array.prototype.push.apply(this.parent.children, removed);
|
|
return this;
|
|
}
|
|
|
|
// Creates a processing instruction node after the current node
|
|
|
|
// `target` instruction target
|
|
// `value` instruction value
|
|
instructionAfter(target, value) {
|
|
var child, i, removed;
|
|
// temporarily remove children starting *after* this
|
|
i = this.parent.children.indexOf(this);
|
|
removed = this.parent.children.splice(i + 1);
|
|
// add the new child
|
|
child = this.parent.instruction(target, value);
|
|
// add back removed children after new child
|
|
Array.prototype.push.apply(this.parent.children, removed);
|
|
return this;
|
|
}
|
|
|
|
// Creates the xml declaration
|
|
|
|
// `version` A version number string, e.g. 1.0
|
|
// `encoding` Encoding declaration, e.g. UTF-8
|
|
// `standalone` standalone document declaration: true or false
|
|
declaration(version, encoding, standalone) {
|
|
var doc, xmldec;
|
|
doc = this.document();
|
|
xmldec = new XMLDeclaration(doc, version, encoding, standalone);
|
|
// Replace XML declaration if exists, otherwise insert at top
|
|
if (doc.children.length === 0) {
|
|
doc.children.unshift(xmldec);
|
|
} else if (doc.children[0].type === NodeType.Declaration) {
|
|
doc.children[0] = xmldec;
|
|
} else {
|
|
doc.children.unshift(xmldec);
|
|
}
|
|
return doc.root() || doc;
|
|
}
|
|
|
|
// Creates the document type declaration
|
|
|
|
// `pubID` the public identifier of the external subset
|
|
// `sysID` the system identifier of the external subset
|
|
dtd(pubID, sysID) {
|
|
var child, doc, doctype, i, j, k, len, len1, ref1, ref2;
|
|
doc = this.document();
|
|
doctype = new XMLDocType(doc, pubID, sysID);
|
|
ref1 = doc.children;
|
|
// Replace DTD if exists
|
|
for (i = j = 0, len = ref1.length; j < len; i = ++j) {
|
|
child = ref1[i];
|
|
if (child.type === NodeType.DocType) {
|
|
doc.children[i] = doctype;
|
|
return doctype;
|
|
}
|
|
}
|
|
ref2 = doc.children;
|
|
// insert before root node if the root node exists
|
|
for (i = k = 0, len1 = ref2.length; k < len1; i = ++k) {
|
|
child = ref2[i];
|
|
if (child.isRoot) {
|
|
doc.children.splice(i, 0, doctype);
|
|
return doctype;
|
|
}
|
|
}
|
|
// otherwise append to end
|
|
doc.children.push(doctype);
|
|
return doctype;
|
|
}
|
|
|
|
// Gets the parent node
|
|
up() {
|
|
if (this.isRoot) {
|
|
throw new Error("The root node has no parent. Use doc() if you need to get the document object.");
|
|
}
|
|
return this.parent;
|
|
}
|
|
|
|
// Gets the root node
|
|
root() {
|
|
var node;
|
|
node = this;
|
|
while (node) {
|
|
if (node.type === NodeType.Document) {
|
|
return node.rootObject;
|
|
} else if (node.isRoot) {
|
|
return node;
|
|
} else {
|
|
node = node.parent;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Gets the node representing the XML document
|
|
document() {
|
|
var node;
|
|
node = this;
|
|
while (node) {
|
|
if (node.type === NodeType.Document) {
|
|
return node;
|
|
} else {
|
|
node = node.parent;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ends the document and converts string
|
|
end(options) {
|
|
return this.document().end(options);
|
|
}
|
|
|
|
// Gets the previous node
|
|
prev() {
|
|
var i;
|
|
i = this.parent.children.indexOf(this);
|
|
if (i < 1) {
|
|
throw new Error("Already at the first node. " + this.debugInfo());
|
|
}
|
|
return this.parent.children[i - 1];
|
|
}
|
|
|
|
// Gets the next node
|
|
next() {
|
|
var i;
|
|
i = this.parent.children.indexOf(this);
|
|
if (i === -1 || i === this.parent.children.length - 1) {
|
|
throw new Error("Already at the last node. " + this.debugInfo());
|
|
}
|
|
return this.parent.children[i + 1];
|
|
}
|
|
|
|
// Imports cloned root from another XML document
|
|
|
|
// `doc` the XML document to insert nodes from
|
|
importDocument(doc) {
|
|
var child, clonedRoot, j, len, ref1;
|
|
clonedRoot = doc.root().clone();
|
|
clonedRoot.parent = this;
|
|
clonedRoot.isRoot = false;
|
|
this.children.push(clonedRoot);
|
|
// set properties if imported element becomes the root node
|
|
if (this.type === NodeType.Document) {
|
|
clonedRoot.isRoot = true;
|
|
clonedRoot.documentObject = this;
|
|
this.rootObject = clonedRoot;
|
|
// set dtd name
|
|
if (this.children) {
|
|
ref1 = this.children;
|
|
for (j = 0, len = ref1.length; j < len; j++) {
|
|
child = ref1[j];
|
|
if (child.type === NodeType.DocType) {
|
|
child.name = clonedRoot.name;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
|
|
// Returns debug string for this node
|
|
debugInfo(name) {
|
|
var ref1, ref2;
|
|
name = name || this.name;
|
|
if ((name == null) && !((ref1 = this.parent) != null ? ref1.name : void 0)) {
|
|
return "";
|
|
} else if (name == null) {
|
|
return "parent: <" + this.parent.name + ">";
|
|
} else if (!((ref2 = this.parent) != null ? ref2.name : void 0)) {
|
|
return "node: <" + name + ">";
|
|
} else {
|
|
return "node: <" + name + ">, parent: <" + this.parent.name + ">";
|
|
}
|
|
}
|
|
|
|
// Aliases
|
|
ele(name, attributes, text) {
|
|
return this.element(name, attributes, text);
|
|
}
|
|
|
|
nod(name, attributes, text) {
|
|
return this.node(name, attributes, text);
|
|
}
|
|
|
|
txt(value) {
|
|
return this.text(value);
|
|
}
|
|
|
|
dat(value) {
|
|
return this.cdata(value);
|
|
}
|
|
|
|
com(value) {
|
|
return this.comment(value);
|
|
}
|
|
|
|
ins(target, value) {
|
|
return this.instruction(target, value);
|
|
}
|
|
|
|
doc() {
|
|
return this.document();
|
|
}
|
|
|
|
dec(version, encoding, standalone) {
|
|
return this.declaration(version, encoding, standalone);
|
|
}
|
|
|
|
e(name, attributes, text) {
|
|
return this.element(name, attributes, text);
|
|
}
|
|
|
|
n(name, attributes, text) {
|
|
return this.node(name, attributes, text);
|
|
}
|
|
|
|
t(value) {
|
|
return this.text(value);
|
|
}
|
|
|
|
d(value) {
|
|
return this.cdata(value);
|
|
}
|
|
|
|
c(value) {
|
|
return this.comment(value);
|
|
}
|
|
|
|
r(value) {
|
|
return this.raw(value);
|
|
}
|
|
|
|
i(target, value) {
|
|
return this.instruction(target, value);
|
|
}
|
|
|
|
u() {
|
|
return this.up();
|
|
}
|
|
|
|
// can be deprecated in a future release
|
|
importXMLBuilder(doc) {
|
|
return this.importDocument(doc);
|
|
}
|
|
|
|
// Adds or modifies an attribute.
|
|
|
|
// `name` attribute name
|
|
// `value` attribute value
|
|
attribute(name, value) {
|
|
throw new Error("attribute() applies to element nodes only.");
|
|
}
|
|
|
|
att(name, value) {
|
|
return this.attribute(name, value);
|
|
}
|
|
|
|
a(name, value) {
|
|
return this.attribute(name, value);
|
|
}
|
|
|
|
// Removes an attribute
|
|
|
|
// `name` attribute name
|
|
removeAttribute(name) {
|
|
throw new Error("attribute() applies to element nodes only.");
|
|
}
|
|
|
|
// DOM level 1 functions to be implemented later
|
|
replaceChild(newChild, oldChild) {
|
|
throw new Error("This DOM method is not implemented." + this.debugInfo());
|
|
}
|
|
|
|
removeChild(oldChild) {
|
|
throw new Error("This DOM method is not implemented." + this.debugInfo());
|
|
}
|
|
|
|
appendChild(newChild) {
|
|
throw new Error("This DOM method is not implemented." + this.debugInfo());
|
|
}
|
|
|
|
hasChildNodes() {
|
|
return this.children.length !== 0;
|
|
}
|
|
|
|
cloneNode(deep) {
|
|
throw new Error("This DOM method is not implemented." + this.debugInfo());
|
|
}
|
|
|
|
normalize() {
|
|
throw new Error("This DOM method is not implemented." + this.debugInfo());
|
|
}
|
|
|
|
// DOM level 2
|
|
isSupported(feature, version) {
|
|
return true;
|
|
}
|
|
|
|
hasAttributes() {
|
|
return this.attribs.length !== 0;
|
|
}
|
|
|
|
// DOM level 3 functions to be implemented later
|
|
compareDocumentPosition(other) {
|
|
var ref, res;
|
|
ref = this;
|
|
if (ref === other) {
|
|
return 0;
|
|
} else if (this.document() !== other.document()) {
|
|
res = DocumentPosition.Disconnected | DocumentPosition.ImplementationSpecific;
|
|
if (Math.random() < 0.5) {
|
|
res |= DocumentPosition.Preceding;
|
|
} else {
|
|
res |= DocumentPosition.Following;
|
|
}
|
|
return res;
|
|
} else if (ref.isAncestor(other)) {
|
|
return DocumentPosition.Contains | DocumentPosition.Preceding;
|
|
} else if (ref.isDescendant(other)) {
|
|
return DocumentPosition.Contains | DocumentPosition.Following;
|
|
} else if (ref.isPreceding(other)) {
|
|
return DocumentPosition.Preceding;
|
|
} else {
|
|
return DocumentPosition.Following;
|
|
}
|
|
}
|
|
|
|
isSameNode(other) {
|
|
throw new Error("This DOM method is not implemented." + this.debugInfo());
|
|
}
|
|
|
|
lookupPrefix(namespaceURI) {
|
|
throw new Error("This DOM method is not implemented." + this.debugInfo());
|
|
}
|
|
|
|
isDefaultNamespace(namespaceURI) {
|
|
throw new Error("This DOM method is not implemented." + this.debugInfo());
|
|
}
|
|
|
|
lookupNamespaceURI(prefix) {
|
|
throw new Error("This DOM method is not implemented." + this.debugInfo());
|
|
}
|
|
|
|
isEqualNode(node) {
|
|
var i, j, ref1;
|
|
if (node.nodeType !== this.nodeType) {
|
|
return false;
|
|
}
|
|
if (node.children.length !== this.children.length) {
|
|
return false;
|
|
}
|
|
for (i = j = 0, ref1 = this.children.length - 1; (0 <= ref1 ? j <= ref1 : j >= ref1); i = 0 <= ref1 ? ++j : --j) {
|
|
if (!this.children[i].isEqualNode(node.children[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
getFeature(feature, version) {
|
|
throw new Error("This DOM method is not implemented." + this.debugInfo());
|
|
}
|
|
|
|
setUserData(key, data, handler) {
|
|
throw new Error("This DOM method is not implemented." + this.debugInfo());
|
|
}
|
|
|
|
getUserData(key) {
|
|
throw new Error("This DOM method is not implemented." + this.debugInfo());
|
|
}
|
|
|
|
// Returns true if other is an inclusive descendant of node,
|
|
// and false otherwise.
|
|
contains(other) {
|
|
if (!other) {
|
|
return false;
|
|
}
|
|
return other === this || this.isDescendant(other);
|
|
}
|
|
|
|
// An object A is called a descendant of an object B, if either A is
|
|
// a child of B or A is a child of an object C that is a descendant of B.
|
|
isDescendant(node) {
|
|
var child, isDescendantChild, j, len, ref1;
|
|
ref1 = this.children;
|
|
for (j = 0, len = ref1.length; j < len; j++) {
|
|
child = ref1[j];
|
|
if (node === child) {
|
|
return true;
|
|
}
|
|
isDescendantChild = child.isDescendant(node);
|
|
if (isDescendantChild) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// An object A is called an ancestor of an object B if and only if
|
|
// B is a descendant of A.
|
|
isAncestor(node) {
|
|
return node.isDescendant(this);
|
|
}
|
|
|
|
// An object A is preceding an object B if A and B are in the
|
|
// same tree and A comes before B in tree order.
|
|
isPreceding(node) {
|
|
var nodePos, thisPos;
|
|
nodePos = this.treePosition(node);
|
|
thisPos = this.treePosition(this);
|
|
if (nodePos === -1 || thisPos === -1) {
|
|
return false;
|
|
} else {
|
|
return nodePos < thisPos;
|
|
}
|
|
}
|
|
|
|
// An object A is folllowing an object B if A and B are in the
|
|
// same tree and A comes after B in tree order.
|
|
isFollowing(node) {
|
|
var nodePos, thisPos;
|
|
nodePos = this.treePosition(node);
|
|
thisPos = this.treePosition(this);
|
|
if (nodePos === -1 || thisPos === -1) {
|
|
return false;
|
|
} else {
|
|
return nodePos > thisPos;
|
|
}
|
|
}
|
|
|
|
// Returns the preorder position of the given node in the tree, or -1
|
|
// if the node is not in the tree.
|
|
treePosition(node) {
|
|
var found, pos;
|
|
pos = 0;
|
|
found = false;
|
|
this.foreachTreeNode(this.document(), function(childNode) {
|
|
pos++;
|
|
if (!found && childNode === node) {
|
|
return found = true;
|
|
}
|
|
});
|
|
if (found) {
|
|
return pos;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
// Depth-first preorder traversal through the XML tree
|
|
foreachTreeNode(node, func) {
|
|
var child, j, len, ref1, res;
|
|
node || (node = this.document());
|
|
ref1 = node.children;
|
|
for (j = 0, len = ref1.length; j < len; j++) {
|
|
child = ref1[j];
|
|
if (res = func(child)) {
|
|
return res;
|
|
} else {
|
|
res = this.foreachTreeNode(child, func);
|
|
if (res) {
|
|
return res;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
// DOM level 1
|
|
Object.defineProperty(XMLNode.prototype, 'nodeName', {
|
|
get: function() {
|
|
return this.name;
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(XMLNode.prototype, 'nodeType', {
|
|
get: function() {
|
|
return this.type;
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(XMLNode.prototype, 'nodeValue', {
|
|
get: function() {
|
|
return this.value;
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(XMLNode.prototype, 'parentNode', {
|
|
get: function() {
|
|
return this.parent;
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(XMLNode.prototype, 'childNodes', {
|
|
get: function() {
|
|
if (!this.childNodeList || !this.childNodeList.nodes) {
|
|
this.childNodeList = new XMLNodeList(this.children);
|
|
}
|
|
return this.childNodeList;
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(XMLNode.prototype, 'firstChild', {
|
|
get: function() {
|
|
return this.children[0] || null;
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(XMLNode.prototype, 'lastChild', {
|
|
get: function() {
|
|
return this.children[this.children.length - 1] || null;
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(XMLNode.prototype, 'previousSibling', {
|
|
get: function() {
|
|
var i;
|
|
i = this.parent.children.indexOf(this);
|
|
return this.parent.children[i - 1] || null;
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(XMLNode.prototype, 'nextSibling', {
|
|
get: function() {
|
|
var i;
|
|
i = this.parent.children.indexOf(this);
|
|
return this.parent.children[i + 1] || null;
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(XMLNode.prototype, 'ownerDocument', {
|
|
get: function() {
|
|
return this.document() || null;
|
|
}
|
|
});
|
|
|
|
// DOM level 3
|
|
Object.defineProperty(XMLNode.prototype, 'textContent', {
|
|
get: function() {
|
|
var child, j, len, ref1, str;
|
|
if (this.nodeType === NodeType.Element || this.nodeType === NodeType.DocumentFragment) {
|
|
str = '';
|
|
ref1 = this.children;
|
|
for (j = 0, len = ref1.length; j < len; j++) {
|
|
child = ref1[j];
|
|
if (child.textContent) {
|
|
str += child.textContent;
|
|
}
|
|
}
|
|
return str;
|
|
} else {
|
|
return null;
|
|
}
|
|
},
|
|
set: function(value) {
|
|
throw new Error("This DOM method is not implemented." + this.debugInfo());
|
|
}
|
|
});
|
|
|
|
return XMLNode;
|
|
|
|
}).call(this);
|
|
|
|
}).call(this);
|