Got some XHR tests to run, still some hanging threads (need to investigate). Started...
[jquery.git] / build / runtest / env.js
1 /*
2  * Simulated browser environment for Rhino
3  *   By John Resig <http://ejohn.org/>
4  * Copyright 2007 John Resig, under the MIT License
5  */
6
7 // The window Object
8 var window = this;
9
10 (function(){
11
12         // Browser Navigator
13
14         window.navigator = {
15                 get userAgent(){
16                         return "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3";
17                 }
18         };
19         
20         var curLocation = (new java.io.File("./")).toURL();
21         
22         window.__defineSetter__("location", function(url){
23                 curLocation = new java.net.URL( curLocation, url );
24                 
25                 window.document = new DOMDocument(
26                         new Packages.org.xml.sax.InputSource(
27                         new java.io.InputStreamReader(
28                                 new java.io.FileInputStream( url ))));
29         });
30         
31         window.__defineGetter__("location", function(url){
32                 return {
33                         get protocol(){
34                                 return curLocation.getProtocol() + ":";
35                         }
36                 };
37         });
38         
39         // Timers
40
41         var timers = [];
42         
43         window.setTimeout = function(fn, time){
44                 var num;
45                 return num = setInterval(function(){
46                         fn();
47                         clearInterval(num);
48                 }, time);
49         };
50         
51         window.setInterval = function(fn, time){
52                 var num = timers.length;
53                 
54                 timers[num] = new java.lang.Thread(new java.lang.Runnable({
55                         run: function(){
56                                 while (true){
57                                         java.lang.Thread.currentThread().sleep(time);
58                                         fn();
59                                 }
60                         }
61                 }));
62                 
63                 timers[num].start();
64         
65                 return num;
66         };
67         
68         window.clearInterval = function(num){
69                 if ( timers[num] ) {
70                         timers[num].stop();
71                         delete timers[num];
72                 }
73         };
74         
75         // Window Events
76
77         window.addEventListener = function(){};
78         window.removeEventListener = function(){};
79         
80         // DOM Document
81         
82         window.DOMDocument = function(file){
83                 this._file = file;
84                 this._dom = Packages.javax.xml.parsers.
85                         DocumentBuilderFactory.newInstance()
86                                 .newDocumentBuilder().parse(file);
87                 
88                 if ( !obj_nodes.containsKey( this._dom ) )
89                         obj_nodes.put( this._dom, this );
90         };
91         
92         DOMDocument.prototype = {
93                 createTextNode: function(text){
94                         return makeNode( this._dom.createTextNode(
95                                 text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")) );
96                 },
97                 createElement: function(name){
98                         return makeNode( this._dom.createElement(name.toLowerCase()) );
99                 },
100                 getElementsByTagName: function(name){
101                         return new DOMNodeList( this._dom.getElementsByTagName(
102                                 name.toLowerCase()) );
103                 },
104                 getElementById: function(id){
105                         var elems = this._dom.getElementsByTagName("*");
106                         
107                         for ( var i = 0; i < elems.length; i++ ) {
108                                 var elem = elems.item(i);
109                                 if ( elem.getAttribute("id") == id )
110                                         return makeNode(elem);
111                         }
112                         
113                         return null;
114                 },
115                 get body(){
116                         return this.getElementsByTagName("body")[0];
117                 },
118                 get documentElement(){
119                         return makeNode( this._dom.getDocumentElement() );
120                 },
121                 get ownerDocument(){
122                         return null;
123                 },
124                 addEventListener: function(){},
125                 removeEventListener: function(){},
126                 get nodeName() {
127                         return "#document";
128                 },
129                 importNode: function(node, deep){
130                         return makeNode( this._dom.importNode(node._dom, deep) );
131                 },
132                 toString: function(){
133                         return "Document" + (typeof this._file == "string" ?
134                                 ": " + this._file : "");
135                 },
136                 
137                 get defaultView(){
138                         return {
139                                 getComputedStyle: function(elem){
140                                         return {
141                                                 getPropertyValue: function(prop){
142                                                         prop = prop.replace(/\-(\w)/g,function(m,c){
143                                                                 return c.toUpperCase();
144                                                         });
145                                                         var val = elem.style[prop];
146                                                         
147                                                         if ( prop == "opacity" && val == "" )
148                                                                 val = "1";
149                                                                 
150                                                         return val;
151                                                 }
152                                         };
153                                 }
154                         };
155                 }
156         };
157         
158         function getDocument(node){
159                 return obj_nodes.get(node);
160         }
161         
162         // DOM NodeList
163         
164         window.DOMNodeList = function(list){
165                 this._dom = list;
166                 this.length = list.getLength();
167                 
168                 for ( var i = 0; i < this.length; i++ ) {
169                         var node = list.item(i);
170                         this[i] = makeNode( node );
171                 }
172         };
173         
174         DOMNodeList.prototype = {
175                 toString: function(){
176                         return "[ " +
177                                 Array.prototype.join.call( this, ", " ) + " ]";
178                 },
179                 valueOf: function(){
180                         return Array.prototype.map.call(
181                                 this, function(node){return node.valueOf();}).join('');
182                 }
183         };
184         
185         // DOM Node
186         
187         window.DOMNode = function(node){
188                 this._dom = node;
189         };
190         
191         DOMNode.prototype = {
192                 get nodeType(){
193                         return this._dom.getNodeType();
194                 },
195                 get nodeValue(){
196                         return this._dom.getNodeValue();
197                 },
198                 get nodeName() {
199                         return this._dom.getNodeName();
200                 },
201                 cloneNode: function(deep){
202                         return makeNode( this._dom.cloneNode(deep) );
203                 },
204                 get ownerDocument(){
205                         return getDocument( this._dom.ownerDocument );
206                 },
207                 get documentElement(){
208                         return makeNode( this._dom.documentElement );
209                 },
210                 get parentNode() {
211                         return makeNode( this._dom.getParentNode() );
212                 },
213                 get nextSibling() {
214                         return makeNode( this._dom.getNextSibling() );
215                 },
216                 get previousSibling() {
217                         return makeNode( this._dom.getPreviousSibling() );
218                 },
219                 toString: function(){
220                         return '"' + this.nodeValue + '"';
221                 },
222                 valueOf: function(){
223                         return this.nodeValue;
224                 }
225         };
226
227         // DOM Element
228
229         window.DOMElement = function(elem){
230                 this._dom = elem;
231                 this.style = {
232                         get opacity(){ return this._opacity; },
233                         set opacity(val){ this._opacity = val + ""; }
234                 };
235                 
236                 // Load CSS info
237                 var styles = (this.getAttribute("style") || "").split(/\s*;\s*/);
238                 
239                 for ( var i = 0; i < styles.length; i++ ) {
240                         var style = styles[i].split(/\s*:\s*/);
241                         if ( style.length == 2 )
242                                 this.style[ style[0] ] = style[1];
243                 }
244         };
245         
246         DOMElement.prototype = extend( new DOMNode(), {
247                 get nodeName(){
248                         return this.tagName.toUpperCase();
249                 },
250                 get tagName(){
251                         return this._dom.getTagName();
252                 },
253                 toString: function(){
254                         return "<" + this.tagName + (this.id ? "#" + this.id : "" ) + ">";
255                 },
256                 valueOf: function(){
257                         var ret = "<" + this.tagName, attr = this.attributes;
258                         
259                         for ( var i in attr )
260                                 ret += " " + i + "='" + attr[i] + "'";
261                                 
262                         if ( this.childNodes.length || this.nodeName == "SCRIPT" )
263                                 ret += ">" + this.childNodes.valueOf() + 
264                                         "</" + this.tagName + ">";
265                         else
266                                 ret += "/>";
267                         
268                         return ret;
269                 },
270                 
271                 get attributes(){
272                         var attr = {}, attrs = this._dom.getAttributes();
273                         
274                         for ( var i = 0; i < attrs.getLength(); i++ )
275                                 attr[ attrs.item(i).nodeName ] = attrs.item(i).nodeValue;
276                                 
277                         return attr;
278                 },
279                 
280                 get innerHTML(){
281                         return this.childNodes.valueOf();       
282                 },
283                 set innerHTML(html){
284                         html = html.replace(/<\/?([A-Z]+)/g, function(m){
285                                 return m.toLowerCase();
286                         });
287                         
288                         var nodes = this.ownerDocument.importNode(
289                                 new DOMDocument( new java.io.ByteArrayInputStream(
290                                         (new java.lang.String("<wrap>" + html + "</wrap>"))
291                                                 .getBytes("UTF8"))).documentElement, true).childNodes;
292                                 
293                         while (this.firstChild)
294                                 this.removeChild( this.firstChild );
295                         
296                         for ( var i = 0; i < nodes.length; i++ )
297                                 this.appendChild( nodes[i] );
298                 },
299                 
300                 get textContent(){
301                         return nav(this.childNodes);
302                         
303                         function nav(nodes){
304                                 var str = "";
305                                 for ( var i = 0; i < nodes.length; i++ )
306                                         if ( nodes[i].nodeType == 3 )
307                                                 str += nodes[i].nodeValue;
308                                         else if ( nodes[i].nodeType == 1 )
309                                                 str += nav(nodes[i].childNodes);
310                                 return str;
311                         }
312                 },
313                 set textContent(text){
314                         while (this.firstChild)
315                                 this.removeChild( this.firstChild );
316                         this.appendChild( this.ownerDocument.createTextNode(text));
317                 },
318                 
319                 style: {},
320                 clientHeight: 0,
321                 clientWidth: 0,
322                 offsetHeight: 0,
323                 offsetWidth: 0,
324                 
325                 get disabled() {
326                         var val = this.getAttribute("disabled");
327                         return val != "false" && !!val;
328                 },
329                 set disabled(val) { return this.setAttribute("disabled",val); },
330                 
331                 get checked() {
332                         var val = this.getAttribute("checked");
333                         return val != "false" && !!val;
334                 },
335                 set checked(val) { return this.setAttribute("checked",val); },
336                 
337                 get selected() {
338                         if ( !this._selectDone ) {
339                                 this._selectDone = true;
340                                 
341                                 if ( this.nodeName == "OPTION" && !this.parentNode.getAttribute("multiple") ) {
342                                         var opt = this.parentNode.getElementsByTagName("option");
343                                         
344                                         if ( this == opt[0] ) {
345                                                 var select = true;
346                                                 
347                                                 for ( var i = 1; i < opt.length; i++ )
348                                                         if ( opt[i].selected ) {
349                                                                 select = false;
350                                                                 break;
351                                                         }
352                                                         
353                                                 if ( select )
354                                                         this.selected = true;
355                                         }
356                                 }
357                         }
358                         
359                         var val = this.getAttribute("selected");
360                         return val != "false" && !!val;
361                 },
362                 set selected(val) { return this.setAttribute("selected",val); },
363
364                 get className() { return this.getAttribute("class") || ""; },
365                 set className(val) {
366                         return this.setAttribute("class",
367                                 val.replace(/(^\s*|\s*$)/g,""));
368                 },
369                 
370                 get type() { return this.getAttribute("type") || ""; },
371                 set type(val) { return this.setAttribute("type",val); },
372                 
373                 get value() { return this.getAttribute("value") || ""; },
374                 set value(val) { return this.setAttribute("value",val); },
375                 
376                 get src() { return this.getAttribute("src") || ""; },
377                 set src(val) { return this.setAttribute("src",val); },
378                 
379                 get id() { return this.getAttribute("id") || ""; },
380                 set id(val) { return this.setAttribute("id",val); },
381                 
382                 getAttribute: function(name){
383                         return this._dom.hasAttribute(name) ?
384                                 new String( this._dom.getAttribute(name) ) :
385                                 null;
386                 },
387                 setAttribute: function(name,value){
388                         this._dom.setAttribute(name,value);
389                 },
390                 removeAttribute: function(name){
391                         this._dom.removeAttribute(name);
392                 },
393                 
394                 get childNodes(){
395                         return new DOMNodeList( this._dom.getChildNodes() );
396                 },
397                 get firstChild(){
398                         return makeNode( this._dom.getFirstChild() );
399                 },
400                 get lastChild(){
401                         return makeNode( this._dom.getLastChild() );
402                 },
403                 appendChild: function(node){
404                         this._dom.appendChild( node._dom );
405                 },
406                 insertBefore: function(node,before){
407                         this._dom.insertBefore( node._dom, before ? before._dom : before );
408                 },
409                 removeChild: function(node){
410                         this._dom.removeChild( node._dom );
411                 },
412
413                 getElementsByTagName: DOMDocument.prototype.getElementsByTagName,
414                 addEventListener: function(){},
415                 removeEventListener: function(){},
416                 click: function(){},
417                 submit: function(){},
418                 focus: function(){},
419                 blur: function(){},
420                 get elements(){
421                         return this.getElementsByTagName("*");
422                 },
423                 get contentWindow(){
424                         return this.nodeName == "IFRAME" ? {
425                                 document: this.contentDocument
426                         } : null;
427                 },
428                 get contentDocument(){
429                         if ( this.nodeName == "IFRAME" ) {
430                                 if ( !this._doc )
431                                         this._doc = new DOMDocument(
432                                                 new java.io.ByteArrayInputStream((new java.lang.String(
433                                                 "<html><head><title></title></head><body></body></html>"))
434                                                 .getBytes("UTF8")));
435                                 return this._doc;
436                         } else
437                                 return null;
438                 }
439         });
440         
441         // Helper method for extending one object with another
442         
443         function extend(a,b) {
444                 for ( var i in b ) {
445                         var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);
446                         
447                         if ( g || s ) {
448                                 if ( g )
449                                         a.__defineGetter__(i, g);
450                                 if ( s )
451                                         a.__defineSetter__(i, s);
452                         } else
453                                 a[i] = b[i];
454                 }
455                 return a;
456         }
457         
458         // Helper method for generating the right
459         // DOM objects based upon the type
460         
461         var obj_nodes = new java.util.HashMap();
462         
463         function makeNode(node){
464                 if ( node ) {
465                         if ( !obj_nodes.containsKey( node ) )
466                                 obj_nodes.put( node, node.getNodeType() == 
467                                         Packages.org.w3c.dom.Node.ELEMENT_NODE ?
468                                                 new DOMElement( node ) : new DOMNode( node ) );
469                         
470                         return obj_nodes.get(node);
471                 } else
472                         return null;
473         }
474         
475         // XMLHttpRequest
476         // Originally implemented by Yehuda Katz
477
478         window.XMLHttpRequest = function(){
479                 this.headers = {};
480                 this.responseHeaders = {};
481         };
482         
483         XMLHttpRequest.prototype = {
484                 open: function(method, url, async, user, password){ 
485                         this.readyState = 1;
486                         if (async)
487                                 this.async = true;
488                         this.method = method || "GET";
489                         this.url = url;
490                         this.onreadystatechange();
491                 },
492                 setRequestHeader: function(header, value){
493                         this.headers[header] = value;
494                 },
495                 getResponseHeader: function(header){ },
496                 send: function(data){
497                         var self = this;
498                         
499                         function makeRequest(){
500                                 var url = new java.net.URL(curLocation, self.url),
501                                         connection = url.openConnection();
502                                 
503                                 // Add headers to Java connection
504                                 for (var header in self.headers)
505                                         connection.addRequestProperty(header, self.headers[header]);
506                         
507                                 connection.connect();
508                                 
509                                 // Stick the response headers into responseHeaders
510                                 for (var i=0; ; i++) { 
511                                         var headerName = connection.getHeaderFieldKey(i); 
512                                         var headerValue = connection.getHeaderField(i); 
513                                         if (!headerName && !headerValue) break; 
514                                         if (headerName)
515                                                 self.responseHeaders[headerName] = headerValue;
516                                 }
517                                 
518                                 self.readyState = 4;
519                                 self.status = parseInt(connection.responseCode);
520                                 self.statusText = connection.responseMessage;
521                                 
522                                 var stream = new java.io.InputStreamReader(
523                                                 connection.getInputStream()),
524                                         buffer = new java.io.BufferedReader(stream),
525                                         line;
526                                 
527                                 while ((line = buffer.readLine()) != null)
528                                         self.responseText += line;
529                                         
530                                 self.responseXML = null;
531                                 
532                                 if ( self.responseText.match(/^\s*</) ) {
533                                         try {
534                                                 self.responseXML = new DOMDocument(
535                                                         new java.io.ByteArrayInputStream(
536                                                                 (new java.lang.String(
537                                                                         self.responseText)).getBytes("UTF8")));
538                                         } catch(e) {}
539                                 }
540
541                                 self.onreadystatechange();
542                         }
543
544                         if (this.async)
545                                 (new java.lang.Thread(new java.lang.Runnable({
546                                         run: makeRequest
547                                 }))).start();
548                         else
549                                 makeRequest();
550                 },
551                 abort: function(){},
552                 onreadystatechange: function(){},
553                 getResponseHeader: function(header){
554                         if (this.readyState < 3)
555                                 throw new Error("INVALID_STATE_ERR");
556                         else {
557                                 var returnedHeaders = [];
558                                 for (var rHeader in this.responseHeaders) {
559                                         if (rHeader.match(new Regexp(header, "i")))
560                                                 returnedHeaders.push(this.responseHeaders[rHeader]);
561                                 }
562                         
563                                 if (returnedHeaders.length)
564                                         return returnedHeaders.join(", ");
565                         }
566                         
567                         return null;
568                 },
569                 getAllResponseHeaders: function(header){
570                         if (this.readyState < 3)
571                                 throw new Error("INVALID_STATE_ERR");
572                         else {
573                                 var returnedHeaders = [];
574                                 
575                                 for (var header in this.responseHeaders)
576                                         returnedHeaders.push( header + ": " + this.responseHeaders[header] );
577                                 
578                                 return returnedHeaders.join("\r\n");
579                         }
580                 },
581                 async: true,
582                 readyState: 0,
583                 responseText: "",
584                 status: 0
585         };
586 })();