/* * 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 += ""; 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 ""; }, 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