/*
* env.rhino.js
*/
var __env__ = {};
(function($env){
//You can emulate different user agents by overriding these after loading env
$env.appCodeName = "EnvJS";//eg "Mozilla"
$env.appName = "Resig/20070309 BirdDog/0.0.0.1";//eg "Gecko/20070309 Firefox/2.0.0.3"
//set this to true and see profile/profile.js to select which methods
//to profile
$env.profile = false;
$env.log = function(msg, level){
print(' '+ (level?level:'LOG') + ':\t['+ new Date()+"] {ENVJS} "+msg);
};
$env.debug = function(){};
$env.info = function(){};
$env.warn = function(){};
$env.error = function(){};
//uncomment these if you want to get some internal log statementes
/*$env.debug = function(msg){
$env.log(msg,"DEBUG");
};
$env.info = function(msg){
$env.log(msg,"INFO");
};*/
$env.warn = function(msg){
$env.log(msg,"WARNIING");
};
$env.error = function(msg, e){
$env.log(msg+ " Line: "+ $env.lineSource(e),'ERROR');
$env.log(e||"",'ERROR');
};
$env.info("Initializing Rhino Platform Env");
$env.lineSource = function(e){
return e&&e.rhinoException?e.rhinoException.lineSource():"(line ?)";
};
$env.hashCode = function(obj){
return obj?obj.hashCode().toString()+'':null;
};
//For Java the window.location object is a java.net.URL
$env.location = function(path, base){
var protocol = new RegExp('(^file\:|^http\:|^https\:)');
var m = protocol.exec(path);
if(m&&m.length>1){
return new java.net.URL(path).toString()+'';
}else if(base){
return new java.net.URL(new java.net.URL(base), path).toString()+'';
}else{
//return an absolute url from a url relative to the window location
if(window.location.href.length > 0){
base = window.location.href.substring(0, window.location.href.lastIndexOf('/'));
return base + '/' + path;
}else{
return new java.io.File( path ).toURL().toString()+'';
}
}
};
//For Java the window.timer is created using the java.lang.Thread in combination
//with the java.lang.Runnable
$env.timer = function(fn, time){
//$env.debug("wating for timer "+time);
return new java.lang.Thread(new java.lang.Runnable({
run: function(){
while (true){
java.lang.Thread.currentThread().sleep(time);
//$env.debug("calling in timer "+time);
fn();
}
}
}));
};
//Since we're running in rhino I guess we can safely assume
//java is 'enabled'. I'm sure this requires more thought
//than I've given it here
$env.javaEnabled = true;
//Used in the XMLHttpRquest implementation to run a
// request in a seperate thread
$env.runAsync = function(fn){
$env.debug("running async");
(new java.lang.Thread(new java.lang.Runnable({
run: fn
}))).start();
};
//Used to write to a local file
$env.writeToFile = function(text, url){
$env.debug("writing text to url : " + url);
var out = new java.io.FileWriter(
new java.io.File(
new java.net.URI(url.toString())));
out.write( text, 0, text.length );
out.flush();
out.close();
};
//Used to write to a local file
$env.writeToTempFile = function(text, suffix){
$env.debug("writing text to temp url : " + suffix);
// Create temp file.
var temp = java.io.File.createTempFile("envjs-tmp", suffix);
// Delete temp file when program exits.
temp.deleteOnExit();
// Write to temp file
var out = new java.io.FileWriter(temp);
out.write(text, 0, text.length);
out.close();
return temp.getAbsolutePath().toString()+'';
};
//Used to delete a local file
$env.deleteFile = function(url){
var file = new java.io.File( new java.net.URI( url ) );
file["delete"]();
};
$env.connection = function(xhr, responseHandler){
var url = java.net.URL(xhr.url);//, $w.location);
var connection;
if ( /^file\:/.test(url) ) {
if ( xhr.method == "PUT" ) {
var text = data || "" ;
$env.writeToFile(text, url);
} else if ( xhr.method == "DELETE" ) {
$env.deleteFile(url);
} else {
connection = url.openConnection();
connection.connect();
}
} else {
connection = url.openConnection();
connection.setRequestMethod( xhr.method );
// Add headers to Java connection
for (var header in xhr.headers){
connection.addRequestProperty(header+'', xhr.headers[header]+'');
}connection.connect();
// Stick the response headers into responseHeaders
for (var i = 0; ; i++) {
var headerName = connection.getHeaderFieldKey(i);
var headerValue = connection.getHeaderField(i);
if (!headerName && !headerValue) break;
if (headerName)
xhr.responseHeaders[headerName+''] = headerValue+'';
}
}
if(connection){
xhr.readyState = 4;
xhr.status = parseInt(connection.responseCode,10) || undefined;
xhr.statusText = connection.responseMessage || "";
var contentEncoding = connection.getContentEncoding() || "utf-8",
stream = (contentEncoding.equalsIgnoreCase("gzip") || contentEncoding.equalsIgnoreCase("decompress") )?
new java.util.zip.GZIPInputStream(connection.getInputStream()) :
connection.getInputStream(),
baos = new java.io.ByteArrayOutputStream(),
buffer = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 1024),
length,
responseXML = null;
while ((length = stream.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
baos.close();
stream.close();
xhr.responseText = java.nio.charset.Charset.forName("UTF-8").
decode(java.nio.ByteBuffer.wrap(baos.toByteArray())).toString()+"";
}
if(responseHandler){
responseHandler();
}
};
var htmlDocBuilder = Packages.javax.xml.parsers.DocumentBuilderFactory.newInstance();
htmlDocBuilder.setNamespaceAware(false);
htmlDocBuilder.setValidating(false);
$env.parseHTML = function(htmlstring){
return htmlDocBuilder.newDocumentBuilder().parse(
new java.io.ByteArrayInputStream(
(new java.lang.String(htmlstring)).getBytes("UTF8")))+"";
};
var xmlDocBuilder = Packages.javax.xml.parsers.DocumentBuilderFactory.newInstance();
xmlDocBuilder.setNamespaceAware(true);
xmlDocBuilder.setValidating(true);
$env.parseXML = function(xmlstring){
return xmlDocBuilder.newDocumentBuilder().parse(
new java.io.ByteArrayInputStream(
(new java.lang.String(xmlstring)).getBytes("UTF8")))+"";
};
$env.xpath = function(expression, doc){
return Packages.javax.xml.xpath.
XPathFactory.newInstance().newXPath().
evaluate(expression, doc, javax.xml.xpath.XPathConstants.NODESET);
};
$env.tmpdir = java.lang.System.getProperty("java.io.tmpdir");
$env.os_name = java.lang.System.getProperty("os.name");
$env.os_arch = java.lang.System.getProperty("os.arch");
$env.os_version = java.lang.System.getProperty("os.version");
$env.lang = java.lang.System.getProperty("user.lang");
$env.platform = "Rhino ";//how do we get the version
$env.safeScript = function(){
//do nothing
};
$env.scriptTypes = {
"text/javascript" :false,
"text/envjs" :true
};
$env.loadLocalScript = function(script, parser){
$env.debug("loading script ");
var types, type, src, i, base,
docWrites = [],
write = document.write,
writeln = document.writeln;
//temporarily replace document write becuase the function
//has a different meaning during parsing
document.write = function(text){
docWrites.push(text);
};
try{
if(script.type){
types = script.type?script.type.split(";"):[];
for(i=0;i
* Copyright 2008 John Resig, under the MIT License
*/
// The Window Object
var __this__ = this;
this.__defineGetter__('window', function(){
return __this__;
});
try{
(function($w, $env, $policy){
/*
* window.js
* - this file will be wrapped in a closure providing the window object as $w
*/
// a logger or empty function available to all modules.
var $log = $env.log,
$debug = $env.debug,
$info = $env.info,
$warn = $env.warn,
$error = $env.error;
//The version of this application
var $version = "0.1";
//This should be hooked to git or svn or whatever
var $revision = "0.0.0.0";
//These descriptions of window properties are taken loosely David Flanagan's
//'JavaScript - The Definitive Guide' (O'Reilly)
/**> $cookies - see cookie.js <*/
// read only boolean specifies whether the window has been closed
var $closed = false;
// a read/write string that specifies the default message that appears in the status line
var $defaultStatus = "Done";
// a read-only reference to the Document object belonging to this window
/**> $document - See document.js <*/
//IE only, refers to the most recent event object - this maybe be removed after review
var $event = null;
//A read-only array of window objects
var $frames = [];
// a read-only reference to the History object
/**> $history - see location.js <**/
// read-only properties that specify the height and width, in pixels
var $innerHeight = 600, $innerWidth = 800;
// a read-only reference to the Location object. the location object does expose read/write properties
/**> $location - see location.js <**/
// a read only property specifying the name of the window. Can be set when using open()
// and may be used when specifying the target attribute of links
var $name = 'Resig Env Browser';
// a read-only reference to the Navigator object
/**> $navigator - see navigator.js <**/
// a read/write reference to the Window object that contained the script that called open() to
//open this browser window. This property is valid only for top-level window objects.
var $opener;
// Read-only properties that specify the total height and width, in pixels, of the browser window.
// These dimensions include the height and width of the menu bar, toolbars, scrollbars, window
// borders and so on. These properties are not supported by IE and IE offers no alternative
// properties;
var $outerHeight = $innerHeight, $outerWidth = $innerWidth;
// Read-only properties that specify the number of pixels that the current document has been scrolled
//to the right and down. These are not supported by IE.
var $pageXOffset = 0, $pageYOffset = 0;
//A read-only reference to the Window object that contains this window or frame. If the window is
// a top-level window, parent refers to the window itself. If this window is a frame, this property
// refers to the window or frame that conatins it.
var $parent;
// a read-only refernce to the Screen object that specifies information about the screen:
// the number of available pixels and the number of available colors.
/**> $screen - see screen.js <**/
// read only properties that specify the coordinates of the upper-left corner of the screen.
var $screenX = 0, $screenY = 0;
var $screenLeft = $screenX, $screenTop = $screenY;
// a read-only refernce to this window itself.
var $self;
// a read/write string that specifies the current contents of the status line.
var $status = '';
// a read-only reference to the top-level window that contains this window. If this
// window is a top-level window it is simply a refernce to itself. If this window
// is a frame, the top property refers to the top-level window that contains the frame.
var $top;
// the window property is identical to the self property.
var $window = $w;
$debug("Initializing Window.");
__extend__($w,{
get closed(){return $closed;},
get defaultStatus(){return $defaultStatus;},
set defaultStatus(_defaultStatus){$defaultStatus = _defaultStatus;},
//get document(){return $document;}, - see document.js
get event(){return $event;},
get frames(){return $frames;},
//get history(){return $history;}, - see location.js
get innerHeight(){return $innerHeight;},
get innerWidth(){return $innerWidth;},
get clientHeight(){return $innerHeight;},
get clientWidth(){return $innerWidth;},
//get location(){return $location;}, see location.js
get name(){return $name;},
//get navigator(){return $navigator;}, see navigator.js
get opener(){return $opener;},
get outerHeight(){return $outerHeight;},
get outerWidth(){return $outerWidth;},
get pageXOffest(){return $pageXOffset;},
get pageYOffset(){return $pageYOffset;},
get parent(){return $parent;},
//get screen(){return $screen;}, see screen.js
get screenLeft(){return $screenLeft;},
get screenTop(){return $screenTop;},
get screenX(){return $screenX;},
get screenY(){return $screenY;},
get self(){return $self;},
get status(){return $status;},
set status(_status){$status = _status;},
get top(){return $top || $window;},
get window(){return $window;}
});
$w.open = function(url, name, features, replace){
//TODO
};
$w.close = function(){
//TODO
};
/* Time related functions - see timer.js
* - clearTimeout
* - clearInterval
* - setTimeout
* - setInterval
*/
/*
* Events related functions - see event.js
* - addEventListener
* - attachEvent
* - detachEvent
* - removeEventListener
*
* These functions are identical to the Element equivalents.
*/
/*
* UIEvents related functions - see uievent.js
* - blur
* - focus
*
* These functions are identical to the Element equivalents.
*/
/* Dialog related functions - see dialog.js
* - alert
* - confirm
* - prompt
*/
/* Screen related functions - see screen.js
* - moveBy
* - moveTo
* - print
* - resizeBy
* - resizeTo
* - scrollBy
* - scrollTo
*/
/* CSS related functions - see css.js
* - getComputedStyle
*/
/*
* Shared utility methods
*/
// Helper method for extending one object with another.
function __extend__(a,b) {
for ( var i in b ) {
var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);
if ( g || s ) {
if ( g ) a.__defineGetter__(i, g);
if ( s ) a.__defineSetter__(i, s);
} else
a[i] = b[i];
} return a;
};
// from ariel flesler http://flesler.blogspot.com/2008/11/fast-trim-function-for-javascript.html
// this might be a good utility function to provide in the env.core
// as in might be useful to the parser and other areas as well
function trim( str ){
return (str || "").replace( /^\s+|\s+$/g, "" );
};
/*function trim( str ){
var start = -1,
end = str.length;
/*jsl:ignore*
while( str.charCodeAt(--end) < 33 );
while( str.charCodeAt(++start) < 33 );
/*jsl:end*
return str.slice( start, end + 1 );
};*/
//from jQuery
function __setArray__( target, array ) {
// Resetting the length to 0, then using the native Array push
// is a super-fast way to populate an object with array-like properties
target.length = 0;
Array.prototype.push.apply( target, array );
};
$debug("Defining NodeList");
/*
* NodeList - DOM Level 2
*/
$w.__defineGetter__('NodeList', function(){
return function(){
throw new Error("Object cannot be created in this context");
};
});
/**
* @class DOMNodeList - provides the abstraction of an ordered collection of nodes
*
* @author Jon van Noort (jon@webarcana.com.au)
*
* @param ownerDocument : DOMDocument - the ownerDocument
* @param parentNode : DOMNode - the node that the DOMNodeList is attached to (or null)
*/
var DOMNodeList = function(ownerDocument, parentNode) {
this.length = 0;
this.parentNode = parentNode;
this.ownerDocument = ownerDocument;
this._readonly = false;
__setArray__(this, []);
};
__extend__(DOMNodeList.prototype, {
item : function(index) {
var ret = null;
//$log("NodeList item("+index+") = " + this[index]);
if ((index >= 0) && (index < this.length)) { // bounds check
ret = this[index]; // return selected Node
}
return ret; // if the index is out of bounds, default value null is returned
},
get xml() {
var ret = "";
// create string containing the concatenation of the string values of each child
for (var i=0; i < this.length; i++) {
if(this[i]){
if(this[i].nodeType == DOMNode.TEXT_NODE && i>0 && this[i-1].nodeType == DOMNode.TEXT_NODE){
//add a single space between adjacent text nodes
ret += " "+this[i].xml;
}else{
ret += this[i].xml;
}
}
}
return ret;
},
toArray: function () {
var children = [];
for ( var i=0; i < this.length; i++) {
children.push (this[i]);
}
return children;
},
toString: function(){
return "[ "+(this.length > 0?Array.prototype.join.apply(this, [", "]):"Empty NodeList")+" ]";
}
});
/**
* @method DOMNodeList._findItemIndex - find the item index of the node with the specified internal id
* @author Jon van Noort (jon@webarcana.com.au)
* @param id : int - unique internal id
* @return : int
*/
var __findItemIndex__ = function (nodelist, id) {
var ret = -1;
// test that id is valid
if (id > -1) {
for (var i=0; i= 0) && (refChildIndex < nodelist.length)) { // bounds check
if (newChild.nodeType == DOMNode.DOCUMENT_FRAGMENT_NODE) { // node is a DocumentFragment
// append the children of DocumentFragment
Array.prototype.splice.apply(nodelist,[refChildIndex, 0].concat(newChild.childNodes.toArray()));
}
else {
// append the newChild
Array.prototype.splice.apply(nodelist,[refChildIndex, 0, newChild]);
}
}
};
/**
* @method DOMNodeList._replaceChild - replace the specified Node in the NodeList at the specified index
* Used by DOMNode.replaceChild(). Note: DOMNode.replaceChild() is responsible for Node Pointer surgery
* DOMNodeList._replaceChild() simply modifies the internal data structure (Array).
*
* @author Jon van Noort (jon@webarcana.com.au)
* @param newChild : DOMNode - the Node to be inserted
* @param refChildIndex : int - the array index to hold the Node
*/
var __replaceChild__ = function(nodelist, newChild, refChildIndex) {
var ret = null;
if ((refChildIndex >= 0) && (refChildIndex < nodelist.length)) { // bounds check
ret = nodelist[refChildIndex]; // preserve old child for return
if (newChild.nodeType == DOMNode.DOCUMENT_FRAGMENT_NODE) { // node is a DocumentFragment
// get array containing children prior to refChild
Array.prototype.splice.apply(nodelist,[refChildIndex, 1].concat(newChild.childNodes.toArray()));
}
else {
// simply replace node in array (links between Nodes are made at higher level)
nodelist[refChildIndex] = newChild;
}
}
return ret; // return replaced node
};
/**
* @method DOMNodeList._removeChild - remove the specified Node in the NodeList at the specified index
* Used by DOMNode.removeChild(). Note: DOMNode.removeChild() is responsible for Node Pointer surgery
* DOMNodeList._replaceChild() simply modifies the internal data structure (Array).
*
* @author Jon van Noort (jon@webarcana.com.au)
* @param refChildIndex : int - the array index holding the Node to be removed
*/
var __removeChild__ = function(nodelist, refChildIndex) {
var ret = null;
if (refChildIndex > -1) { // found it!
ret = nodelist[refChildIndex]; // return removed node
// rebuild array without removed child
Array.prototype.splice.apply(nodelist,[refChildIndex, 1]);
}
return ret; // return removed node
};
/**
* @method DOMNodeList._appendChild - append the specified Node to the NodeList
* Used by DOMNode.appendChild(). Note: DOMNode.appendChild() is responsible for Node Pointer surgery
* DOMNodeList._appendChild() simply modifies the internal data structure (Array).
*
* @author Jon van Noort (jon@webarcana.com.au)
* @param newChild : DOMNode - the Node to be inserted
*/
var __appendChild__ = function(nodelist, newChild) {
if (newChild.nodeType == DOMNode.DOCUMENT_FRAGMENT_NODE) { // node is a DocumentFragment
// append the children of DocumentFragment
Array.prototype.push.apply(nodelist, newChild.childNodes.toArray() );
} else {
// simply add node to array (links between Nodes are made at higher level)
Array.prototype.push.apply(nodelist, [newChild]);
}
};
/**
* @method DOMNodeList._cloneNodes - Returns a NodeList containing clones of the Nodes in this NodeList
*
* @author Jon van Noort (jon@webarcana.com.au)
* @param deep : boolean - If true, recursively clone the subtree under each of the nodes;
* if false, clone only the nodes themselves (and their attributes, if it is an Element).
* @param parentNode : DOMNode - the new parent of the cloned NodeList
* @return : DOMNodeList - NodeList containing clones of the Nodes in this NodeList
*/
var __cloneNodes__ = function(nodelist, deep, parentNode) {
var cloneNodeList = new DOMNodeList(nodelist.ownerDocument, parentNode);
// create list containing clones of each child
for (var i=0; i < nodelist.length; i++) {
__appendChild__(cloneNodeList, nodelist[i].cloneNode(deep));
}
return cloneNodeList;
};
/**
* @class DOMNamedNodeMap - used to represent collections of nodes that can be accessed by name
* typically a set of Element attributes
*
* @extends DOMNodeList - note W3C spec says that this is not the case,
* but we need an item() method identicle to DOMNodeList's, so why not?
* @author Jon van Noort (jon@webarcana.com.au)
* @param ownerDocument : DOMDocument - the ownerDocument
* @param parentNode : DOMNode - the node that the DOMNamedNodeMap is attached to (or null)
*/
var DOMNamedNodeMap = function(ownerDocument, parentNode) {
//$log("\t\tcreating dom namednodemap");
this.DOMNodeList = DOMNodeList;
this.DOMNodeList(ownerDocument, parentNode);
__setArray__(this, []);
};
DOMNamedNodeMap.prototype = new DOMNodeList;
__extend__(DOMNamedNodeMap.prototype, {
getNamedItem : function(name) {
var ret = null;
// test that Named Node exists
var itemIndex = __findNamedItemIndex__(this, name);
if (itemIndex > -1) { // found it!
ret = this[itemIndex]; // return NamedNode
}
return ret; // if node is not found, default value null is returned
},
setNamedItem : function(arg) {
// test for exceptions
if (__ownerDocument__(this).implementation.errorChecking) {
// throw Exception if arg was not created by this Document
if (this.ownerDocument != arg.ownerDocument) {
throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR));
}
// throw Exception if DOMNamedNodeMap is readonly
if (this._readonly || (this.parentNode && this.parentNode._readonly)) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// throw Exception if arg is already an attribute of another Element object
if (arg.ownerElement && (arg.ownerElement != this.parentNode)) {
throw(new DOMException(DOMException.INUSE_ATTRIBUTE_ERR));
}
}
// get item index
var itemIndex = __findNamedItemIndex__(this, arg.name);
var ret = null;
if (itemIndex > -1) { // found it!
ret = this[itemIndex]; // use existing Attribute
// throw Exception if DOMAttr is readonly
if (__ownerDocument__(this).implementation.errorChecking && ret._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
} else {
this[itemIndex] = arg; // over-write existing NamedNode
this[arg.name] = arg;
}
} else {
// add new NamedNode
Array.prototype.push.apply(this, [arg]);
this[arg.name] = arg;
}
arg.ownerElement = this.parentNode; // update ownerElement
return ret; // return old node or null
},
removeNamedItem : function(name) {
var ret = null;
// test for exceptions
// throw Exception if DOMNamedNodeMap is readonly
if (__ownerDocument__(this).implementation.errorChecking &&
(this._readonly || (this.parentNode && this.parentNode._readonly))) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// get item index
var itemIndex = __findNamedItemIndex__(this, name);
// throw Exception if there is no node named name in this map
if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) {
throw(new DOMException(DOMException.NOT_FOUND_ERR));
}
// get Node
var oldNode = this[itemIndex];
//this[oldNode.name] = undefined;
// throw Exception if Node is readonly
if (__ownerDocument__(this).implementation.errorChecking && oldNode._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// return removed node
return __removeChild__(this, itemIndex);
},
getNamedItemNS : function(namespaceURI, localName) {
var ret = null;
// test that Named Node exists
var itemIndex = __findNamedItemNSIndex__(this, namespaceURI, localName);
if (itemIndex > -1) { // found it!
ret = this[itemIndex]; // return NamedNode
}
return ret; // if node is not found, default value null is returned
},
setNamedItemNS : function(arg) {
// test for exceptions
if (__ownerDocument__(this).implementation.errorChecking) {
// throw Exception if DOMNamedNodeMap is readonly
if (this._readonly || (this.parentNode && this.parentNode._readonly)) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// throw Exception if arg was not created by this Document
if (__ownerDocument__(this) != __ownerDocument__(arg)) {
throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR));
}
// throw Exception if arg is already an attribute of another Element object
if (arg.ownerElement && (arg.ownerElement != this.parentNode)) {
throw(new DOMException(DOMException.INUSE_ATTRIBUTE_ERR));
}
}
// get item index
var itemIndex = __findNamedItemNSIndex__(this, arg.namespaceURI, arg.localName);
var ret = null;
if (itemIndex > -1) { // found it!
ret = this[itemIndex]; // use existing Attribute
// throw Exception if DOMAttr is readonly
if (__ownerDocument__(this).implementation.errorChecking && ret._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
} else {
this[itemIndex] = arg; // over-write existing NamedNode
}
}else {
// add new NamedNode
Array.prototype.push.apply(this, [arg]);
}
arg.ownerElement = this.parentNode;
return ret; // return old node or null
},
removeNamedItemNS : function(namespaceURI, localName) {
var ret = null;
// test for exceptions
// throw Exception if DOMNamedNodeMap is readonly
if (__ownerDocument__(this).implementation.errorChecking && (this._readonly || (this.parentNode && this.parentNode._readonly))) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// get item index
var itemIndex = __findNamedItemNSIndex__(this, namespaceURI, localName);
// throw Exception if there is no matching node in this map
if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) {
throw(new DOMException(DOMException.NOT_FOUND_ERR));
}
// get Node
var oldNode = this[itemIndex];
// throw Exception if Node is readonly
if (__ownerDocument__(this).implementation.errorChecking && oldNode._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
return __removeChild__(this, itemIndex); // return removed node
},
get xml() {
var ret = "";
// create string containing concatenation of all (but last) Attribute string values (separated by spaces)
for (var i=0; i < this.length -1; i++) {
ret += this[i].xml +" ";
}
// add last Attribute to string (without trailing space)
if (this.length > 0) {
ret += this[this.length -1].xml;
}
return ret;
}
});
/**
* @method DOMNamedNodeMap._findNamedItemIndex - find the item index of the node with the specified name
*
* @author Jon van Noort (jon@webarcana.com.au)
* @param name : string - the name of the required node
* @param isnsmap : if its a DOMNamespaceNodeMap
* @return : int
*/
var __findNamedItemIndex__ = function(namednodemap, name, isnsmap) {
var ret = -1;
// loop through all nodes
for (var i=0; i -1) { // found it!
ret = true; // return true
}
return ret; // if node is not found, default value false is returned
}
/**
* @method DOMNamedNodeMap._hasAttributeNS - Returns true if specified node exists
*
* @author Jon van Noort (jon@webarcana.com.au)
* @param namespaceURI : string - the namespace URI of the required node
* @param localName : string - the local name of the required node
* @return : boolean
*/
var __hasAttributeNS__ = function(namednodemap, namespaceURI, localName) {
var ret = false;
// test that Named Node exists
var itemIndex = __findNamedItemNSIndex__(namednodemap, namespaceURI, localName);
if (itemIndex > -1) { // found it!
ret = true; // return true
}
return ret; // if node is not found, default value false is returned
}
/**
* @method DOMNamedNodeMap._cloneNodes - Returns a NamedNodeMap containing clones of the Nodes in this NamedNodeMap
*
* @author Jon van Noort (jon@webarcana.com.au)
* @param parentNode : DOMNode - the new parent of the cloned NodeList
* @param isnsmap : bool - is this a DOMNamespaceNodeMap
* @return : DOMNamedNodeMap - NamedNodeMap containing clones of the Nodes in this DOMNamedNodeMap
*/
var __cloneNamedNodes__ = function(namednodemap, parentNode, isnsmap) {
var cloneNamedNodeMap = isnsmap?
new DOMNamespaceNodeMap(namednodemap.ownerDocument, parentNode):
new DOMNamedNodeMap(namednodemap.ownerDocument, parentNode);
// create list containing clones of all children
for (var i=0; i < namednodemap.length; i++) {
$debug("cloning node in named node map :" + namednodemap[i]);
__appendChild__(cloneNamedNodeMap, namednodemap[i].cloneNode(false));
}
return cloneNamedNodeMap;
};
/**
* @class DOMNamespaceNodeMap - used to represent collections of namespace nodes that can be accessed by name
* typically a set of Element attributes
*
* @extends DOMNamedNodeMap
*
* @author Jon van Noort (jon@webarcana.com.au)
*
* @param ownerDocument : DOMDocument - the ownerDocument
* @param parentNode : DOMNode - the node that the DOMNamespaceNodeMap is attached to (or null)
*/
var DOMNamespaceNodeMap = function(ownerDocument, parentNode) {
//$log("\t\t\tcreating dom namespacednodemap");
this.DOMNamedNodeMap = DOMNamedNodeMap;
this.DOMNamedNodeMap(ownerDocument, parentNode);
__setArray__(this, []);
};
DOMNamespaceNodeMap.prototype = new DOMNamedNodeMap;
__extend__(DOMNamespaceNodeMap.prototype, {
get xml() {
var ret = "";
// identify namespaces declared local to this Element (ie, not inherited)
for (var ind = 0; ind < this.length; ind++) {
// if namespace declaration does not exist in the containing node's, parentNode's namespaces
var ns = null;
try {
var ns = this.parentNode.parentNode._namespaces.
getNamedItem(this[ind].localName);
}
catch (e) {
//breaking to prevent default namespace being inserted into return value
break;
}
if (!(ns && (""+ ns.nodeValue == ""+ this[ind].nodeValue))) {
// display the namespace declaration
ret += this[ind].xml +" ";
}
}
return ret;
}
});
$debug("Defining Node");
/*
* Node - DOM Level 2
*/
$w.__defineGetter__('Node', function(){
return __extend__(function(){
throw new Error("Object cannot be created in this context");
} , {
ELEMENT_NODE :1,
ATTRIBUTE_NODE :2,
TEXT_NODE :3,
CDATA_SECTION_NODE: 4,
PROCESSING_INSTRUCTION_NODE: 7,
COMMENT_NODE: 8,
DOCUMENT_NODE: 9,
DOCUMENT_TYPE_NODE: 10,
DOCUMENT_FRAGMENT_NODE: 11
});
});
/**
* @class DOMNode - The Node interface is the primary datatype for the entire Document Object Model.
* It represents a single node in the document tree.
* @author Jon van Noort (jon@webarcana.com.au), David Joham (djoham@yahoo.com) and Scott Severtson
* @param ownerDocument : DOMDocument - The Document object associated with this node.
*/
var DOMNode = function(ownerDocument) {
if (ownerDocument) {
this._id = ownerDocument._genId(); // generate unique internal id
}
this.namespaceURI = ""; // The namespace URI of this node (Level 2)
this.prefix = ""; // The namespace prefix of this node (Level 2)
this.localName = ""; // The localName of this node (Level 2)
this.nodeName = ""; // The name of this node
this.nodeValue = ""; // The value of this node
this.className = ""; // The CSS class name of this node.
// The parent of this node. All nodes, except Document, DocumentFragment, and Attr may have a parent.
// However, if a node has just been created and not yet added to the tree, or if it has been removed from the tree, this is null
this.parentNode = null;
// A NodeList that contains all children of this node. If there are no children, this is a NodeList containing no nodes.
// The content of the returned NodeList is "live" in the sense that, for instance, changes to the children of the node object
// that it was created from are immediately reflected in the nodes returned by the NodeList accessors;
// it is not a static snapshot of the content of the node. This is true for every NodeList, including the ones returned by the getElementsByTagName method.
this.childNodes = new DOMNodeList(ownerDocument, this);
this.firstChild = null; // The first child of this node. If there is no such node, this is null
this.lastChild = null; // The last child of this node. If there is no such node, this is null.
this.previousSibling = null; // The node immediately preceding this node. If there is no such node, this is null.
this.nextSibling = null; // The node immediately following this node. If there is no such node, this is null.
this.ownerDocument = ownerDocument; // The Document object associated with this node
this.attributes = new DOMNamedNodeMap(this.ownerDocument, this);
this._namespaces = new DOMNamespaceNodeMap(ownerDocument, this); // The namespaces in scope for this node
this._readonly = false;
};
// nodeType constants
DOMNode.ELEMENT_NODE = 1;
DOMNode.ATTRIBUTE_NODE = 2;
DOMNode.TEXT_NODE = 3;
DOMNode.CDATA_SECTION_NODE = 4;
DOMNode.ENTITY_REFERENCE_NODE = 5;
DOMNode.ENTITY_NODE = 6;
DOMNode.PROCESSING_INSTRUCTION_NODE = 7;
DOMNode.COMMENT_NODE = 8;
DOMNode.DOCUMENT_NODE = 9;
DOMNode.DOCUMENT_TYPE_NODE = 10;
DOMNode.DOCUMENT_FRAGMENT_NODE = 11;
DOMNode.NOTATION_NODE = 12;
DOMNode.NAMESPACE_NODE = 13;
__extend__(DOMNode.prototype, {
hasAttributes : function() {
if (this.attributes.length == 0) {
return false;
}else{
return true;
}
},
insertBefore : function(newChild, refChild) {
var prevNode;
// test for exceptions
if (__ownerDocument__(this).implementation.errorChecking) {
// throw Exception if DOMNode is readonly
if (this._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// throw Exception if newChild was not created by this Document
if (__ownerDocument__(this) != __ownerDocument__(newChild)) {
throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR));
}
// throw Exception if the node is an ancestor
if (__isAncestor__(this, newChild)) {
throw(new DOMException(DOMException.HIERARCHY_REQUEST_ERR));
}
}
if (refChild) { // if refChild is specified, insert before it
// find index of refChild
var itemIndex = __findItemIndex__(this.childNodes, refChild._id);
// throw Exception if there is no child node with this id
if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) {
throw(new DOMException(DOMException.NOT_FOUND_ERR));
}
// if the newChild is already in the tree,
var newChildParent = newChild.parentNode;
if (newChildParent) {
// remove it
newChildParent.removeChild(newChild);
}
// insert newChild into childNodes
__insertBefore__(this.childNodes, newChild,
__findItemIndex__(this.childNodes, refChild._id));
// do node pointer surgery
prevNode = refChild.previousSibling;
// handle DocumentFragment
if (newChild.nodeType == DOMNode.DOCUMENT_FRAGMENT_NODE) {
if (newChild.childNodes.length > 0) {
// set the parentNode of DocumentFragment's children
for (var ind = 0; ind < newChild.childNodes.length; ind++) {
newChild.childNodes[ind].parentNode = this;
}
// link refChild to last child of DocumentFragment
refChild.previousSibling = newChild.childNodes[newChild.childNodes.length-1];
}
}else {
newChild.parentNode = this; // set the parentNode of the newChild
refChild.previousSibling = newChild; // link refChild to newChild
}
}else { // otherwise, append to end
prevNode = this.lastChild;
this.appendChild(newChild);
}
if (newChild.nodeType == DOMNode.DOCUMENT_FRAGMENT_NODE) {
// do node pointer surgery for DocumentFragment
if (newChild.childNodes.length > 0) {
if (prevNode) {
prevNode.nextSibling = newChild.childNodes[0];
}else { // this is the first child in the list
this.firstChild = newChild.childNodes[0];
}
newChild.childNodes[0].previousSibling = prevNode;
newChild.childNodes[newChild.childNodes.length-1].nextSibling = refChild;
}
}else {
// do node pointer surgery for newChild
if (prevNode) {
prevNode.nextSibling = newChild;
}else { // this is the first child in the list
this.firstChild = newChild;
}
newChild.previousSibling = prevNode;
newChild.nextSibling = refChild;
}
return newChild;
},
replaceChild : function(newChild, oldChild) {
var ret = null;
// test for exceptions
if (__ownerDocument__(this).implementation.errorChecking) {
// throw Exception if DOMNode is readonly
if (this._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// throw Exception if newChild was not created by this Document
if (__ownerDocument__(this) != __ownerDocument__(newChild)) {
throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR));
}
// throw Exception if the node is an ancestor
if (__isAncestor__(this, newChild)) {
throw(new DOMException(DOMException.HIERARCHY_REQUEST_ERR));
}
}
// get index of oldChild
var index = __findItemIndex__(this.childNodes, oldChild._id);
// throw Exception if there is no child node with this id
if (__ownerDocument__(this).implementation.errorChecking && (index < 0)) {
throw(new DOMException(DOMException.NOT_FOUND_ERR));
}
// if the newChild is already in the tree,
var newChildParent = newChild.parentNode;
if (newChildParent) {
// remove it
newChildParent.removeChild(newChild);
}
// add newChild to childNodes
ret = __replaceChild__(this.childNodes,newChild, index);
if (newChild.nodeType == DOMNode.DOCUMENT_FRAGMENT_NODE) {
// do node pointer surgery for Document Fragment
if (newChild.childNodes.length > 0) {
for (var ind = 0; ind < newChild.childNodes.length; ind++) {
newChild.childNodes[ind].parentNode = this;
}
if (oldChild.previousSibling) {
oldChild.previousSibling.nextSibling = newChild.childNodes[0];
} else {
this.firstChild = newChild.childNodes[0];
}
if (oldChild.nextSibling) {
oldChild.nextSibling.previousSibling = newChild;
} else {
this.lastChild = newChild.childNodes[newChild.childNodes.length-1];
}
newChild.childNodes[0].previousSibling = oldChild.previousSibling;
newChild.childNodes[newChild.childNodes.length-1].nextSibling = oldChild.nextSibling;
}
} else {
// do node pointer surgery for newChild
newChild.parentNode = this;
if (oldChild.previousSibling) {
oldChild.previousSibling.nextSibling = newChild;
}else{
this.firstChild = newChild;
}
if (oldChild.nextSibling) {
oldChild.nextSibling.previousSibling = newChild;
}else{
this.lastChild = newChild;
}
newChild.previousSibling = oldChild.previousSibling;
newChild.nextSibling = oldChild.nextSibling;
}
return ret;
},
removeChild : function(oldChild) {
// throw Exception if DOMNamedNodeMap is readonly
if (__ownerDocument__(this).implementation.errorChecking && (this._readonly || oldChild._readonly)) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// get index of oldChild
var itemIndex = __findItemIndex__(this.childNodes, oldChild._id);
// throw Exception if there is no child node with this id
if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) {
throw(new DOMException(DOMException.NOT_FOUND_ERR));
}
// remove oldChild from childNodes
__removeChild__(this.childNodes, itemIndex);
// do node pointer surgery
oldChild.parentNode = null;
if (oldChild.previousSibling) {
oldChild.previousSibling.nextSibling = oldChild.nextSibling;
}else {
this.firstChild = oldChild.nextSibling;
}
if (oldChild.nextSibling) {
oldChild.nextSibling.previousSibling = oldChild.previousSibling;
}else {
this.lastChild = oldChild.previousSibling;
}
oldChild.previousSibling = null;
oldChild.nextSibling = null;
return oldChild;
},
appendChild : function(newChild) {
// test for exceptions
if (__ownerDocument__(this).implementation.errorChecking) {
// throw Exception if Node is readonly
if (this._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// throw Exception if arg was not created by this Document
if (__ownerDocument__(this) != __ownerDocument__(this)) {
throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR));
}
// throw Exception if the node is an ancestor
if (__isAncestor__(this, newChild)) {
throw(new DOMException(DOMException.HIERARCHY_REQUEST_ERR));
}
}
// if the newChild is already in the tree,
var newChildParent = newChild.parentNode;
if (newChildParent) {
// remove it
newChildParent.removeChild(newChild);
}
// add newChild to childNodes
__appendChild__(this.childNodes, newChild);
if (newChild.nodeType == DOMNode.DOCUMENT_FRAGMENT_NODE) {
// do node pointer surgery for DocumentFragment
if (newChild.childNodes.length > 0) {
for (var ind = 0; ind < newChild.childNodes.length; ind++) {
newChild.childNodes[ind].parentNode = this;
}
if (this.lastChild) {
this.lastChild.nextSibling = newChild.childNodes[0];
newChild.childNodes[0].previousSibling = this.lastChild;
this.lastChild = newChild.childNodes[newChild.childNodes.length-1];
}
else {
this.lastChild = newChild.childNodes[newChild.childNodes.length-1];
this.firstChild = newChild.childNodes[0];
}
}
}
else {
// do node pointer surgery for newChild
newChild.parentNode = this;
if (this.lastChild) {
this.lastChild.nextSibling = newChild;
newChild.previousSibling = this.lastChild;
this.lastChild = newChild;
}
else {
this.lastChild = newChild;
this.firstChild = newChild;
}
}
return newChild;
},
hasChildNodes : function() {
return (this.childNodes.length > 0);
},
cloneNode: function(deep) {
// use importNode to clone this Node
//do not throw any exceptions
try {
return __ownerDocument__(this).importNode(this, deep);
} catch (e) {
//there shouldn't be any exceptions, but if there are, return null
return null;
}
},
normalize : function() {
var inode;
var nodesToRemove = new DOMNodeList();
if (this.nodeType == DOMNode.ELEMENT_NODE || this.nodeType == DOMNode.DOCUMENT_NODE) {
var adjacentTextNode = null;
// loop through all childNodes
for(var i = 0; i < this.childNodes.length; i++) {
inode = this.childNodes.item(i);
if (inode.nodeType == DOMNode.TEXT_NODE) { // this node is a text node
if (inode.length < 1) { // this text node is empty
__appendChild__(nodesToRemove, inode); // add this node to the list of nodes to be remove
}else {
if (adjacentTextNode) { // if previous node was also text
adjacentTextNode.appendData(inode.data); // merge the data in adjacent text nodes
__appendChild__(nodesToRemove, inode); // add this node to the list of nodes to be removed
}else {
adjacentTextNode = inode; // remember this node for next cycle
}
}
} else {
adjacentTextNode = null; // (soon to be) previous node is not a text node
inode.normalize(); // normalise non Text childNodes
}
}
// remove redundant Text Nodes
for(var i = 0; i < nodesToRemove.length; i++) {
inode = nodesToRemove.item(i);
inode.parentNode.removeChild(inode);
}
}
},
isSupported : function(feature, version) {
// use Implementation.hasFeature to determin if this feature is supported
return __ownerDocument__(this).implementation.hasFeature(feature, version);
},
getElementsByTagName : function(tagname) {
// delegate to _getElementsByTagNameRecursive
// recurse childNodes
var nodelist = new DOMNodeList(__ownerDocument__(this));
for(var i = 0; i < this.childNodes.length; i++) {
nodeList = __getElementsByTagNameRecursive__(this.childNodes.item(i), tagname, nodelist);
}
return nodelist;
},
getElementsByTagNameNS : function(namespaceURI, localName) {
// delegate to _getElementsByTagNameNSRecursive
return __getElementsByTagNameNSRecursive__(this, namespaceURI, localName,
new DOMNodeList(__ownerDocument__(this)));
},
importNode : function(importedNode, deep) {
var importNode;
//$debug("importing node " + importedNode.nodeName + "(?deep = "+deep+")");
//there is no need to perform namespace checks since everything has already gone through them
//in order to have gotten into the DOM in the first place. The following line
//turns namespace checking off in ._isValidNamespace
__ownerDocument__(this)._performingImportNodeOperation = true;
if (importedNode.nodeType == DOMNode.ELEMENT_NODE) {
if (!__ownerDocument__(this).implementation.namespaceAware) {
// create a local Element (with the name of the importedNode)
importNode = __ownerDocument__(this).createElement(importedNode.tagName);
// create attributes matching those of the importedNode
for(var i = 0; i < importedNode.attributes.length; i++) {
importNode.setAttribute(importedNode.attributes.item(i).name, importedNode.attributes.item(i).value);
}
}else {
// create a local Element (with the name & namespaceURI of the importedNode)
importNode = __ownerDocument__(this).createElementNS(importedNode.namespaceURI, importedNode.nodeName);
// create attributes matching those of the importedNode
for(var i = 0; i < importedNode.attributes.length; i++) {
importNode.setAttributeNS(importedNode.attributes.item(i).namespaceURI,
importedNode.attributes.item(i).name, importedNode.attributes.item(i).value);
}
// create namespace definitions matching those of the importedNode
for(var i = 0; i < importedNode._namespaces.length; i++) {
importNode._namespaces[i] = __ownerDocument__(this).createNamespace(importedNode._namespaces.item(i).localName);
importNode._namespaces[i].value = importedNode._namespaces.item(i).value;
}
}
} else if (importedNode.nodeType == DOMNode.ATTRIBUTE_NODE) {
if (!__ownerDocument__(this).implementation.namespaceAware) {
// create a local Attribute (with the name of the importedAttribute)
importNode = __ownerDocument__(this).createAttribute(importedNode.name);
} else {
// create a local Attribute (with the name & namespaceURI of the importedAttribute)
importNode = __ownerDocument__(this).createAttributeNS(importedNode.namespaceURI, importedNode.nodeName);
// create namespace definitions matching those of the importedAttribute
for(var i = 0; i < importedNode._namespaces.length; i++) {
importNode._namespaces[i] = __ownerDocument__(this).createNamespace(importedNode._namespaces.item(i).localName);
importNode._namespaces[i].value = importedNode._namespaces.item(i).value;
}
}
// set the value of the local Attribute to match that of the importedAttribute
importNode.value = importedNode.value;
} else if (importedNode.nodeType == DOMNode.DOCUMENT_FRAGMENT) {
// create a local DocumentFragment
importNode = __ownerDocument__(this).createDocumentFragment();
} else if (importedNode.nodeType == DOMNode.NAMESPACE_NODE) {
// create a local NamespaceNode (with the same name & value as the importedNode)
importNode = __ownerDocument__(this).createNamespace(importedNode.nodeName);
importNode.value = importedNode.value;
} else if (importedNode.nodeType == DOMNode.TEXT_NODE) {
// create a local TextNode (with the same data as the importedNode)
importNode = __ownerDocument__(this).createTextNode(importedNode.data);
} else if (importedNode.nodeType == DOMNode.CDATA_SECTION_NODE) {
// create a local CDATANode (with the same data as the importedNode)
importNode = __ownerDocument__(this).createCDATASection(importedNode.data);
} else if (importedNode.nodeType == DOMNode.PROCESSING_INSTRUCTION_NODE) {
// create a local ProcessingInstruction (with the same target & data as the importedNode)
importNode = __ownerDocument__(this).createProcessingInstruction(importedNode.target, importedNode.data);
} else if (importedNode.nodeType == DOMNode.COMMENT_NODE) {
// create a local Comment (with the same data as the importedNode)
importNode = __ownerDocument__(this).createComment(importedNode.data);
} else { // throw Exception if nodeType is not supported
throw(new DOMException(DOMException.NOT_SUPPORTED_ERR));
}
if (deep) { // recurse childNodes
for(var i = 0; i < importedNode.childNodes.length; i++) {
importNode.appendChild(__ownerDocument__(this).importNode(importedNode.childNodes.item(i), true));
}
}
//reset _performingImportNodeOperation
__ownerDocument__(this)._performingImportNodeOperation = false;
return importNode;
},
contains : function(node){
while(node && node != this ){
node = node.parentNode;
}
return !!node;
},
compareDocumentPosition : function(b){
var a = this;
var number = (a != b && a.contains(b) && 16) + (a != b && b.contains(a) && 8);
//find position of both
var all = document.getElementsByTagName("*");
var my_location = 0, node_location = 0;
for(var i=0; i < all.length; i++){
if(all[i] == a) my_location = i;
if(all[i] == b) node_location = i;
if(my_location && node_location) break;
}
number += (my_location < node_location && 4)
number += (my_location > node_location && 2)
return number;
}
});
/**
* @method DOMNode._getElementsByTagNameRecursive - implements getElementsByTagName()
* @param elem : DOMElement - The element which are checking and then recursing into
* @param tagname : string - The name of the tag to match on. The special value "*" matches all tags
* @param nodeList : DOMNodeList - The accumulating list of matching nodes
*
* @return : DOMNodeList
*/
var __getElementsByTagNameRecursive__ = function (elem, tagname, nodeList) {
if (elem.nodeType == DOMNode.ELEMENT_NODE || elem.nodeType == DOMNode.DOCUMENT_NODE) {
if(elem.nodeType !== DOMNode.DOCUMENT_NODE &&
((elem.nodeName.toUpperCase() == tagname.toUpperCase()) ||
(tagname == "*")) ){
__appendChild__(nodeList, elem); // add matching node to nodeList
}
// recurse childNodes
for(var i = 0; i < elem.childNodes.length; i++) {
nodeList = __getElementsByTagNameRecursive__(elem.childNodes.item(i), tagname, nodeList);
}
}
return nodeList;
};
/**
* @method DOMNode._getElementsByTagNameNSRecursive - implements getElementsByTagName()
*
* @param elem : DOMElement - The element which are checking and then recursing into
* @param namespaceURI : string - the namespace URI of the required node
* @param localName : string - the local name of the required node
* @param nodeList : DOMNodeList - The accumulating list of matching nodes
*
* @return : DOMNodeList
*/
var __getElementsByTagNameNSRecursive__ = function(elem, namespaceURI, localName, nodeList) {
if (elem.nodeType == DOMNode.ELEMENT_NODE || elem.nodeType == DOMNode.DOCUMENT_NODE) {
if (((elem.namespaceURI == namespaceURI) || (namespaceURI == "*")) && ((elem.localName == localName) || (localName == "*"))) {
__appendChild__(nodeList, elem); // add matching node to nodeList
}
// recurse childNodes
for(var i = 0; i < elem.childNodes.length; i++) {
nodeList = __getElementsByTagNameNSRecursive__(elem.childNodes.item(i), namespaceURI, localName, nodeList);
}
}
return nodeList;
};
/**
* @method DOMNode._isAncestor - returns true if node is ancestor of target
* @param target : DOMNode - The node we are using as context
* @param node : DOMNode - The candidate ancestor node
* @return : boolean
*/
var __isAncestor__ = function(target, node) {
// if this node matches, return true,
// otherwise recurse up (if there is a parentNode)
return ((target == node) || ((target.parentNode) && (__isAncestor__(target.parentNode, node))));
};
var __ownerDocument__ = function(node){
return (node.nodeType == DOMNode.DOCUMENT_NODE)?node:node.ownerDocument;
};
/**
* @class DOMNamespace - The Namespace interface represents an namespace in an Element object
*
* @extends DOMNode
* @author Jon van Noort (jon@webarcana.com.au)
* @param ownerDocument : DOMDocument - The Document object associated with this node.
*/
var DOMNamespace = function(ownerDocument) {
this.DOMNode = DOMNode;
this.DOMNode(ownerDocument);
this.name = ""; // the name of this attribute
// If this attribute was explicitly given a value in the original document, this is true; otherwise, it is false.
// Note that the implementation is in charge of this attribute, not the user.
// If the user changes the value of the attribute (even if it ends up having the same value as the default value)
// then the specified flag is automatically flipped to true
this.specified = false;
};
DOMNamespace.prototype = new DOMNode;
__extend__(DOMNamespace.prototype, {
get value(){
// the value of the attribute is returned as a string
return this.nodeValue;
},
set value(value){
this.nodeValue = value+'';
},
get nodeType(){
return DOMNode.NAMESPACE_NODE;
},
get xml(){
var ret = "";
// serialize Namespace Declaration
if (this.nodeName != "") {
ret += this.nodeName +"=\""+ __escapeXML__(this.nodeValue) +"\"";
}
else { // handle default namespace
ret += "xmlns=\""+ __escapeXML__(this.nodeValue) +"\"";
}
return ret;
},
toString: function(){
return "Namespace #" + this.id;
}
});
$debug("Defining CharacterData");
/*
* CharacterData - DOM Level 2
*/
$w.__defineGetter__("CharacterData", function(){
return function(){
throw new Error("Object cannot be created in this context");
};
});
/**
* @class DOMCharacterData - parent abstract class for DOMText and DOMComment
* @extends DOMNode
* @author Jon van Noort (jon@webarcana.com.au)
* @param ownerDocument : DOMDocument - The Document object associated with this node.
*/
var DOMCharacterData = function(ownerDocument) {
this.DOMNode = DOMNode;
this.DOMNode(ownerDocument);
};
DOMCharacterData.prototype = new DOMNode;
__extend__(DOMCharacterData.prototype,{
get data(){
return this.nodeValue;
},
set data(data){
this.nodeValue = data;
},
get length(){return this.nodeValue.length;},
appendData: function(arg){
// throw Exception if DOMCharacterData is readonly
if (__ownerDocument__(this).implementation.errorChecking && this._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// append data
this.data = "" + this.data + arg;
},
deleteData: function(offset, count){
// throw Exception if DOMCharacterData is readonly
if (__ownerDocument__(this).implementation.errorChecking && this._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
if (this.data) {
// throw Exception if offset is negative or greater than the data length,
if (__ownerDocument__(this).implementation.errorChecking &&
((offset < 0) || (offset > this.data.length) || (count < 0))) {
throw(new DOMException(DOMException.INDEX_SIZE_ERR));
}
// delete data
if(!count || (offset + count) > this.data.length) {
this.data = this.data.substring(0, offset);
}else {
this.data = this.data.substring(0, offset).
concat(this.data.substring(offset + count));
}
}
},
insertData: function(offset, arg){
// throw Exception if DOMCharacterData is readonly
if(__ownerDocument__(this).implementation.errorChecking && this._readonly){
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
if(this.data){
// throw Exception if offset is negative or greater than the data length,
if (__ownerDocument__(this).implementation.errorChecking &&
((offset < 0) || (offset > this.data.length))) {
throw(new DOMException(DOMException.INDEX_SIZE_ERR));
}
// insert data
this.data = this.data.substring(0, offset).concat(arg, this.data.substring(offset));
}else {
// throw Exception if offset is negative or greater than the data length,
if (__ownerDocument__(this).implementation.errorChecking && (offset != 0)) {
throw(new DOMException(DOMException.INDEX_SIZE_ERR));
}
// set data
this.data = arg;
}
},
replaceData: function(offset, count, arg){
// throw Exception if DOMCharacterData is readonly
if (__ownerDocument__(this).implementation.errorChecking && this._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
if (this.data) {
// throw Exception if offset is negative or greater than the data length,
if (__ownerDocument__(this).implementation.errorChecking &&
((offset < 0) || (offset > this.data.length) || (count < 0))) {
throw(new DOMException(DOMException.INDEX_SIZE_ERR));
}
// replace data
this.data = this.data.substring(0, offset).
concat(arg, this.data.substring(offset + count));
}else {
// set data
this.data = arg;
}
},
substringData: function(offset, count){
var ret = null;
if (this.data) {
// throw Exception if offset is negative or greater than the data length,
// or the count is negative
if (__ownerDocument__(this).implementation.errorChecking &&
((offset < 0) || (offset > this.data.length) || (count < 0))) {
throw(new DOMException(DOMException.INDEX_SIZE_ERR));
}
// if count is not specified
if (!count) {
ret = this.data.substring(offset); // default to 'end of string'
}else{
ret = this.data.substring(offset, offset + count);
}
}
return ret;
}
});
$debug("Defining Text");
/*
* Text - DOM Level 2
*/
$w.__defineGetter__("Text", function(){
return function(){
throw new Error("Object cannot be created in this context");
};
});
/**
* @class DOMText - The Text interface represents the textual content (termed character data in XML) of an Element or Attr.
* If there is no markup inside an element's content, the text is contained in a single object implementing the Text interface
* that is the only child of the element. If there is markup, it is parsed into a list of elements and Text nodes that form the
* list of children of the element.
* @extends DOMCharacterData
* @author Jon van Noort (jon@webarcana.com.au) and David Joham (djoham@yahoo.com)
* @param ownerDocument : DOMDocument - The Document object associated with this node.
*/
DOMText = function(ownerDocument) {
this.DOMCharacterData = DOMCharacterData;
this.DOMCharacterData(ownerDocument);
this.nodeName = "#text";
};
DOMText.prototype = new DOMCharacterData;
__extend__(DOMText.prototype,{
//Breaks this Text node into two Text nodes at the specified offset,
// keeping both in the tree as siblings. This node then only contains all the content up to the offset point.
// And a new Text node, which is inserted as the next sibling of this node, contains all the content at and after the offset point.
splitText : function(offset) {
var data, inode;
// test for exceptions
if (__ownerDocument__(this).implementation.errorChecking) {
// throw Exception if Node is readonly
if (this._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// throw Exception if offset is negative or greater than the data length,
if ((offset < 0) || (offset > this.data.length)) {
throw(new DOMException(DOMException.INDEX_SIZE_ERR));
}
}
if (this.parentNode) {
// get remaining string (after offset)
data = this.substringData(offset);
// create new TextNode with remaining string
inode = __ownerDocument__(this).createTextNode(data);
// attach new TextNode
if (this.nextSibling) {
this.parentNode.insertBefore(inode, this.nextSibling);
}
else {
this.parentNode.appendChild(inode);
}
// remove remaining string from original TextNode
this.deleteData(offset);
}
return inode;
},
get nodeType(){
return DOMNode.TEXT_NODE;
},
get xml(){
return __escapeXML__(""+ this.nodeValue);
},
toString: function(){
return "Text #" + this._id;
}
});
$debug("Defining CDATASection");
/*
* CDATASection - DOM Level 2
*/
$w.__defineGetter__("CDATASection", function(){
return function(){
throw new Error("Object cannot be created in this context");
};
});
/**
* @class DOMCDATASection - CDATA sections are used to escape blocks of text containing characters that would otherwise be regarded as markup.
* The only delimiter that is recognized in a CDATA section is the "\]\]\>" string that ends the CDATA section
* @extends DOMCharacterData
* @author Jon van Noort (jon@webarcana.com.au) and David Joham (djoham@yahoo.com)
* @param ownerDocument : DOMDocument - The Document object associated with this node.
*/
var DOMCDATASection = function(ownerDocument) {
this.DOMText = DOMText;
this.DOMText(ownerDocument);
this.nodeName = "#cdata-section";
};
DOMCDATASection.prototype = new DOMText;
__extend__(DOMCDATASection.prototype,{
get nodeType(){
return DOMNode.CDATA_SECTION_NODE;
},
get xml(){
return "";
},
toString : function(){
return "CDATA #"+this._id;
}
});$debug("Defining Comment");
/*
* Comment - DOM Level 2
*/
$w.__defineGetter__("Comment", function(){
return function(){
throw new Error("Object cannot be created in this context");
};
});
/**
* @class DOMComment - This represents the content of a comment, i.e., all the characters between the starting ''
* @extends DOMCharacterData
* @author Jon van Noort (jon@webarcana.com.au)
* @param ownerDocument : DOMDocument - The Document object associated with this node.
*/
var DOMComment = function(ownerDocument) {
this.DOMCharacterData = DOMCharacterData;
this.DOMCharacterData(ownerDocument);
this.nodeName = "#comment";
};
DOMComment.prototype = new DOMCharacterData;
__extend__(DOMComment.prototype, {
get nodeType(){
return DOMNode.COMMENT_NODE;
},
get xml(){
return "";
},
toString : function(){
return "Comment #"+this._id;
}
});
$debug("Defining DocumentType");
;/*
* DocumentType - DOM Level 2
*/
$w.__defineGetter__('DocumentType', function(){
return function(){
throw new Error("Object cannot be created in this context");
};
});
var DOMDocumentType = function() { $error("DOMDocumentType.constructor(): Not Implemented" ); };$debug("Defining Attr");
/*
* Attr - DOM Level 2
*/
$w.__defineGetter__("Attr", function(){
return function(){
throw new Error("Object cannot be created in this context");
};
});
/**
* @class DOMAttr - The Attr interface represents an attribute in an Element object
* @extends DOMNode
* @author Jon van Noort (jon@webarcana.com.au)
* @param ownerDocument : DOMDocument - The Document object associated with this node.
*/
var DOMAttr = function(ownerDocument) {
this.DOMNode = DOMNode;
this.DOMNode(ownerDocument);
this.ownerElement = null; // set when Attr is added to NamedNodeMap
};
DOMAttr.prototype = new DOMNode;
__extend__(DOMAttr.prototype, {
// the name of this attribute
get name(){
return this.nodeName;
},
set name(name){
this.nodeName = name;
},
// the value of the attribute is returned as a string
get value(){
return this.nodeValue;
},
set value(value){
// throw Exception if Attribute is readonly
if (__ownerDocument__(this).implementation.errorChecking && this._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// delegate to node
this.nodeValue = value;
},
get specified(){
return (this.value.length > 0);
},
get nodeType(){
return DOMNode.ATTRIBUTE_NODE;
},
get xml(){
return this.nodeName + '="' + __escapeXML__(this.nodeValue) + '" ';
},
toString : function(){
return "Attr #" + this._id + " " + this.name;
}
});
$debug("Defining Element");
/*
* Element - DOM Level 2
*/
$w.__defineGetter__("Element", function(){
return function(){
throw new Error("Object cannot be created in this context");
};
});
/**
* @class DOMElement - By far the vast majority of objects (apart from text) that authors encounter
* when traversing a document are Element nodes.
* @extends DOMNode
* @author Jon van Noort (jon@webarcana.com.au) and David Joham (djoham@yahoo.com)
* @param ownerDocument : DOMDocument - The Document object associated with this node.
*/
var DOMElement = function(ownerDocument) {
this.DOMNode = DOMNode;
this.DOMNode(ownerDocument);
this.id = ""; // the ID of the element
};
DOMElement.prototype = new DOMNode;
__extend__(DOMElement.prototype, {
// The name of the element.
get tagName(){
return this.nodeName;
},
set tagName(name){
this.nodeName = name;
},
addEventListener : function(){ window.addEventListener.apply(this, arguments) },
removeEventListener : function(){ window.removeEventListener.apply(this, arguments) },
dispatchEvent : function(){ window.dispatchEvent.apply(this, arguments) },
getAttribute: function(name) {
var ret = null;
// if attribute exists, use it
var attr = this.attributes.getNamedItem(name);
if (attr) {
ret = attr.value;
}
return ret; // if Attribute exists, return its value, otherwise, return ""
},
setAttribute : function (name, value) {
// if attribute exists, use it
var attr = this.attributes.getNamedItem(name);
var value = value+'';
//I had to add this check becuase as the script initializes
//the id may be set in the constructor, and the html element
//overrides the id property with a getter/setter.
if(__ownerDocument__(this)){
if (!attr) {
attr = __ownerDocument__(this).createAttribute(name); // otherwise create it
}
// test for exceptions
if (__ownerDocument__(this).implementation.errorChecking) {
// throw Exception if Attribute is readonly
if (attr._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// throw Exception if the value string contains an illegal character
if (!__isValidString__(value)) {
throw(new DOMException(DOMException.INVALID_CHARACTER_ERR));
}
}
if (__isIdDeclaration__(name)) {
// this.id = value; // cache ID for getElementById()
}
// assign values to properties (and aliases)
attr.value = value;
// add/replace Attribute in NamedNodeMap
this.attributes.setNamedItem(attr);
}
},
removeAttribute : function removeAttribute(name) {
// delegate to DOMNamedNodeMap.removeNamedItem
return this.attributes.removeNamedItem(name);
},
getAttributeNode : function getAttributeNode(name) {
// delegate to DOMNamedNodeMap.getNamedItem
return this.attributes.getNamedItem(name);
},
setAttributeNode: function(newAttr) {
// if this Attribute is an ID
if (__isIdDeclaration__(newAttr.name)) {
this.id = newAttr.value; // cache ID for getElementById()
}
// delegate to DOMNamedNodeMap.setNamedItem
return this.attributes.setNamedItem(newAttr);
},
removeAttributeNode: function(oldAttr) {
// throw Exception if Attribute is readonly
if (__ownerDocument__(this).implementation.errorChecking && oldAttr._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// get item index
var itemIndex = this.attributes._findItemIndex(oldAttr._id);
// throw Exception if node does not exist in this map
if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) {
throw(new DOMException(DOMException.NOT_FOUND_ERR));
}
return this.attributes._removeChild(itemIndex);
},
getAttributeNS : function(namespaceURI, localName) {
var ret = "";
// delegate to DOMNAmedNodeMap.getNamedItemNS
var attr = this.attributes.getNamedItemNS(namespaceURI, localName);
if (attr) {
ret = attr.value;
}
return ret; // if Attribute exists, return its value, otherwise return ""
},
setAttributeNS : function(namespaceURI, qualifiedName, value) {
// call DOMNamedNodeMap.getNamedItem
var attr = this.attributes.getNamedItem(namespaceURI, qualifiedName);
if (!attr) { // if Attribute exists, use it
// otherwise create it
attr = __ownerDocument__(this).createAttributeNS(namespaceURI, qualifiedName);
}
var value = value+'';
// test for exceptions
if (__ownerDocument__(this).implementation.errorChecking) {
// throw Exception if Attribute is readonly
if (attr._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
// throw Exception if the Namespace is invalid
if (!__isValidNamespace__(namespaceURI, qualifiedName)) {
throw(new DOMException(DOMException.NAMESPACE_ERR));
}
// throw Exception if the value string contains an illegal character
if (!__isValidString__(value)) {
throw(new DOMException(DOMException.INVALID_CHARACTER_ERR));
}
}
// if this Attribute is an ID
if (__isIdDeclaration__(name)) {
this.id = value; // cache ID for getElementById()
}
// assign values to properties (and aliases)
attr.value = value;
attr.nodeValue = value;
// delegate to DOMNamedNodeMap.setNamedItem
this.attributes.setNamedItemNS(attr);
},
removeAttributeNS : function(namespaceURI, localName) {
// delegate to DOMNamedNodeMap.removeNamedItemNS
return this.attributes.removeNamedItemNS(namespaceURI, localName);
},
getAttributeNodeNS : function(namespaceURI, localName) {
// delegate to DOMNamedNodeMap.getNamedItemNS
return this.attributes.getNamedItemNS(namespaceURI, localName);
},
setAttributeNodeNS : function(newAttr) {
// if this Attribute is an ID
if ((newAttr.prefix == "") && __isIdDeclaration__(newAttr.name)) {
this.id = newAttr.value+''; // cache ID for getElementById()
}
// delegate to DOMNamedNodeMap.setNamedItemNS
return this.attributes.setNamedItemNS(newAttr);
},
hasAttribute : function(name) {
// delegate to DOMNamedNodeMap._hasAttribute
return __hasAttribute__(this.attributes,name);
},
hasAttributeNS : function(namespaceURI, localName) {
// delegate to DOMNamedNodeMap._hasAttributeNS
return __hasAttributeNS__(this.attributes, namespaceURI, localName);
},
get nodeType(){
return DOMNode.ELEMENT_NODE;
},
get xml() {
var ret = "";
// serialize namespace declarations
var ns = this._namespaces.xml;
if (ns.length > 0) ns = " "+ ns;
// serialize Attribute declarations
var attrs = this.attributes.xml;
if (attrs.length > 0) attrs = " "+ attrs;
// serialize this Element
ret += "<" + this.nodeName.toLowerCase() + ns + attrs +">";
ret += this.childNodes.xml;
ret += "" + this.nodeName.toLowerCase()+">";
return ret;
},
toString : function(){
return "Element #"+this._id + " "+ this.tagName + (this.id?" => "+this.id:'');
}
});
/**
* @class DOMException - raised when an operation is impossible to perform
* @author Jon van Noort (jon@webarcana.com.au)
* @param code : int - the exception code (one of the DOMException constants)
*/
var DOMException = function(code) {
this.code = code;
};
// DOMException constants
// Introduced in DOM Level 1:
DOMException.INDEX_SIZE_ERR = 1;
DOMException.DOMSTRING_SIZE_ERR = 2;
DOMException.HIERARCHY_REQUEST_ERR = 3;
DOMException.WRONG_DOCUMENT_ERR = 4;
DOMException.INVALID_CHARACTER_ERR = 5;
DOMException.NO_DATA_ALLOWED_ERR = 6;
DOMException.NO_MODIFICATION_ALLOWED_ERR = 7;
DOMException.NOT_FOUND_ERR = 8;
DOMException.NOT_SUPPORTED_ERR = 9;
DOMException.INUSE_ATTRIBUTE_ERR = 10;
// Introduced in DOM Level 2:
DOMException.INVALID_STATE_ERR = 11;
DOMException.SYNTAX_ERR = 12;
DOMException.INVALID_MODIFICATION_ERR = 13;
DOMException.NAMESPACE_ERR = 14;
DOMException.INVALID_ACCESS_ERR = 15;
$debug("Defining DocumentFragment");
/*
* DocumentFragment - DOM Level 2
*/
$w.__defineGetter__("DocumentFragment", function(){
return function(){
throw new Error("Object cannot be created in this context");
};
});
/**
* @class DOMDocumentFragment - DocumentFragment is a "lightweight" or "minimal" Document object.
* @extends DOMNode
* @author Jon van Noort (jon@webarcana.com.au) and David Joham (djoham@yahoo.com)
* @param ownerDocument : DOMDocument - The Document object associated with this node.
*/
var DOMDocumentFragment = function(ownerDocument) {
this.DOMNode = DOMNode;
this.DOMNode(ownerDocument);
this.nodeName = "#document-fragment";
};
DOMDocumentFragment.prototype = new DOMNode;
__extend__(DOMDocumentFragment.prototype,{
get nodeType(){
return DOMNode.DOCUMENT_FRAGMENT_NODE;
},
get xml(){
var xml = "",
count = this.childNodes.length;
// create string concatenating the serialized ChildNodes
for (var i = 0; i < count; i++) {
xml += this.childNodes.item(i).xml;
}
return xml;
},
toString : function(){
return "DocumentFragment #"+this._id;
}
});
$debug("Defining ProcessingInstruction");
/*
* ProcessingInstruction - DOM Level 2
*/
$w.__defineGetter__('ProcessingInstruction', function(){
return function(){
throw new Error("Object cannot be created in this context");
};
});
/**
* @class DOMProcessingInstruction - The ProcessingInstruction interface represents a "processing instruction",
* used in XML as a way to keep processor-specific information in the text of the document
* @extends DOMNode
* @author Jon van Noort (jon@webarcana.com.au)
* @param ownerDocument : DOMDocument - The Document object associated with this node.
*/
var DOMProcessingInstruction = function(ownerDocument) {
this.DOMNode = DOMNode;
this.DOMNode(ownerDocument);
};
DOMProcessingInstruction.prototype = new DOMNode;
__extend__(DOMProcessingInstruction.prototype, {
get data(){
return this.nodeValue;
},
set data(data){
// throw Exception if DOMNode is readonly
if (__ownerDocument__(this).errorChecking && this._readonly) {
throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR));
}
this.nodeValue = data;
},
get target(){
// The target of this processing instruction.
// XML defines this as being the first token following the markup that begins the processing instruction.
// The content of this processing instruction.
return this.nodeName;
},
get nodeType(){
return DOMNode.PROCESSING_INSTRUCTION_NODE;
},
get xml(){
return "" + this.nodeName +" "+ this.nodeValue + " ?>";
},
toString : function(){
return "ProcessingInstruction #"+this._id;
}
});
$debug("Defining DOMParser");
/*
* DOMParser
*/
var DOMParser = function(){};
__extend__(DOMParser.prototype,{
parseFromString: function(xmlString){
//$log("Parsing XML String: " +xmlString);
return document.implementation.createDocument().loadXML(xmlString);
}
});
$debug("Initializing Internal DOMParser.");
//keep one around for internal use
$domparser = new DOMParser();
$w.__defineGetter__('DOMParser', DOMParser);
// =========================================================================
//
// xmlsax.js - an XML SAX parser in JavaScript.
//
// version 3.1
//
// =========================================================================
//
// Copyright (C) 2001 - 2002 David Joham (djoham@yahoo.com) and Scott Severtson
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//
// Visit the XML for