Add a starter JavaScript version of Scour
This commit is contained in:
parent
60b48353b3
commit
fbcbedef37
6 changed files with 1568 additions and 0 deletions
120
lite/index.html
Normal file
120
lite/index.html
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Scour Lite</title>
|
||||
<style type='text/css'>
|
||||
.hidden { display: none; }
|
||||
#status {
|
||||
border: solid 1px lightgrey;
|
||||
color: grey;
|
||||
margin: 10px;
|
||||
padding: 5px;
|
||||
}
|
||||
#status p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Scour Lite</h1>
|
||||
<input id='fileInput' type='file'/>
|
||||
<p id='progressPara' class='hidden'>
|
||||
<span id='stage'>Progress</span>: <progress id='progress' max='100'></progress>
|
||||
</p>
|
||||
<div>
|
||||
<div id='originalSvg' class='hidden'>
|
||||
Original:
|
||||
<a id='originalLinkText' href='#'>[text]</a>
|
||||
<a id='originalLinkSvg' href='#'>[svg]</a>
|
||||
</div>
|
||||
<div id='scouredSvg' class='hidden'>
|
||||
Scoured:
|
||||
<a id='scouredLinkText' href='#'>[text]</a>
|
||||
<a id='scouredLinkSvg' href='#'>[svg]</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id='status' class='hidden'></div>
|
||||
</body>
|
||||
<script type='text/javascript' src='pdom.js'></script>
|
||||
<script type='text/javascript'>
|
||||
var input = document.getElementById('fileInput');
|
||||
var stageSpan = document.getElementById('stage');
|
||||
var progress = document.getElementById('progress');
|
||||
var originalSvg;
|
||||
var scouredSvg;
|
||||
|
||||
document.getElementById('originalLinkText').onclick = function(evt) {
|
||||
window.open('data:text/plain;base64,' + window.btoa(originalSvg));
|
||||
};
|
||||
document.getElementById('originalLinkSvg').onclick = function(evt) {
|
||||
window.open('data:image/svg+xml;base64,' + window.btoa(originalSvg));
|
||||
};
|
||||
document.getElementById('scouredLinkText').onclick = function(evt) {
|
||||
window.open('data:text/plain;base64,' + window.btoa(scouredSvg));
|
||||
};
|
||||
document.getElementById('scouredLinkSvg').onclick = function(evt) {
|
||||
window.open('data:image/svg+xml;base64,' + window.btoa(scouredSvg));
|
||||
};
|
||||
|
||||
var handleMessage = function(evt) {
|
||||
if (typeof evt.data == 'string') {
|
||||
var p = document.createElement('p');
|
||||
p.innerHTML = evt.data;
|
||||
var status = document.getElementById('status');
|
||||
status.insertBefore(p, status.firstChild);
|
||||
} else {
|
||||
if (evt.data.stage) {
|
||||
stageSpan.innerHTML = evt.data.stage;
|
||||
}
|
||||
if (evt.data.message) {
|
||||
handleMessage({data: evt.data.message});
|
||||
}
|
||||
if (evt.data.progress) {
|
||||
handleProgress(evt.data.progress);
|
||||
}
|
||||
if (evt.data.scouredSvg) {
|
||||
document.getElementById('scouredSvg').className = '';
|
||||
scouredSvg = evt.data.scouredSvg;
|
||||
handleMessage({
|
||||
data: 'Scoured SVG came out to be ' +
|
||||
evt.data.scouredSvg.length + ' bytes'
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
var handleProgress = function(evt) {
|
||||
progress.max = evt.total;
|
||||
progress.value = evt.loaded;
|
||||
};
|
||||
var getFile = function(evt) {
|
||||
stageSpan.innerHTML = 'Loading';
|
||||
var showElems = ['progressPara', 'status', 'originalSvg'];
|
||||
for (var i in showElems) {
|
||||
document.getElementById(showElems[i]).className = '';
|
||||
}
|
||||
if (input.files.length == 1) {
|
||||
var theFile = input.files[0];
|
||||
// TODO: One day, all browsers will support passing of File blobs
|
||||
// to the worker and the creation of FileReaders inside workers.
|
||||
// When that day comes, shove this code into scour.js.
|
||||
var fr = new FileReader();
|
||||
// TODO: Use addEventListener when WebKit supports it
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=42723
|
||||
fr.onload = function(evt) {
|
||||
handleMessage({data:'Loaded \'' + theFile.name + '\'' + ' (' + theFile.size + ' bytes)'});
|
||||
var worker = new Worker('scour.js');
|
||||
worker.addEventListener('message', handleMessage);
|
||||
originalSvg = evt.target.result;
|
||||
var parser = new pdom.DOMParser();
|
||||
var pdoc = parser.parseFromString(originalSvg);
|
||||
// TODO: Restore this once pdom is working satisfactorily.
|
||||
worker.postMessage(originalSvg);
|
||||
};
|
||||
fr.onprogress = handleProgress;
|
||||
fr.readAsText(theFile);
|
||||
}
|
||||
};
|
||||
input.addEventListener('change', getFile, false);
|
||||
</script>
|
||||
</html>
|
||||
49
lite/muther.js
Normal file
49
lite/muther.js
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* Mini Unit Test Harness
|
||||
* Copyright(c) 2011, Google Inc.
|
||||
*
|
||||
* A really tiny unit test harness.
|
||||
*/
|
||||
|
||||
var muther = muther || {};
|
||||
|
||||
muther.assert = function(cond, err) {
|
||||
if (!cond) {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
muther.addTest_ = function(testDiv, innerHTML, pass) {
|
||||
var theTest = document.createElement('div');
|
||||
// Convert all angle brackets into displayable text.
|
||||
innerHTML = innerHTML.replace(/&/g, '&').
|
||||
replace(/</g, '<').
|
||||
replace(/>/g, '>');
|
||||
theTest.innerHTML = innerHTML;
|
||||
theTest.setAttribute('style', pass ? 'color:#090' : 'color:#900');
|
||||
testDiv.appendChild(theTest);
|
||||
};
|
||||
|
||||
// Run through all tests and record the results.
|
||||
muther.test = function(testsToRun) {
|
||||
var progress = document.createElement('progress');
|
||||
var testDiv = document.createElement('div');
|
||||
document.body.insertBefore(testDiv, document.body.firstChild);
|
||||
document.body.insertBefore(progress, document.body.firstChild);
|
||||
|
||||
var max = testsToRun.length;
|
||||
progress.max = max;
|
||||
progress.value = 0;
|
||||
testDiv.innerHTML = max + ' Tests';
|
||||
for (var t = 0; t < max; ++t) {
|
||||
var test = testsToRun[t];
|
||||
try {
|
||||
test();
|
||||
muther.addTest_(testDiv, test.name + ': Pass', true);
|
||||
} catch(e) {
|
||||
muther.addTest_(testDiv, test.name + ': Fail. ' + e, false);
|
||||
}
|
||||
progress.value += 1;
|
||||
}
|
||||
};
|
||||
|
||||
856
lite/pdom.js
Normal file
856
lite/pdom.js
Normal file
|
|
@ -0,0 +1,856 @@
|
|||
/**
|
||||
* Pico DOM
|
||||
* Copyright(c) 2011, Google Inc.
|
||||
*
|
||||
* A really tiny implementation of the DOM for use in Web Workers.
|
||||
*/
|
||||
|
||||
// TODO: Look into defineProperty instead of getters.
|
||||
|
||||
var pdom = pdom || {};
|
||||
|
||||
// ===========================================================================
|
||||
// Stolen from Closure because it's the best way to do Java-like inheritance.
|
||||
pdom.base = function(me, opt_methodName, var_args) {
|
||||
var caller = arguments.callee.caller;
|
||||
if (caller.superClass_) {
|
||||
// This is a constructor. Call the superclass constructor.
|
||||
return caller.superClass_.constructor.apply(
|
||||
me, Array.prototype.slice.call(arguments, 1));
|
||||
}
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 2);
|
||||
var foundCaller = false;
|
||||
for (var ctor = me.constructor;
|
||||
ctor; ctor = ctor.superClass_ && ctor.superClass_.constructor) {
|
||||
if (ctor.prototype[opt_methodName] === caller) {
|
||||
foundCaller = true;
|
||||
} else if (foundCaller) {
|
||||
return ctor.prototype[opt_methodName].apply(me, args);
|
||||
}
|
||||
}
|
||||
|
||||
// If we did not find the caller in the prototype chain,
|
||||
// then one of two things happened:
|
||||
// 1) The caller is an instance method.
|
||||
// 2) This method was not called by the right caller.
|
||||
if (me[opt_methodName] === caller) {
|
||||
return me.constructor.prototype[opt_methodName].apply(me, args);
|
||||
} else {
|
||||
throw Error(
|
||||
'goog.base called from a method of one name ' +
|
||||
'to a method of a different name');
|
||||
}
|
||||
};
|
||||
pdom.inherits = function(childCtor, parentCtor) {
|
||||
/** @constructor */
|
||||
function tempCtor() {};
|
||||
tempCtor.prototype = parentCtor.prototype;
|
||||
childCtor.superClass_ = parentCtor.prototype;
|
||||
childCtor.prototype = new tempCtor();
|
||||
childCtor.prototype.constructor = childCtor;
|
||||
};
|
||||
// ===========================================================================
|
||||
|
||||
|
||||
/**
|
||||
* A DOMException
|
||||
*
|
||||
* @param {number} code The DOM exception code.
|
||||
* @constructor
|
||||
*/
|
||||
pdom.DOMException = function(code) {
|
||||
this.__defineGetter__('code', function() { return code });
|
||||
};
|
||||
pdom.DOMException.INDEX_SIZE_ERR = 1;
|
||||
pdom.DOMException.DOMSTRING_SIZE_ERR = 2;
|
||||
pdom.DOMException.HIERARCHY_REQUEST_ERR = 3;
|
||||
pdom.DOMException.WRONG_DOCUMENT_ERR = 4;
|
||||
pdom.DOMException.INVALID_CHARACTER_ERR = 5;
|
||||
pdom.DOMException.NO_DATA_ALLOWED_ERR = 6;
|
||||
pdom.DOMException.NO_MODIFICATION_ALLOWED_ERR = 7;
|
||||
pdom.DOMException.NOT_FOUND_ERR = 8;
|
||||
pdom.DOMException.NOT_SUPPORTED_ERR = 9;
|
||||
pdom.DOMException.INUSE_ATTRIBUTE_ERR = 10;
|
||||
pdom.DOMException.INVALID_STATE_ERR = 11;
|
||||
pdom.DOMException.SYNTAX_ERR = 12;
|
||||
pdom.DOMException.INVALID_MODIFICATION_ERR = 13;
|
||||
pdom.DOMException.NAMESPACE_ERR = 14;
|
||||
pdom.DOMException.INVALID_ACCESS_ERR = 15;
|
||||
pdom.DOMException.VALIDATION_ERR = 16;
|
||||
pdom.DOMException.TYPE_MISMATCH_ERR = 17;
|
||||
|
||||
|
||||
/**
|
||||
* A NodeList.
|
||||
*
|
||||
* @param {Array.<Node>} nodeArray The array of nodes.
|
||||
* @constructor
|
||||
*/
|
||||
pdom.NodeList = function(nodeArray) {
|
||||
this.nodes_ = nodeArray;
|
||||
|
||||
this.__defineGetter__('length', function() { return this.nodes_.length; });
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} index The index of the node to return.
|
||||
* @return {pdom.Node} The node.
|
||||
*/
|
||||
pdom.NodeList.prototype.item = function(index) {
|
||||
if (index >= 0 && index < this.length) {
|
||||
return this.nodes_[index];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Object.<string, pdom.Node>} nodeMap An object containing the
|
||||
* attribute name-Node pairs.
|
||||
* @constructor
|
||||
*/
|
||||
pdom.NamedNodeMap = function(nodeMap) {
|
||||
this.setNodeMapInternal(nodeMap);
|
||||
this.__defineGetter__('length', function() { return this.attrs_.length });
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An array of the nodes.
|
||||
* @type {Array.<pdom.Node>}
|
||||
* @private
|
||||
*/
|
||||
pdom.NamedNodeMap.prototype.attrs_ = [];
|
||||
|
||||
|
||||
/**
|
||||
* The node map.
|
||||
* @type {Object.<string, pdom.Node>}
|
||||
* @private
|
||||
*/
|
||||
pdom.NamedNodeMap.prototype.nodeMap_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the internal node map (and updates the array).
|
||||
* @param {Object.<string, pdom.Node>} The node map.
|
||||
*/
|
||||
pdom.NamedNodeMap.prototype.setNodeMapInternal = function(nodeMap) {
|
||||
this.nodeMap_ = {};
|
||||
this.attrs_ = [];
|
||||
for (var name in nodeMap) {
|
||||
var attr = new pdom.Attr(name, nodeMap[name]);
|
||||
this.attrs_.push(attr);
|
||||
this.nodeMap_[name] = attr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} name The name of the node to return.
|
||||
* @return {pdom.Node} The named node.
|
||||
*/
|
||||
pdom.NamedNodeMap.prototype.getNamedItem = function(name) {
|
||||
return this.nodeMap_[name] || null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} index The index of the node to return.
|
||||
*/
|
||||
pdom.NamedNodeMap.prototype.item = function(index) {
|
||||
if (index >= 0 && index < this.attrs_.length) {
|
||||
return this.attrs_[index];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A Node.
|
||||
*
|
||||
* @param {pdom.Node} opt_parentNode The parent node, which can be null.
|
||||
* @constructor
|
||||
*/
|
||||
pdom.Node = function(opt_parentNode) {
|
||||
this.parentNode_ = opt_parentNode;
|
||||
|
||||
this.__defineGetter__('nodeType', function() { throw 'Unknown type of Node' });
|
||||
this.__defineGetter__('parentNode', function() { return this.parentNode_ });
|
||||
|
||||
/**
|
||||
* An array of child nodes.
|
||||
* @type {Array.<pdom.Node>}
|
||||
* @private
|
||||
*/
|
||||
this.childNodes_ = [];
|
||||
|
||||
// Read-only properties.
|
||||
this.__defineGetter__('childNodes', function() {
|
||||
return new pdom.NodeList(this.childNodes_);
|
||||
});
|
||||
this.__defineGetter__('firstChild', function() {
|
||||
return this.childNodes_[0] || null;
|
||||
});
|
||||
this.__defineGetter__('lastChild', function() {
|
||||
return this.childNodes_.length <= 0 ? null :
|
||||
this.childNodes_[this.childNodes_.length - 1];
|
||||
});
|
||||
this.__defineGetter__('previousSibling', function() {
|
||||
var parent = this.parentNode;
|
||||
if (parent) {
|
||||
var familySize = parent.childNodes_.length;
|
||||
for (var i = 0; i < familySize; ++i) {
|
||||
var child = parent.childNodes_[i];
|
||||
if (child === this && i > 0) {
|
||||
return parent.childNodes_[i - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
this.__defineGetter__('nextSibling', function() {
|
||||
var parent = this.parentNode;
|
||||
if (parent) {
|
||||
var familySize = parent.childNodes_.length;
|
||||
for (var i = 0; i < familySize; ++i) {
|
||||
var child = parent.childNodes_[i];
|
||||
if (child === this && i < familySize - 1) {
|
||||
return parent.childNodes_[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
this.__defineGetter__('attributes', function() { return null });
|
||||
|
||||
this.__defineGetter__('namespaceURI', function() {
|
||||
if (this.parentNode_) {
|
||||
return this.parentNode_.namespaceURI;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
pdom.Node.ELEMENT_NODE = 1;
|
||||
pdom.Node.ATTRIBUTE_NODE = 2;
|
||||
pdom.Node.TEXT_NODE = 3;
|
||||
pdom.Node.CDATA_SECTION_NODE = 4;
|
||||
pdom.Node.ENTITY_REFERENCE_NODE = 5;
|
||||
pdom.Node.ENTITY_NODE = 6;
|
||||
pdom.Node.PROCESSING_INSTRUCTION_NODE = 7;
|
||||
pdom.Node.COMMENT_NODE = 8;
|
||||
pdom.Node.DOCUMENT_NODE = 9;
|
||||
pdom.Node.DOCUMENT_TYPE_NODE = 10;
|
||||
pdom.Node.DOCUMENT_FRAGMENT_NODE = 11;
|
||||
pdom.Node.NOTATION_NODE = 12;
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the node has any children.
|
||||
*/
|
||||
pdom.Node.prototype.hasChildNodes = function() {
|
||||
return this.childNodes_.length > 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {pdom.Node} child The node to remove.
|
||||
* @return {pdom.Node} The removed node.
|
||||
*/
|
||||
pdom.Node.prototype.removeChild = function(child) {
|
||||
var max = this.childNodes.length;
|
||||
for (var i = 0; i < max; ++i) {
|
||||
if (this.childNodes_[i] == child) {
|
||||
this.childNodes_.splice(i, 1);
|
||||
child.parentNode_ = null;
|
||||
return child;
|
||||
}
|
||||
}
|
||||
throw new pdom.DOMException(pdom.DOMException.NOT_FOUND_ERR);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {pdom.Node} child The node to append.
|
||||
* @return {pdom.Node} The appended node.
|
||||
*/
|
||||
pdom.Node.prototype.appendChild = function(child) {
|
||||
if (child.parentNode) {
|
||||
child.parentNode.removeChild(child);
|
||||
}
|
||||
this.childNodes_.push(child);
|
||||
return child;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A XML Document.
|
||||
*
|
||||
* @param {string} opt_text The optional text of the document.
|
||||
* @param {pdom.Node} opt_parentNode The parent node, which can be null.
|
||||
* @constructor
|
||||
* @extends {pdom.Node}
|
||||
*/
|
||||
pdom.XMLDocument = function(opt_text) {
|
||||
pdom.base(this, null);
|
||||
|
||||
this.__defineGetter__('nodeType', function() {
|
||||
return pdom.Node.DOCUMENT_NODE;
|
||||
});
|
||||
this.__defineGetter__('documentElement', function() {
|
||||
for (var i = 0; i < this.childNodes_.length; ++i) {
|
||||
if (this.childNodes_[i].nodeType == 1) {
|
||||
return this.childNodes_[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
};
|
||||
pdom.inherits(pdom.XMLDocument, pdom.Node);
|
||||
|
||||
|
||||
/**
|
||||
* A DocumentType node.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {pdom.Node}
|
||||
*/
|
||||
pdom.DocumentType = function() {
|
||||
pdom.base(this, null);
|
||||
|
||||
this.__defineGetter__('nodeType', function() {
|
||||
return pdom.Node.DOCUMENT_TYPE_NODE
|
||||
});
|
||||
};
|
||||
pdom.inherits(pdom.DocumentType, pdom.Node);
|
||||
|
||||
|
||||
/**
|
||||
* An Attr node.
|
||||
*
|
||||
* @param {string} name The name of the attribute.
|
||||
* @param {string} value The value of the attribute.
|
||||
* @constructor
|
||||
* @extends {pdom.Attr}
|
||||
*/
|
||||
pdom.Attr = function(name, value) {
|
||||
pdom.base(this, null);
|
||||
|
||||
this.__defineGetter__('nodeType', function() {
|
||||
return pdom.Node.ATTRIBUTE_NODE;
|
||||
});
|
||||
this.__defineGetter__('name', function() { return name });
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
this.value = value;
|
||||
};
|
||||
pdom.inherits(pdom.Attr, pdom.Node);
|
||||
|
||||
|
||||
/**
|
||||
* An Element node.
|
||||
*
|
||||
* @param {string} tagName The tag name of this element.
|
||||
* @param {pdom.Node} opt_parentNode The parent node, which can be null.
|
||||
* @param {Object.<string,string>} opt_attrs The attribute map.
|
||||
* @constructor
|
||||
* @extends {pdom.Node}
|
||||
*/
|
||||
pdom.Element = function(tagName, opt_parentNode, opt_attrs) {
|
||||
pdom.base(this, opt_parentNode);
|
||||
|
||||
/**
|
||||
* Internal map of attributes for this element.
|
||||
*
|
||||
* @type {Object.<string, string>}
|
||||
* @private
|
||||
*/
|
||||
this.attributes_ = opt_attrs || {};
|
||||
|
||||
this.__defineGetter__('attributes', function() {
|
||||
if (!this.attributeMap_) {
|
||||
this.attributeMap_ = new pdom.NamedNodeMap(this.attributes_);
|
||||
}
|
||||
return this.attributeMap_;
|
||||
});
|
||||
|
||||
this.__defineGetter__('nodeType', function() {
|
||||
return pdom.Node.ELEMENT_NODE;
|
||||
});
|
||||
this.__defineGetter__('tagName', function() { return tagName });
|
||||
this.__defineGetter__('nodeName', function() { return tagName });
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.namespaceURI_ = this.parentNode_ ? this.parentNode_.namespaceURI : null;
|
||||
|
||||
/**
|
||||
* Map of namespace prefix to URI.
|
||||
*
|
||||
* @type {Object.<string, string>}
|
||||
*/
|
||||
this.nsPrefixMapInternal = {};
|
||||
|
||||
// Generate map of prefixes to namespace URIs. Also, discover if there is
|
||||
// a default namespace on this element.
|
||||
for (var attrName in this.attributes_) {
|
||||
if (attrName.indexOf('xmlns:') == 0 && attrName.length > 6) {
|
||||
var prefix = attrName.substring(6);
|
||||
this.nsPrefixMapInternal[prefix] = this.attributes_[attrName];
|
||||
} else if (attrName === 'xmlns') {
|
||||
this.namespaceURI_ = this.attributes_[attrName];
|
||||
}
|
||||
}
|
||||
|
||||
// If the tagname includes a colon, resolve the namespace prefix.
|
||||
var colonIndex = tagName.indexOf(':');
|
||||
if (colonIndex != -1) {
|
||||
var prefix = tagName.substring(0, colonIndex);
|
||||
var node = this;
|
||||
while (node) {
|
||||
var uri = node.nsPrefixMapInternal[prefix];
|
||||
if (uri) {
|
||||
this.namespaceURI_ = uri;
|
||||
break;
|
||||
}
|
||||
node = node.parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
this.__defineGetter__('namespaceURI', function() { return this.namespaceURI_ });
|
||||
};
|
||||
pdom.inherits(pdom.Element, pdom.Node);
|
||||
|
||||
|
||||
/**
|
||||
* @type {pdom.NamedNodeMap}
|
||||
* @private
|
||||
*/
|
||||
pdom.Element.prototype.attributeMap_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} attrName The attribute name to get.
|
||||
*/
|
||||
pdom.Element.prototype.getAttribute = function(attrName) {
|
||||
var attrVal = this.attributes_[attrName] || '';
|
||||
return attrVal;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} name The attribute name to set.
|
||||
* @param {string} value The attribute value to set.
|
||||
*/
|
||||
pdom.Element.prototype.setAttribute = function(name, value) {
|
||||
this.attributes_[name] = value;
|
||||
if (this.attributeMap_) {
|
||||
this.attributeMap_.setNodeMapInternal(this.attributes_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} name The attribute to remove.
|
||||
*/
|
||||
pdom.Element.prototype.removeAttribute = function(name) {
|
||||
delete this.attributes_[name];
|
||||
if (this.attributeMap_) {
|
||||
this.attributeMap_.setNodeMapInternal(this.attributes_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the element had an attribute.
|
||||
*/
|
||||
pdom.Element.prototype.hasAttribute = function(name) {
|
||||
return !!this.attributes_[name];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* CharacterData node.
|
||||
*
|
||||
* @param {string} opt_text The optional text of the document.
|
||||
* @param {pdom.Node} opt_parentNode The parent node, which can be null.
|
||||
* @constructor
|
||||
* @extends {pdom.Node}
|
||||
*/
|
||||
pdom.CharacterData = function(opt_text, opt_parentNode) {
|
||||
pdom.base(this, opt_parentNode);
|
||||
|
||||
this.__defineGetter__('data', function() { return opt_text });
|
||||
};
|
||||
pdom.inherits(pdom.CharacterData, pdom.Node);
|
||||
|
||||
|
||||
/**
|
||||
* A Comment node.
|
||||
*
|
||||
* @param {string} opt_text The optional text of the comment.
|
||||
* @param {pdom.Node} opt_parentNode The parent node, which can be null.
|
||||
* @constructor
|
||||
* @extends {pdom.CharacterData}
|
||||
*/
|
||||
pdom.Comment = function(opt_text, opt_parentNode) {
|
||||
pdom.base(this, opt_text);
|
||||
|
||||
this.__defineGetter__('nodeType', function() {
|
||||
return pdom.Node.COMMENT_NODE;
|
||||
});
|
||||
};
|
||||
pdom.inherits(pdom.Comment, pdom.CharacterData);
|
||||
|
||||
|
||||
/**
|
||||
* A Text node.
|
||||
*
|
||||
* @param {string} opt_text The optional text of the comment.
|
||||
* @param {pdom.Node} opt_parentNode The parent node, which can be null.
|
||||
* @constructor
|
||||
* @extends {pdom.CharacterData}
|
||||
*/
|
||||
pdom.Text = function(opt_text, opt_parentNode) {
|
||||
pdom.base(this, opt_text, opt_parentNode);
|
||||
|
||||
this.__defineGetter__('nodeType', function() {
|
||||
return pdom.Node.TEXT_NODE;
|
||||
});
|
||||
};
|
||||
pdom.inherits(pdom.Text, pdom.CharacterData);
|
||||
|
||||
|
||||
|
||||
pdom.parse = {};
|
||||
|
||||
/**
|
||||
* Swallows all whitespace on the left.
|
||||
*
|
||||
* @private
|
||||
* @return {boolean} True if some whitespace characters were swallowed.
|
||||
*/
|
||||
pdom.parse.swallowWS_ = function(parsingContext) {
|
||||
var wsMatches = parsingContext.xmlText.match(/^\s+/);
|
||||
if (wsMatches && wsMatches.length > 0) {
|
||||
parsingContext.offset += wsMatches[0].length;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {boolean} True if some cruft was swallowed.
|
||||
*/
|
||||
pdom.parse.swallowXmlCruft_ = function(parsingContext, head, tail) {
|
||||
pdom.parse.swallowWS_(parsingContext);
|
||||
var text = parsingContext.xmlText;
|
||||
var start = parsingContext.offset;
|
||||
// If we find the start, strip it all off.
|
||||
if (text.indexOf(head, start) == 0) {
|
||||
var end = text.indexOf(tail, start + head.length);
|
||||
if (end == -1) {
|
||||
throw 'Could not find the end of the thing (' + tail + ')';
|
||||
}
|
||||
parsingContext.offset = end + tail.length;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses the XML prolog, if present.
|
||||
*
|
||||
* @private
|
||||
* @return {boolean} True if an XML prolog was found.
|
||||
*/
|
||||
pdom.parse.parseProlog_ = function(parsingContext) {
|
||||
return pdom.parse.swallowXmlCruft_(parsingContext, '<?xml ', '?>');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parses the DOCTYPE, if present.
|
||||
*
|
||||
* @return {boolean} True if a DOCTYPE was found.
|
||||
*/
|
||||
pdom.parse.parseDocType_ = function(parsingContext) {
|
||||
swallowWS(parsingContext);
|
||||
var text = parsingContext.xmlText;
|
||||
var start = parsingContext.offset;
|
||||
var head = '<!DOCTYPE ';
|
||||
if (text.indexOf(head, start) == 0) {
|
||||
// Deal with [] in the DOCTYPE.
|
||||
var startBracket = text.indexOf('[', start + head.length);
|
||||
if (startBracket != -1) {
|
||||
var endBracket = text.indexOf(']', startBracket + 1);
|
||||
if (endBracket == -1) {
|
||||
throw 'Could not find end ] in DOCTYPE';
|
||||
}
|
||||
start = endBracket + 1;
|
||||
}
|
||||
|
||||
var endDocType = text.indexOf('>', start + head.length);
|
||||
if (endDocType == -1) {
|
||||
throw 'Could not find the end of the DOCTYPE (>)';
|
||||
}
|
||||
parsingContext.offset = endDocType + 2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parses one node from the XML stream.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} parsingContext The parsing context.
|
||||
* @return {pdom.Node} Returns the Node or null if none are found.
|
||||
*/
|
||||
pdom.parse.parseOneNode_ = function(parsingContext) {
|
||||
var i = parsingContext.offset;
|
||||
var xmlText = parsingContext.xmlText;
|
||||
|
||||
// Detect if it's a comment (<!-- -->)
|
||||
var COMMENT_START = '<!--';
|
||||
var COMMENT_END = '-->';
|
||||
if (xmlText.indexOf(COMMENT_START, i) == i) {
|
||||
var endComment = xmlText.indexOf(COMMENT_END, i + COMMENT_START.length + 1);
|
||||
if (endComment == -1) {
|
||||
throw "End tag for comment not found";
|
||||
}
|
||||
var newComment = new pdom.Comment(
|
||||
xmlText.substring(i + COMMENT_START.length, endComment),
|
||||
parsingContext.currentNode);
|
||||
parsingContext.currentNode.childNodes_.push(newComment);
|
||||
parsingContext.offset = endComment + COMMENT_END.length;
|
||||
return newComment;
|
||||
}
|
||||
|
||||
// Determine if it's a DOCTYPE (<!DOCTYPE ...[]>)
|
||||
var DOCTYPE_START = '<!DOCTYPE ';
|
||||
var DOCTYPE_END = '>';
|
||||
if (xmlText.indexOf(DOCTYPE_START, i) == i) {
|
||||
// Deal with [] in the DOCTYPE.
|
||||
var startBracket = xmlText.indexOf('[', i + DOCTYPE_START.length + 1);
|
||||
if (startBracket != -1) {
|
||||
var endBracket = xmlText.indexOf(']', startBracket + 1);
|
||||
if (endBracket == -1) {
|
||||
throw 'Could not find end ] in DOCTYPE';
|
||||
}
|
||||
i = endBracket + 1;
|
||||
}
|
||||
|
||||
// TODO: Is this right? Shouldn't it be after the [] if they were present?
|
||||
var endDocType = xmlText.indexOf('>', i + DOCTYPE_START.length + 1);
|
||||
if (endDocType == -1) {
|
||||
throw 'Could not find the end of the DOCTYPE (>)';
|
||||
}
|
||||
var newDocType = new pdom.DocType();
|
||||
parsingContext.currentNode.childNodes_.push(newDocType);
|
||||
parsingContext.offset = endDocType + 1;
|
||||
return newDocType;
|
||||
}
|
||||
|
||||
// If we are inside an element, see if we have the end tag.
|
||||
if (parsingContext.currentNode.nodeType == 1 &&
|
||||
xmlText.indexOf('</', i) == i) {
|
||||
// Look for end of end tag.
|
||||
var endEndTagIndex = xmlText.indexOf('>', i + 2);
|
||||
if (endEndTagIndex == -1) {
|
||||
throw 'Could not find end of end tag';
|
||||
}
|
||||
|
||||
// Check if the tagname matches the end tag. If not, that's an error.
|
||||
var tagName = xmlText.substring(i + 2, endEndTagIndex);
|
||||
if (tagName != parsingContext.currentNode.tagName) {
|
||||
throw 'Found </' + tagName + '> instead of </' +
|
||||
parsingContext.currentNode.tagName + '>';
|
||||
}
|
||||
|
||||
// Otherwise, parsing of the current element is done. Return it and
|
||||
// update the parsing context.
|
||||
var elementToReturn = parsingContext.currentNode;
|
||||
parsingContext.offset = endEndTagIndex + 1;
|
||||
parsingContext.currentNode = elementToReturn.parentNode;
|
||||
return elementToReturn;
|
||||
}
|
||||
|
||||
// TODO: Detect if the element has a proper name.
|
||||
if (xmlText[i] == '<') {
|
||||
var isSelfClosing = false;
|
||||
var selfClosingElementIndex = xmlText.indexOf('/>', i + 1);
|
||||
var endStartTagIndex = xmlText.indexOf('>', i + 1)
|
||||
if (selfClosingElementIndex == -1 && endStartTagIndex == -1) {
|
||||
throw 'Could not find end of start tag in Element';
|
||||
}
|
||||
|
||||
// Self-closing element.
|
||||
if (selfClosingElementIndex != -1 &&
|
||||
selfClosingElementIndex < endStartTagIndex) {
|
||||
endStartTagIndex = selfClosingElementIndex;
|
||||
isSelfClosing = true;
|
||||
}
|
||||
|
||||
var attrs = {};
|
||||
|
||||
// TODO: This should be whitespace, not space.
|
||||
var tagNameIndex = xmlText.indexOf(' ', i + 1);
|
||||
if (tagNameIndex == -1 || tagNameIndex > endStartTagIndex) {
|
||||
tagNameIndex = endStartTagIndex;
|
||||
} else {
|
||||
// Find all attributes and record them.
|
||||
var attrGlobs = xmlText.substring(tagNameIndex + 1, endStartTagIndex).trim();
|
||||
var j = 0;
|
||||
while (j < attrGlobs.length) {
|
||||
var equalsIndex = attrGlobs.indexOf('=', j);
|
||||
if (equalsIndex == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Found an attribute name-value pair.
|
||||
var attrName = attrGlobs.substring(j, equalsIndex).trim();
|
||||
|
||||
j = equalsIndex + 1;
|
||||
var theRest = attrGlobs.substring(j);
|
||||
var singleQuoteIndex = theRest.indexOf('\'', 0);
|
||||
var doubleQuoteIndex = theRest.indexOf('"', 0);
|
||||
if (singleQuoteIndex == -1 && doubleQuoteIndex == -1) {
|
||||
throw 'Attribute "' + attrName + '" found with no quoted value';
|
||||
}
|
||||
|
||||
var quoteChar = '"';
|
||||
var quoteIndex = doubleQuoteIndex;
|
||||
if (singleQuoteIndex != -1 &&
|
||||
((doubleQuoteIndex != -1 && singleQuoteIndex < doubleQuoteIndex) ||
|
||||
doubleQuoteIndex == -1)) {
|
||||
// Singly-quoted.
|
||||
quoteChar = '\'';
|
||||
quoteIndex = singleQuoteIndex;
|
||||
}
|
||||
|
||||
var endQuoteIndex = theRest.indexOf(quoteChar, quoteIndex + 1);
|
||||
if (endQuoteIndex == -1) {
|
||||
throw 'Did not find end quote for value of attribute "' + attrName + '"';
|
||||
}
|
||||
|
||||
var attrVal = theRest.substring(quoteIndex + 1, endQuoteIndex);
|
||||
attrs[attrName] = attrVal;
|
||||
|
||||
j += endQuoteIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
var newElementNode = new pdom.Element(
|
||||
xmlText.substring(i + 1, tagNameIndex),
|
||||
parsingContext.currentNode,
|
||||
attrs);
|
||||
|
||||
parsingContext.offset = endStartTagIndex + 1;
|
||||
parsingContext.currentNode.childNodes_.push(newElementNode);
|
||||
|
||||
if (isSelfClosing) {
|
||||
// Nudge it past the closing bracket.
|
||||
parsingContext.offset += 1;
|
||||
return newElementNode;
|
||||
}
|
||||
|
||||
// Else, recurse into this element.
|
||||
parsingContext.currentNode = newElementNode;
|
||||
return pdom.parse.parseOneNode_(parsingContext);
|
||||
}
|
||||
|
||||
// Everything else is a text node.
|
||||
if (i != xmlText.length) {
|
||||
var endTextIndex = xmlText.indexOf('<', i + 1);
|
||||
if (endTextIndex == -1) {
|
||||
endTextIndex = xmlText.length;
|
||||
}
|
||||
var theText = xmlText.substring(i, endTextIndex);
|
||||
var newTextNode = new pdom.Text(theText, parsingContext.currentNode);
|
||||
parsingContext.currentNode.childNodes_.push(newTextNode);
|
||||
parsingContext.offset = endTextIndex;
|
||||
return newTextNode;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A DOM Parser.
|
||||
*/
|
||||
pdom.DOMParser = function(xmlText) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} xmlText The XML Text.
|
||||
* @return {pdom.XMLDocument}
|
||||
*/
|
||||
pdom.DOMParser.prototype.parseFromString = function(xmlText) {
|
||||
var theDoc = new pdom.XMLDocument(xmlText);
|
||||
var parsingContext = {xmlText: xmlText, offset: 0, currentNode: theDoc};
|
||||
pdom.parse.parseProlog_(parsingContext);
|
||||
while (!!(node = pdom.parse.parseOneNode_(parsingContext))) {
|
||||
// do nothing.
|
||||
};
|
||||
return theDoc;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A XML Serializer.
|
||||
*/
|
||||
pdom.XMLSerializer = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {pdom.Node} node A node.
|
||||
* @return {string} The node serialized to text.
|
||||
*/
|
||||
pdom.XMLSerializer.prototype.serializeToString = function(node) {
|
||||
if (!(node instanceof pdom.Node)) {
|
||||
throw 'Argument XMLSerializer.serializeToString() was not a pdom.Node';
|
||||
}
|
||||
var str = '';
|
||||
switch (node.nodeType) {
|
||||
case pdom.Node.DOCUMENT_NODE:
|
||||
return this.serializeToString(node.documentElement);
|
||||
case pdom.Node.ELEMENT_NODE:
|
||||
str = '<' + node.tagName;
|
||||
if (node.attributes && node.attributes.length > 0) {
|
||||
for (var i = 0; i < node.attributes.length; ++i) {
|
||||
var attr = node.attributes.item(i);
|
||||
str += ' ' + attr.name + '="' + attr.value + '"';
|
||||
}
|
||||
}
|
||||
if (node.childNodes.length > 0) {
|
||||
str += '>';
|
||||
for (var i = 0; i < node.childNodes.length; ++i) {
|
||||
var child = node.childNodes.item(i);
|
||||
str += this.serializeToString(child);
|
||||
}
|
||||
str += '</' + node.tagName + '>';
|
||||
} else {
|
||||
str += '/>'
|
||||
}
|
||||
return str;
|
||||
case pdom.Node.TEXT_NODE:
|
||||
return node.data;
|
||||
}
|
||||
};
|
||||
203
lite/pdom_support.html
Normal file
203
lite/pdom_support.html
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>DOM Core Support in pdom</title>
|
||||
<style type="text/css">
|
||||
table * { font-size: small; }
|
||||
table a { color: white; font-weight: bold; }
|
||||
.no { background-color: red; color: white; }
|
||||
.yes { background-color: green; color: white; }
|
||||
.partial { background-color: orange; color: white; }
|
||||
|
||||
.dom2 { display: none; }
|
||||
.dom3 { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>DOM Core Support in pdom</h1>
|
||||
<p>This table shows the current level of <a href="http://www.w3.org/TR/DOM-Level-3-Core/">DOM Core</a> support in pdom. At present, this table only shows <a href="http://www.w3.org/TR/REC-DOM-Level-1/">DOM Core Level 1</a> and a couple properties/methods from DOM Level 2.</p>
|
||||
<table border="1">
|
||||
<tr><th>Interface</th><th>Property/Method</th><th>Support?</th></tr>
|
||||
|
||||
<!--
|
||||
// DOM Core Level 2 additions
|
||||
interface DOMImplementation {
|
||||
DocumentType createDocumentType(in DOMString qualifiedName, in DOMString publicId, in DOMString systemId)
|
||||
Document createDocument(in DOMString namespaceURI, in DOMString qualifiedName, in DocumentType doctype)
|
||||
};
|
||||
|
||||
interface Node {
|
||||
boolean isSupported(in DOMString feature, in DOMString version);
|
||||
DOMString prefix;
|
||||
DOMString localName;
|
||||
boolean hasAttributes();
|
||||
};
|
||||
|
||||
interface NamedNodeMap {
|
||||
Node getNamedItemNS(in DOMString namespaceURI, in DOMString localName);
|
||||
Node setNamedItemNS(in Node arg)
|
||||
Node removeNamedItemNS(in DOMString namespaceURI, in DOMString localName)
|
||||
};
|
||||
|
||||
interface Attr : Node {
|
||||
Element ownerElement;
|
||||
};
|
||||
|
||||
interface Element : Node {
|
||||
DOMString getAttributeNS(in DOMString namespaceURI, in DOMString localName);
|
||||
void setAttributeNS(in DOMString namespaceURI, in DOMString qualifiedName, in DOMString value)
|
||||
void removeAttributeNS(in DOMString namespaceURI, in DOMString localName)
|
||||
Attr getAttributeNodeNS(in DOMString namespaceURI, in DOMString localName);
|
||||
Attr setAttributeNodeNS(in Attr newAttr)
|
||||
NodeList getElementsByTagNameNS(in DOMString namespaceURI, in DOMString localName);
|
||||
boolean hasAttributeNS(in DOMString namespaceURI, in DOMString localName);
|
||||
};
|
||||
|
||||
interface DocumentType : Node {
|
||||
DOMString publicId;
|
||||
DOMString systemId;
|
||||
DOMString internalSubset;
|
||||
};
|
||||
|
||||
interface Document : Node {
|
||||
Node importNode(in Node importedNode, in boolean deep)
|
||||
Element createElementNS(in DOMString namespaceURI, in DOMString qualifiedName)
|
||||
Attr createAttributeNS(in DOMString namespaceURI, in DOMString qualifiedName)
|
||||
NodeList getElementsByTagNameNS(in DOMString namespaceURI, in DOMString localName);
|
||||
};
|
||||
};
|
||||
|
||||
-->
|
||||
|
||||
<tr id="Node"><td rowspan="18" class="partial"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1950641247">Node</a></td>
|
||||
<td class="no">DOMString <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-F68D095">nodeName</a></td><td class="no"></td></tr><tr>
|
||||
<td class="no">DOMString <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-F68D080">nodeValue</a></td><td class="no"></td></tr><tr>
|
||||
<td class="yes">unsigned short <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-111237558">nodeType</a></td><td class="yes"></td></tr><tr>
|
||||
<td class="yes">Node <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1060184317">parentNode</a></td><td class="yes"></td></tr><tr>
|
||||
<td class="yes">NodeList <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1451460987">childNodes</a></td><td class="yes"></td></tr><tr>
|
||||
<td class="yes">Node <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-169727388">firstChild</a></td><td class="yes"></td></tr><tr>
|
||||
<td class="yes">Node <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-61AD09FB">lastChild</a></td><td class="yes"></td></tr><tr>
|
||||
<td class="yes">Node <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-640FB3C8">previousSibling</a></td><td class="yes"></td></tr><tr>
|
||||
<td class="yes">Node <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-6AC54C2F">nextSibling</a></td><td class="yes"></td></tr><tr>
|
||||
<td class="yes">NamedNodeMap <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-84CF096">attributes</a></td><td class="yes"></td></tr><tr>
|
||||
<td class="no">Document <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#node-ownerDoc">ownerDocument</a></td><td class="no"></td></tr><tr>
|
||||
<td class="no">Node <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-952280727">insertBefore</a>(in Node newChild, in Node refChild)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">Node <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-785887307">replaceChild</a>(in Node newChild, in Node oldChild)</td><td class="no"></td></tr><tr>
|
||||
<td class="yes">Node <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1734834066">removeChild</a>(in Node oldChild)</td><td class="yes"></td></tr><tr>
|
||||
<td class="yes">Node <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-184E7107">appendChild</a>(in Node newChild)</td><td class="yes"></td></tr><tr>
|
||||
<td class="yes">boolean <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-810594187">hasChildNodes</a>()</td><td class="yes"></td></tr><tr>
|
||||
<td class="no">Node cloneNode(in boolean deep)</td><td class="no"></td></tr><tr>
|
||||
<td class="yes">DOMString <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-NodeNSname">namespaceURI</a></td><td class="yes"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr id="Element"><td rowspan="10" class="partial"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-745549614">Element</a> : <a href="#Node">Node</a></td>
|
||||
<td class="yes">DOMString <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-104682815">tagName</a></td><td class="yes"></td></tr><tr>
|
||||
<td class="yes">DOMString <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-666EE0F9">getAttribute</a>(in DOMString name)</td><td class="yes"></td></tr><tr>
|
||||
<td class="yes">void <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-F68F082">setAttribute</a>(in DOMString name, in DOMString value)</td><td class="yes"></td></tr><tr>
|
||||
<td class="yes">void <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-6D6AC0F9">removeAttribute</a>(in DOMString name)</td><td class="yes"></td></tr><tr>
|
||||
<td class="no">Attr <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-217A91B8">getAttributeNode</a>(in DOMString name)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">Attr <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-887236154">setAttributeNode</a>(in Attr newAttr)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">Attr <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-D589198">removeAttributeNode</a>(in Attr oldAttr)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">NodeList <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1938918D">getElementsByTagName</a>(in DOMString name)</td><td class="no"></td></tr><tr>
|
||||
<td class="yes">boolean <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-ElHasAttr">hasAttribute</a>(in DOMString name)</td><td class="yes"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr id="Document"><td rowspan="13" class="partial"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#i-Document">Document</a> : <a href="#Node">Node</a></td>
|
||||
<td class="no">DocumentType doctype</td><td class="no"></td></tr><tr>
|
||||
<td class="no">DOMImplementation implementation</td><td class="no"></td></tr><tr>
|
||||
<td class="yes">Element <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-87CD092">documentElement</a></td><td class="yes"></td></tr><tr>
|
||||
<td class="no">Element <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-2141741547">createElement</a>(in DOMString tagName)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">DocumentFragment createDocumentFragment()</td><td class="no"></td></tr><tr>
|
||||
<td class="no"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1975348127">createTextNode</a>(in DOMString data)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">createComment(in DOMString data)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">createCDATASection(in DOMString data)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">createProcessingInstruction(in DOMString target, in DOMString data)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">Attr <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1084891198">createAttribute</a>(in DOMString name)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">EntityReference createEntityByReference(in DOMString name)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">NodeList <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-A6C9094">getElementsByTagName</a>(in DOMString tagName)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">Element <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-getElBId">getElementById</a>(in DOMString elementId)</td><td class="no"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr id="NodeList"><td rowspan="2" class="yes"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-536297177">NodeList</a></td>
|
||||
<td class="yes">Node <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-844377136">item</a>(in unsigned long index)</td><td class="yes"></td></tr><tr>
|
||||
<td class="yes">unsigned long <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-203510337">length</a></td><td class="yes"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr id="NamedNodeMap"><td rowspan="5" class="partial"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1780488922">NamedNodeMap</a></td>
|
||||
<td class="yes">Node <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1074577549">getNamedItem</a>(in DOMString name)</td><td class="yes"></td></tr><tr>
|
||||
<td class="no">Node <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1025163788">setNamedItem</a>(in Node arg)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">Node <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-D58B193">removeNamedItem</a>(in DOMString name)</td><td class="no"></td></tr><tr>
|
||||
<td class="yes">Node <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-349467F9">item</a>(in unsigned long index)</td><td class="yes"></td></tr><tr>
|
||||
<td class="yes">unsigned long <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-6D0FB19E">length</a></td><td class="yes"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr id="CharacterData"><td rowspan="7" class="partial"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-FF21A306">CharacterData</a> : <a href="#Node">Node</a></td>
|
||||
<td class="yes">DOMString <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-72AB8359">data</a></td><td class="yes"></td></tr><tr>
|
||||
<td class="no">unsigned long <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-7D61178C">length</a></td><td class="no"></td></tr><tr>
|
||||
<td class="no">DOMString substringData(in unsigned long offset, in unsigned long count)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">void appendData(in DOMString arg)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">void insertData(in unsigned long offset, in DOMString arg)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">void deleteData(in unsigned long offset, in unsigned long count)</td><td class="no"></td></tr><tr>
|
||||
<td class="no">void replaceData(in unsigned long offset, in unsigned long count, in DOMString arg)</td><td class="no"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr id="Text"><td rowspan="1" class="partial"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1312295772">Text</a> : <a href="#CharacterData">CharacterData</a></td>
|
||||
<td class="no">Text splitText(in unsigned long offset)</td><td class="no"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr id="Attr"><td rowspan="4" class="partial"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-637646024">Attr</a> : <a href="#Node">Node</a></td>
|
||||
<td class="yes">DOMString <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1112119403">name</a></td><td class="no"></td></tr><tr>
|
||||
<td class="no">boolean specified</td><td class="no"></td></tr><tr>
|
||||
<td class="yes">DOMString <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-221662474">value</a></td><td class="no"></td></tr><tr>
|
||||
<td class="no">Element <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#Attr-ownerElement">ownerElement</a></td><td class="no"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr><td rowspan="1" class="partial">Comment : CharacterData</td>
|
||||
<td class="no">(empty)</td><td class="no"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr><td rowspan="1" class="no">CDATASection : Text</td>
|
||||
<td class="no">(empty)</td><td class="no"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr><td rowspan="1" class="yes">DOMException</td>
|
||||
<td class="yes">unsigned short code</td><td class="yes"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr><td rowspan="1" class="no">DOMImplementation</td>
|
||||
<td class="no">boolean hasFeature(in DOMString feature, in DOMString version)</td><td class="no"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr><td rowspan="1" class="no">DocumentFragment</td>
|
||||
<td class="no">(empty)</td><td class="no"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr><td rowspan="3" class="partial">DocumentType : <a href="#Node">Node<a></td>
|
||||
<td class="no">DOMString name</td><td class="no"></td></tr><tr>
|
||||
<td class="no">NamedNodeMap entities</td><td class="no"></td></tr><tr>
|
||||
<td class="no">NamedNodeMap notations</td><td class="no"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr><td rowspan="2" class="no">Notation : <a href="#Node">Node</a></td>
|
||||
<td class="no">DOMString publicId</td><td class="no"></td></tr><tr>
|
||||
<td class="no">DOMString systemId</td><td class="no"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr><td rowspan="3" class="no">Entity : <a href="#Node">Node</a></td>
|
||||
<td class="no">DOMString publicId</td><td class="no"></td></tr><tr>
|
||||
<td class="no">DOMString systemId</td><td class="no"></td></tr><tr>
|
||||
<td class="no">DOMString notationName</td><td class="no"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr><td rowspan="1" class="no">EntityReference : <a href="#Node">Node<a/></td>
|
||||
<td class="no">(empty)</td><td class="no"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
<tr><td rowspan="2" class="no">ProcessingInstruction : <a href="#Node">Node</a></td>
|
||||
<td class="no">DOMString target</td><td class="no"></td></tr><tr>
|
||||
<td class="no">DOMString data</td><td class="no"></td></tr><tr>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
256
lite/pdom_test.html
Normal file
256
lite/pdom_test.html
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>pdom unit tests</title>
|
||||
<script src='pdom.js'></script>
|
||||
<style type='text/css'>
|
||||
progress {
|
||||
width: 600px;
|
||||
}
|
||||
</style>
|
||||
<script src='muther.js'></script>
|
||||
</head>
|
||||
<body></body>
|
||||
<script type='text/javascript'>
|
||||
muther.test([
|
||||
function testConstruction() {
|
||||
var parser = new pdom.DOMParser();
|
||||
muther.assert(parser, 'Could not construct parser');
|
||||
},
|
||||
|
||||
function testParseEmptyDoc() {
|
||||
var doc = new pdom.DOMParser().parseFromString('<?xml version="1.0"?><empty/>');
|
||||
muther.assert(doc, 'Could not parse doc');
|
||||
muther.assert(doc instanceof pdom.XMLDocument, 'parseFromString() did not return a pdom.XMLDocument');
|
||||
muther.assert(doc.childNodes.length == 1, 'Doc node had incorrect # of nodes: ' + doc.childNodes.length);
|
||||
muther.assert(doc.documentElement, 'Document had no documentElement');
|
||||
muther.assert(doc.documentElement instanceof pdom.Element, 'documentElement not a pdom.Element');
|
||||
muther.assert(doc.documentElement.tagName == 'empty', 'documentElement not an <empty/>');
|
||||
muther.assert(doc.documentElement.childNodes.length == 0, 'documentElement had child nodes');
|
||||
},
|
||||
|
||||
function testParseSimpleGetAttribute() {
|
||||
var doc = new pdom.DOMParser().parseFromString(
|
||||
'<?xml version="1.0"?><simple bar="foo" foo=\'bar\'' +
|
||||
' baz = " blah blah "' +
|
||||
'/>');
|
||||
|
||||
muther.assert(doc, 'Could not parse doc');
|
||||
muther.assert(doc.documentElement, 'Document had no documentElement');
|
||||
|
||||
var elem = doc.documentElement;
|
||||
muther.assert(elem.getAttribute('bar') == 'foo', 'bar attribute not correct');
|
||||
muther.assert(elem.getAttribute('foo') == 'bar', 'foo attribute not correct');
|
||||
muther.assert(elem.getAttribute('baz') == ' blah blah ', 'baz attribute not correct');
|
||||
},
|
||||
|
||||
function testNodeTypes() {
|
||||
var doc = new pdom.DOMParser().parseFromString('<simple foo="bar"><!-- Comment -->Text</simple>');
|
||||
muther.assert(doc.nodeType == 9, 'Document nodetype not 9');
|
||||
muther.assert(doc.documentElement.nodeType == 1, 'Document element not 1');
|
||||
muther.assert(doc.documentElement.attributes.item(0).nodeType == 2, 'Attribute nodeType not 2');
|
||||
muther.assert(doc.documentElement.childNodes.item(0).nodeType == 8, 'Comment nodetype not 8');
|
||||
muther.assert(doc.documentElement.childNodes.item(1).nodeType == 3, 'Text nodetype not 3');
|
||||
},
|
||||
|
||||
function testParentNode() {
|
||||
var doc = new pdom.DOMParser().parseFromString('<simple foo="bar">Text</simple>');
|
||||
muther.assert(doc.documentElement.parentNode == doc,
|
||||
'parentNode of documentElement not the document');
|
||||
muther.assert(doc.documentElement == doc.documentElement.childNodes.item(0).parentNode,
|
||||
'parentNode of text not the documentElement');
|
||||
muther.assert(doc.documentElement.attributes.item(0).parentNode == null,
|
||||
'parentNode of Attr is not null');
|
||||
},
|
||||
|
||||
function testConvenienceNodeProperties() {
|
||||
var doc = new pdom.DOMParser().parseFromString(
|
||||
'<parent><child1/><child2/><child3/></parent>');
|
||||
var parent = doc.documentElement;
|
||||
var child1 = parent.childNodes.item(0);
|
||||
var child2 = parent.childNodes.item(1);
|
||||
var child3 = parent.childNodes.item(2);
|
||||
|
||||
muther.assert(parent.firstChild === child1, 'firstChild did not work');
|
||||
muther.assert(parent.lastChild === child3, 'lastChild did not work');
|
||||
muther.assert(child2.previousSibling === child1, 'previousSibling did not work');
|
||||
muther.assert(child2.nextSibling === child3, 'nextSibling did not work');
|
||||
},
|
||||
|
||||
function testNamespaceless() {
|
||||
var doc = new pdom.DOMParser().parseFromString('<parent><child/></parent>');
|
||||
var parent = doc.documentElement;
|
||||
var child = parent.firstChild;
|
||||
muther.assert(parent.namespaceURI === null, 'parent namespaceURI did not return null');
|
||||
muther.assert(child.namespaceURI === null, 'child namespaceURI did not return null');
|
||||
},
|
||||
|
||||
function testDefaultNamespaceURI() {
|
||||
var doc = new pdom.DOMParser().parseFromString(
|
||||
'<parent xmlns="http://foo/"><child xmlns="http://bar/"><grandchild/></child></parent>');
|
||||
var parent = doc.documentElement;
|
||||
var child = parent.firstChild;
|
||||
var grandchild = child.firstChild;
|
||||
muther.assert(parent.namespaceURI === "http://foo/", 'parent namespaceURI was not correct');
|
||||
muther.assert(child.namespaceURI === "http://bar/", 'child namespaceURI was not correct');
|
||||
muther.assert(grandchild.namespaceURI === "http://bar/",
|
||||
'grandchild namespaceURI was not correct');
|
||||
},
|
||||
|
||||
function testPrefixedNamespaceURI() {
|
||||
var doc = new pdom.DOMParser().parseFromString(
|
||||
'<parent xmlns="http://foo/" xmlns:bar="http://bar/">' +
|
||||
'<child/><bar:child><grandchild/></bar:child></parent>');
|
||||
var parent = doc.documentElement;
|
||||
var firstChild = parent.firstChild;
|
||||
var secondChild = firstChild.nextSibling;
|
||||
var grandChild = secondChild.firstChild;
|
||||
|
||||
muther.assert(secondChild.namespaceURI === "http://bar/",
|
||||
'prefixed namespaceURI did not work');
|
||||
muther.assert(grandChild.namespaceURI === "http://bar/",
|
||||
'prefixed namespaceURI did not work');
|
||||
},
|
||||
|
||||
function testTagName() {
|
||||
var doc = new pdom.DOMParser().parseFromString('<simple/>');
|
||||
muther.assert(doc.documentElement.tagName == 'simple',
|
||||
'tagName was not "simple"');
|
||||
},
|
||||
|
||||
function testHasChildNodes() {
|
||||
var doc = new pdom.DOMParser().parseFromString('<parent><child/></parent>');
|
||||
muther.assert(doc.documentElement.hasChildNodes(), 'documentElement had no child nodes');
|
||||
muther.assert(!doc.documentElement.childNodes.item(0).hasChildNodes(),
|
||||
'child-less element had child nodes');
|
||||
},
|
||||
|
||||
function testRemoveChild() {
|
||||
var doc = new pdom.DOMParser().parseFromString('<parent><child/></parent>');
|
||||
var root = doc.documentElement;
|
||||
var child = root.childNodes.item(0);
|
||||
var retValue = root.removeChild(child);
|
||||
muther.assert(!root.hasChildNodes(), 'Parent still has children');
|
||||
muther.assert(child == retValue, 'removeChild did not return the removed child');
|
||||
muther.assert(!child.parentNode, 'Removed child still has a parent');
|
||||
|
||||
try {
|
||||
root.removeChild(child);
|
||||
muther.assert(false, 'removeChild() did not throw an exception');
|
||||
} catch(e) {
|
||||
muther.assert(e.code == 8, 'DOMException not thrown with code 8');
|
||||
}
|
||||
},
|
||||
|
||||
function testAppendChild() {
|
||||
var doc = new pdom.DOMParser().parseFromString('<parent><child1/><child2/><child3/></parent>');
|
||||
var root = doc.documentElement;
|
||||
var child1 = root.childNodes.item(0);
|
||||
var child2 = root.childNodes.item(1);
|
||||
|
||||
var retValue = root.appendChild(child1);
|
||||
muther.assert(child1 === retValue, 'appendChild did not return the appended child');
|
||||
muther.assert(root.firstChild === child2, 'appendChild did not remove the appended child');
|
||||
muther.assert(root.lastChild === child1, 'appendChild did not append the child');
|
||||
|
||||
retValue = child1.appendChild(child2);
|
||||
muther.assert(root.childNodes.length == 2, 'root did not have 2 children');
|
||||
muther.assert(child1.hasChildNodes(), 'child1 did not have any child nodes');
|
||||
muther.assert(child1.firstChild == child2, 'child1\'s child is not child2');;
|
||||
},
|
||||
|
||||
function testGetAttribute() {
|
||||
var doc = new pdom.DOMParser().parseFromString('<parent foo="bar"></parent>');
|
||||
var root = doc.documentElement;
|
||||
muther.assert(root.getAttribute('foo') == 'bar', 'Element did not have a foo attribute');
|
||||
muther.assert(root.getAttribute('blah') == '', 'getAttribute("blah") did not return an empty string');
|
||||
},
|
||||
|
||||
function testRemoveAttribute() {
|
||||
var doc = new pdom.DOMParser().parseFromString('<parent foo="bar" baz="blah"></parent>');
|
||||
var root = doc.documentElement;
|
||||
var attrMap = root.attributes;
|
||||
|
||||
root.removeAttribute('baz');
|
||||
|
||||
muther.assert(root.getAttribute('baz') == '', 'Element still has a baz attribute');
|
||||
muther.assert(root.getAttribute('foo') == 'bar', 'Element does not have a foo attribute');
|
||||
// Also tests liveness of the NamedNodeMap.
|
||||
muther.assert(attrMap.length == 1, 'attributes NamedNodeMap was not updated after a removeAttribute');
|
||||
},
|
||||
|
||||
function testSetAttribute() {
|
||||
var doc = new pdom.DOMParser().parseFromString('<parent foo="bar"></parent>');
|
||||
var root = doc.documentElement;
|
||||
var attrMap = root.attributes;
|
||||
|
||||
root.setAttribute('foo', 'baz');
|
||||
root.setAttribute('blah', 'boo');
|
||||
|
||||
muther.assert(attrMap.length == 2, 'attributes NamedNodeMap was not updated after a setAttribute');
|
||||
muther.assert(root.getAttribute('foo') == 'baz', 'Foo attribute value not updated after a setAttribute');
|
||||
muther.assert(root.getAttribute('blah') == 'boo', 'Blah attribute value not updated after a setAttribute');
|
||||
},
|
||||
|
||||
function testHasAttribute() {
|
||||
var doc = new pdom.DOMParser().parseFromString('<parent foo="bar"></parent>');
|
||||
var root = doc.documentElement;
|
||||
var attrMap = root.attributes;
|
||||
|
||||
muther.assert(root.hasAttribute('foo'), 'hasAttribute() did not work for parsed attribute');
|
||||
muther.assert(!root.hasAttribute('blah'), 'hasAttribute() returned true for unknown attribute');
|
||||
|
||||
root.setAttribute('foo', 'baz');
|
||||
root.setAttribute('blah', 'boo');
|
||||
muther.assert(root.hasAttribute('foo'), 'hasAttribute() did not work for a set attribute');
|
||||
muther.assert(root.hasAttribute('blah'), 'hasAttribute() returned false for a set attribute');
|
||||
|
||||
root.removeAttribute('foo');
|
||||
muther.assert(!root.hasAttribute('foo'), 'hasAttribute() return true for a removed attribute');
|
||||
},
|
||||
|
||||
function testParseAttributes() {
|
||||
var parser = new pdom.DOMParser();
|
||||
var doc = parser.parseFromString('<simple bar="baz" foo="blah"/>');
|
||||
|
||||
muther.assert(doc, 'Could not parse doc');
|
||||
muther.assert(doc.documentElement, 'Document had no documentElement');
|
||||
|
||||
var elem = doc.documentElement;
|
||||
var attrMap = elem.attributes;
|
||||
muther.assert(attrMap, 'Could not get NamedNodeMap for attributes');
|
||||
muther.assert(attrMap.length == 2, 'Attribute map did not have two items');
|
||||
|
||||
muther.assert(attrMap.item(0) instanceof pdom.Node, 'item(0) did not return a Node');
|
||||
muther.assert(attrMap.item(1) instanceof pdom.Node, 'item(1) did not return a Node');
|
||||
muther.assert(attrMap.item(0).name == 'foo' || attrMap.item(0).name == 'bar',
|
||||
'Unknown node returned from map');
|
||||
|
||||
var fooAttr = attrMap.getNamedItem('foo');
|
||||
muther.assert(fooAttr instanceof pdom.Attr, 'foo attribute was not an Attr node');
|
||||
muther.assert(fooAttr.name == 'foo', 'foo attribute did not have name of "foo"');
|
||||
muther.assert(fooAttr.value == 'blah', 'foo attribute did not have value of "blah"');
|
||||
|
||||
var barAttr = attrMap.getNamedItem('bar');
|
||||
muther.assert(barAttr instanceof pdom.Attr, 'bar attribute was not an Attr node');
|
||||
muther.assert(barAttr.name == 'bar', 'bar attribute did not have name of "bar"');
|
||||
muther.assert(barAttr.value == 'baz', 'bar attribute did not have value of "baz"');
|
||||
|
||||
barAttr.value = 'fungus';
|
||||
muther.assert(attrMap.getNamedItem('bar').value == 'fungus',
|
||||
'Mutating Attr node value did not update the node in NamedNodeMap');
|
||||
},
|
||||
|
||||
function testSerializerRoundtripSimple() {
|
||||
var parser = new pdom.DOMParser();
|
||||
var xmlText = '<simple foo="bar">blah</simple>';
|
||||
var doc = parser.parseFromString(xmlText, 'text/xml');
|
||||
var serializer = new pdom.XMLSerializer();
|
||||
var serializedText = serializer.serializeToString(doc);
|
||||
muther.assert(serializedText == xmlText,
|
||||
('Serializing empty doc failed. Expected: ' + xmlText +
|
||||
' Actual: ' + serializedText));
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
</html>
|
||||
84
lite/scour.js
Normal file
84
lite/scour.js
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* Scour Lite (the JS version)
|
||||
*
|
||||
* Copyright(c) 2011 Google Inc.
|
||||
*/
|
||||
|
||||
importScripts('pdom.js');
|
||||
|
||||
onmessage = function(evt) {
|
||||
// Now evt.data contains the text of the SVG file.
|
||||
postMessage({
|
||||
progress: {loaded: 100, total: 100},
|
||||
scouredSvg: scourString(evt.data)
|
||||
});
|
||||
};
|
||||
|
||||
var NS = {
|
||||
'SVG': 'http://www.w3.org/2000/svg',
|
||||
'XLINK': 'http://www.w3.org/1999/xlink',
|
||||
'SODIPODI': 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd',
|
||||
'INKSCAPE': 'http://www.inkscape.org/namespaces/inkscape',
|
||||
'ADOBE_ILLUSTRATOR': 'http://ns.adobe.com/AdobeIllustrator/10.0/',
|
||||
'ADOBE_GRAPHS': 'http://ns.adobe.com/Graphs/1.0/',
|
||||
'ADOBE_SVG_VIEWER': 'http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/',
|
||||
'ADOBE_VARIABLES': 'http://ns.adobe.com/Variables/1.0/',
|
||||
'ADOBE_SFW': 'http://ns.adobe.com/SaveForWeb/1.0/',
|
||||
'ADOBE_EXTENSIBILITY': 'http://ns.adobe.com/Extensibility/1.0/',
|
||||
'ADOBE_FLOWS': 'http://ns.adobe.com/Flows/1.0/',
|
||||
'ADOBE_IMAGE_REPLACEMENT': 'http://ns.adobe.com/ImageReplacement/1.0/',
|
||||
'ADOBE_CUSTOM': 'http://ns.adobe.com/GenericCustomNamespace/1.0/',
|
||||
'ADOBE_XPATH': 'http://ns.adobe.com/XPath/1.0/'
|
||||
};
|
||||
|
||||
var unwanted_ns = [ NS['SODIPODI'], NS['INKSCAPE'], NS['ADOBE_ILLUSTRATOR'],
|
||||
NS['ADOBE_GRAPHS'], NS['ADOBE_SVG_VIEWER'], NS['ADOBE_VARIABLES'],
|
||||
NS['ADOBE_SFW'], NS['ADOBE_EXTENSIBILITY'], NS['ADOBE_FLOWS'],
|
||||
NS['ADOBE_IMAGE_REPLACEMENT'], NS['ADOBE_CUSTOM'], NS['ADOBE_XPATH'] ];
|
||||
|
||||
/**
|
||||
* @param {pdom.Node|Node} node The parent node.
|
||||
* @param {Array.<string>} namespaces An array of namespace URIs.
|
||||
*/
|
||||
var removeNamespacedElements = function(node, namespaces) {
|
||||
if (node.nodeType == 1) {
|
||||
// Remove all namespace'd child nodes from this element.
|
||||
var childrenToRemove = [];
|
||||
for (var i = 0; i < node.childNodes.length; ++i) {
|
||||
var child = node.childNodes.item(i);
|
||||
if (namespaces.indexOf(child.namespaceURI) != -1) {
|
||||
childrenToRemove.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < childrenToRemove.length; ++i) {
|
||||
node.removeChild(childrenToRemove[i]);
|
||||
}
|
||||
|
||||
// Now recurse for children.
|
||||
for (var i = 0; i < node.childNodes.length; ++i) {
|
||||
removeNamespacedElements(node.childNodes.item(i), namespaces);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} in_string The SVG document as a string.
|
||||
* @param {object} opt_options An optional set of options.
|
||||
*/
|
||||
var scourString = function(in_string, opt_options) {
|
||||
postMessage({progress: {loaded: 0, total: 100}});
|
||||
|
||||
var parser = new pdom.DOMParser();
|
||||
var options = opt_options || {};
|
||||
var doc = parser.parseFromString(in_string, 'text/xml');
|
||||
|
||||
// Remove editor stuff.
|
||||
if (!options.keep_editor_data) {
|
||||
removeNamespacedElements(doc.documentElement, unwanted_ns);
|
||||
postMessage({message: 'Removed namespaced elements'});
|
||||
}
|
||||
|
||||
return new pdom.XMLSerializer().serializeToString(doc);
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue