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