Adds XHR support to Rhino evn
[jquery.git] / build / runtest / env.js
index 30cd8f1..de422f7 100644 (file)
@@ -1,3 +1,9 @@
+/*
+ * Simulated browser environment for Rhino
+ *   By John Resig <http://ejohn.org/>
+ * Copyright 2007 John Resig, under the MIT License
+ */
+
 // The window Object
 var window = this;
 
@@ -12,7 +18,10 @@ var window = this;
        };
        
        window.__defineSetter__("location", function(url){
-               window.document = new DOMDocument(url);
+               window.document = new DOMDocument(
+                       new Packages.org.xml.sax.InputSource(
+                       new java.io.InputStreamReader(
+                               new java.io.FileInputStream(url))));
        });
        
        window.__defineGetter__("location", function(url){
@@ -71,17 +80,22 @@ var window = this;
                this._dom = Packages.javax.xml.parsers.
                        DocumentBuilderFactory.newInstance()
                                .newDocumentBuilder().parse(file);
+               
+               if ( !obj_nodes.containsKey( this._dom ) )
+                       obj_nodes.put( this._dom, this );
        };
        
        DOMDocument.prototype = {
                createTextNode: function(text){
-                       return makeNode( this._dom.createTextNode(text) );
+                       return makeNode( this._dom.createTextNode(
+                               text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")) );
                },
                createElement: function(name){
-                       return makeNode( this._dom.createElement(name) );
+                       return makeNode( this._dom.createElement(name.toLowerCase()) );
                },
                getElementsByTagName: function(name){
-                       return new DOMNodeList( this._dom.getElementsByTagName(name) );
+                       return new DOMNodeList( this._dom.getElementsByTagName(
+                               name.toLowerCase()) );
                },
                getElementById: function(id){
                        var elems = this._dom.getElementsByTagName("*");
@@ -97,16 +111,11 @@ var window = this;
                get body(){
                        return this.getElementsByTagName("body")[0];
                },
-               defaultView: {
-                       getComputedStyle: {
-                               getPropertyValue: function(){ }
-                       }
-               },
                get documentElement(){
                        return makeNode( this._dom.getDocumentElement() );
                },
                get ownerDocument(){
-                       return this;
+                       return null;
                },
                addEventListener: function(){},
                removeEventListener: function(){},
@@ -123,17 +132,29 @@ var window = this;
                
                get defaultView(){
                        return {
-                               getComputedStyle: function(){
+                               getComputedStyle: function(elem){
                                        return {
-                                               getPropertyValue: function(){
-                                                       return "";
+                                               getPropertyValue: function(prop){
+                                                       prop = prop.replace(/\-(\w)/g,function(m,c){
+                                                               return c.toUpperCase();
+                                                       });
+                                                       var val = elem.style[prop];
+                                                       
+                                                       if ( prop == "opacity" && val == "" )
+                                                               val = "1";
+                                                               
+                                                       return val;
                                                }
-                                       }
+                                       };
                                }
                        };
                }
        };
        
+       function getDocument(node){
+               return obj_nodes.get(node);
+       }
+       
        // DOM NodeList
        
        window.DOMNodeList = function(list){
@@ -177,10 +198,10 @@ var window = this;
                        return makeNode( this._dom.cloneNode(deep) );
                },
                get ownerDocument(){
-                       return document;
+                       return getDocument( this._dom.ownerDocument );
                },
                get documentElement(){
-                       return document.documentElement;
+                       return makeNode( this._dom.documentElement );
                },
                get parentNode() {
                        return makeNode( this._dom.getParentNode() );
@@ -203,6 +224,19 @@ var window = this;
 
        window.DOMElement = function(elem){
                this._dom = elem;
+               this.style = {
+                       get opacity(){ return this._opacity; },
+                       set opacity(val){ this._opacity = val + ""; }
+               };
+               
+               // Load CSS info
+               var styles = (this.getAttribute("style") || "").split(/\s*;\s*/);
+               
+               for ( var i = 0; i < styles.length; i++ ) {
+                       var style = styles[i].split(/\s*:\s*/);
+                       if ( style.length == 2 )
+                               this.style[ style[0] ] = style[1];
+               }
        };
        
        DOMElement.prototype = extend( new DOMNode(), {
@@ -243,10 +277,14 @@ var window = this;
                        return this.childNodes.valueOf();       
                },
                set innerHTML(html){
+                       html = html.replace(/<\/?([A-Z]+)/g, function(m){
+                               return m.toLowerCase();
+                       });
+                       
                        var nodes = this.ownerDocument.importNode(
                                new DOMDocument( new java.io.ByteArrayInputStream(
                                        (new java.lang.String("<wrap>" + html + "</wrap>"))
-                                               .getBytes())).documentElement, true).childNodes;
+                                               .getBytes("UTF8"))).documentElement, true).childNodes;
                                
                        while (this.firstChild)
                                this.removeChild( this.firstChild );
@@ -271,8 +309,7 @@ var window = this;
                set textContent(text){
                        while (this.firstChild)
                                this.removeChild( this.firstChild );
-                       this.appendChild( document.createTextNode(text) );
-                       this.innerHTML = document.createTextNode(text).nodeValue;
+                       this.appendChild( this.ownerDocument.createTextNode(text));
                },
                
                style: {},
@@ -281,17 +318,50 @@ var window = this;
                offsetHeight: 0,
                offsetWidth: 0,
                
-               get disabled() { return !!this.getAttribute("disabled"); },
+               get disabled() {
+                       var val = this.getAttribute("disabled");
+                       return val != "false" && !!val;
+               },
                set disabled(val) { return this.setAttribute("disabled",val); },
                
-               get checked() { return !!this.getAttribute("checked"); },
+               get checked() {
+                       var val = this.getAttribute("checked");
+                       return val != "false" && !!val;
+               },
                set checked(val) { return this.setAttribute("checked",val); },
                
-               get selected() { return !!this.getAttribute("selected"); },
+               get selected() {
+                       if ( !this._selectDone ) {
+                               this._selectDone = true;
+                               
+                               if ( this.nodeName == "OPTION" && !this.parentNode.getAttribute("multiple") ) {
+                                       var opt = this.parentNode.getElementsByTagName("option");
+                                       
+                                       if ( this == opt[0] ) {
+                                               var select = true;
+                                               
+                                               for ( var i = 1; i < opt.length; i++ )
+                                                       if ( opt[i].selected ) {
+                                                               select = false;
+                                                               break;
+                                                       }
+                                                       
+                                               if ( select )
+                                                       this.selected = true;
+                                       }
+                               }
+                       }
+                       
+                       var val = this.getAttribute("selected");
+                       return val != "false" && !!val;
+               },
                set selected(val) { return this.setAttribute("selected",val); },
 
                get className() { return this.getAttribute("class") || ""; },
-               set className(val) { return this.setAttribute("class",val); },
+               set className(val) {
+                       return this.setAttribute("class",
+                               val.replace(/(^\s*|\s*$)/g,""));
+               },
                
                get type() { return this.getAttribute("type") || ""; },
                set type(val) { return this.setAttribute("type",val); },
@@ -307,7 +377,7 @@ var window = this;
                
                getAttribute: function(name){
                        return this._dom.hasAttribute(name) ?
-                               this._dom.getAttribute(name) :
+                               new String( this._dom.getAttribute(name) ) :
                                null;
                },
                setAttribute: function(name,value){
@@ -343,7 +413,25 @@ var window = this;
                submit: function(){},
                focus: function(){},
                blur: function(){},
-               elements: []
+               get elements(){
+                       return this.getElementsByTagName("*");
+               },
+               get contentWindow(){
+                       return this.nodeName == "IFRAME" ? {
+                               document: this.contentDocument
+                       } : null;
+               },
+               get contentDocument(){
+                       if ( this.nodeName == "IFRAME" ) {
+                               if ( !this._doc )
+                                       this._doc = new DOMDocument(
+                                               new java.io.ByteArrayInputStream((new java.lang.String(
+                                               "<html><head><title></title></head><body></body></html>"))
+                                               .getBytes("UTF8")));
+                               return this._doc;
+                       } else
+                               return null;
+               }
        });
        
        // Helper method for extending one object with another
@@ -382,15 +470,85 @@ var window = this;
        
        // XMLHttpRequest
 
-       window.XMLHttpRequest = function(){ };
+       window.XMLHttpRequest = function(){
+         this.headers = {};
+         this.responseHeaders = {};
+       };
        
        XMLHttpRequest.prototype = {
-               open: function(){ },
-               setRequestHeader: function(){ },
-               getResponseHeader: function(){ },
+               open: function(method, url, async, user, password){ 
+                 this.readyState = 1;
+                 if(async) this.async = true;
+                 this.method = method || "GET";
+                 this.url = url;
+                 this.onreadystatechange();
+               },
+               setRequestHeader: function(header, value){
+                 this.headers[header] = value;
+               },
+               getResponseHeader: function(header){ },
+               send: function(data){
+                 var makeRequest = function() {
+                   var url = new java.net.URL(this.url);
+                   var connection = url.openConnection();
+                   // Add headers to Java connection
+                   for(header in this.headers) connection.addRequestProperty(header, this.headers[header]);
+                   connection.connect();
+                   // Stick the response headers into responseHeaders
+                   for(i=0;;i++) { 
+                     headerName = connection.getHeaderFieldKey(i); 
+                     headerValue = connection.getHeaderField(i); 
+                     if(!headerName && !headerValue) break; 
+                     if(headerName) this.responseHeaders[headerName] = headerValue;
+                   }
+             this.readyState = 4;
+        this.status = parseInt(connection.responseCode);
+        this.statusText = connection.responseMessage;
+        var stream = new java.io.InputStreamReader(connection.getInputStream());
+        var buffer = new java.io.BufferedReader(stream);
+        var line;
+        while((line = buffer.readLine()) != null) this.responseText += line;
+        try {
+          this.responseXML = new DOMDocument(this.responseText);
+        } catch(e) {
+          this.responseXML = null;
+        }
+        this.onreadystatechange();
+                 };
+                 if(this.async) {
+                 var requestThread = (new java.lang.Thread(new java.lang.Runnable({
+                   run: makeRequest
+                 })));
+                 requestThread.start();
+                 }
+               else makeRequest();
+               },
+               abort: function(){ },
+               onreadystatechange: function(){ },
+               getResponseHeader: function(header) {
+                 if(this.readyState < 3) throw new Error("INVALID_STATE_ERR");
+                 else {
+                   var returnedHeaders = [];
+                   for(rHeader in this.responseHeaders) {
+                     if(rHeader.match(new Regexp(header, "i"))) returnedHeaders.push(this.responseHeaders[rHeader]);
+                   }
+                   if(returnedHeaders != []) return returnedHeaders.join(", ");
+                 }
+                 return null;
+               },
+               getAllResponseHeaders: function(header) {
+                 if(this.readyState < 3) throw new Error("INVALID_STATE_ERR");
+                 else {
+                   returnedHeaders = [];
+                   for(var header in this.responseHeaders) {
+                     returnedHeaders += (header + ": " + this.responseHeaders[header]);
+                   }
+                   return returnedHeaders.join("\r\n");
+                 }
+               },
+               async: true,
                readyState: 0,
                responseText: "",
-               responseXML: {},
                status: 0
        };
 })();