Added a className tweak. All core and selector tests now pass.
[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         window.__defineSetter__("location", function(url){
21                 window.document = new DOMDocument(
22                         new Packages.org.xml.sax.InputSource(\r                  new java.io.InputStreamReader(
23                                 new java.io.FileInputStream(url))));
24         });
25         
26         window.__defineGetter__("location", function(url){
27                 return {
28                         get protocol(){
29                                 return "file:";
30                         }
31                 };
32         });
33         
34         // Timers
35
36         var timers = [];
37         
38         window.setTimeout = function(fn, time){
39                 var num;
40                 return num = setInterval(function(){
41                         fn();
42                         clearInterval(num);
43                 }, time);
44         };
45         
46         window.setInterval = function(fn, time){
47                 var num = timers.length;
48                 
49                 timers[num] = new java.lang.Thread(new java.lang.Runnable({
50                         run: function(){
51                                 while (true){
52                                         java.lang.Thread.currentThread().sleep(time);
53                                         fn();
54                                 }
55                         }
56                 }));
57                 
58                 timers[num].start();
59         
60                 return num;
61         };
62         
63         window.clearInterval = function(num){
64                 if ( timers[num] ) {
65                         timers[num].stop();
66                         delete timers[num];
67                 }
68         };
69         
70         // Window Events
71
72         window.addEventListener = function(){};
73         window.removeEventListener = function(){};
74         
75         // DOM Document
76         
77         window.DOMDocument = function(file){
78                 this._file = file;
79                 this._dom = Packages.javax.xml.parsers.
80                         DocumentBuilderFactory.newInstance()
81                                 .newDocumentBuilder().parse(file);
82                 
83                 if ( !obj_nodes.containsKey( this._dom ) )
84                         obj_nodes.put( this._dom, this );
85         };
86         
87         DOMDocument.prototype = {
88                 createTextNode: function(text){
89                         return makeNode( this._dom.createTextNode(
90                                 text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")) );
91                 },
92                 createElement: function(name){
93                         return makeNode( this._dom.createElement(name.toLowerCase()) );
94                 },
95                 getElementsByTagName: function(name){
96                         return new DOMNodeList( this._dom.getElementsByTagName(
97                                 name.toLowerCase()) );
98                 },
99                 getElementById: function(id){
100                         var elems = this._dom.getElementsByTagName("*");
101                         
102                         for ( var i = 0; i < elems.length; i++ ) {
103                                 var elem = elems.item(i);
104                                 if ( elem.getAttribute("id") == id )
105                                         return makeNode(elem);
106                         }
107                         
108                         return null;
109                 },
110                 get body(){
111                         return this.getElementsByTagName("body")[0];
112                 },
113                 get documentElement(){
114                         return makeNode( this._dom.getDocumentElement() );
115                 },
116                 get ownerDocument(){
117                         return null;
118                 },
119                 addEventListener: function(){},
120                 removeEventListener: function(){},
121                 get nodeName() {
122                         return "#document";
123                 },
124                 importNode: function(node, deep){
125                         return makeNode( this._dom.importNode(node._dom, deep) );
126                 },
127                 toString: function(){
128                         return "Document" + (typeof this._file == "string" ?
129                                 ": " + this._file : "");
130                 },
131                 
132                 get defaultView(){
133                         return {
134                                 getComputedStyle: function(elem){
135                                         return {
136                                                 getPropertyValue: function(prop){
137                                                         prop = prop.replace(/\-(\w)/g,function(m,c){
138                                                                 return c.toUpperCase();
139                                                         });
140                                                         var val = elem.style[prop];
141                                                         
142                                                         if ( prop == "opacity" && val == "" )
143                                                                 val = "1";
144                                                                 
145                                                         return val;
146                                                 }
147                                         };
148                                 }
149                         };
150                 }
151         };
152         
153         function getDocument(node){
154                 return obj_nodes.get(node);
155         }
156         
157         // DOM NodeList
158         
159         window.DOMNodeList = function(list){
160                 this._dom = list;
161                 this.length = list.getLength();
162                 
163                 for ( var i = 0; i < this.length; i++ ) {
164                         var node = list.item(i);
165                         this[i] = makeNode( node );
166                 }
167         };
168         
169         DOMNodeList.prototype = {
170                 toString: function(){
171                         return "[ " +
172                                 Array.prototype.join.call( this, ", " ) + " ]";
173                 },
174                 valueOf: function(){
175                         return Array.prototype.map.call(
176                                 this, function(node){return node.valueOf();}).join('');
177                 }
178         };
179         
180         // DOM Node
181         
182         window.DOMNode = function(node){
183                 this._dom = node;
184         };
185         
186         DOMNode.prototype = {
187                 get nodeType(){
188                         return this._dom.getNodeType();
189                 },
190                 get nodeValue(){
191                         return this._dom.getNodeValue();
192                 },
193                 get nodeName() {
194                         return this._dom.getNodeName();
195                 },
196                 cloneNode: function(deep){
197                         return makeNode( this._dom.cloneNode(deep) );
198                 },
199                 get ownerDocument(){
200                         return getDocument( this._dom.ownerDocument );
201                 },
202                 get documentElement(){
203                         return makeNode( this._dom.documentElement );
204                 },
205                 get parentNode() {
206                         return makeNode( this._dom.getParentNode() );
207                 },
208                 get nextSibling() {
209                         return makeNode( this._dom.getNextSibling() );
210                 },
211                 get previousSibling() {
212                         return makeNode( this._dom.getPreviousSibling() );
213                 },
214                 toString: function(){
215                         return '"' + this.nodeValue + '"';
216                 },
217                 valueOf: function(){
218                         return this.nodeValue;
219                 }
220         };
221
222         // DOM Element
223
224         window.DOMElement = function(elem){
225                 this._dom = elem;
226                 this.style = {
227                         get opacity(){ return this._opacity; },
228                         set opacity(val){ this._opacity = val + ""; }
229                 };
230                 
231                 // Load CSS info
232                 var styles = (this.getAttribute("style") || "").split(/\s*;\s*/);
233                 
234                 for ( var i = 0; i < styles.length; i++ ) {
235                         var style = styles[i].split(/\s*:\s*/);
236                         if ( style.length == 2 )
237                                 this.style[ style[0] ] = style[1];
238                 }
239         };
240         
241         DOMElement.prototype = extend( new DOMNode(), {
242                 get nodeName(){
243                         return this.tagName.toUpperCase();
244                 },
245                 get tagName(){
246                         return this._dom.getTagName();
247                 },
248                 toString: function(){
249                         return "<" + this.tagName + (this.id ? "#" + this.id : "" ) + ">";
250                 },
251                 valueOf: function(){
252                         var ret = "<" + this.tagName, attr = this.attributes;
253                         
254                         for ( var i in attr )
255                                 ret += " " + i + "='" + attr[i] + "'";
256                                 
257                         if ( this.childNodes.length || this.nodeName == "SCRIPT" )
258                                 ret += ">" + this.childNodes.valueOf() + 
259                                         "</" + this.tagName + ">";
260                         else
261                                 ret += "/>";
262                         
263                         return ret;
264                 },
265                 
266                 get attributes(){
267                         var attr = {}, attrs = this._dom.getAttributes();
268                         
269                         for ( var i = 0; i < attrs.getLength(); i++ )
270                                 attr[ attrs.item(i).nodeName ] = attrs.item(i).nodeValue;
271                                 
272                         return attr;
273                 },
274                 
275                 get innerHTML(){
276                         return this.childNodes.valueOf();       
277                 },
278                 set innerHTML(html){
279                         html = html.replace(/<\/?([A-Z]+)/g, function(m){
280                                 return m.toLowerCase();
281                         });
282                         
283                         var nodes = this.ownerDocument.importNode(
284                                 new DOMDocument( new java.io.ByteArrayInputStream(
285                                         (new java.lang.String("<wrap>" + html + "</wrap>"))
286                                                 .getBytes("UTF8"))).documentElement, true).childNodes;
287                                 
288                         while (this.firstChild)
289                                 this.removeChild( this.firstChild );
290                         
291                         for ( var i = 0; i < nodes.length; i++ )
292                                 this.appendChild( nodes[i] );
293                 },
294                 
295                 get textContent(){
296                         return nav(this.childNodes);
297                         
298                         function nav(nodes){
299                                 var str = "";
300                                 for ( var i = 0; i < nodes.length; i++ )
301                                         if ( nodes[i].nodeType == 3 )
302                                                 str += nodes[i].nodeValue;
303                                         else if ( nodes[i].nodeType == 1 )
304                                                 str += nav(nodes[i].childNodes);
305                                 return str;
306                         }
307                 },
308                 set textContent(text){
309                         while (this.firstChild)
310                                 this.removeChild( this.firstChild );
311                         this.appendChild( this.ownerDocument.createTextNode(text));
312                 },
313                 
314                 style: {},
315                 clientHeight: 0,
316                 clientWidth: 0,
317                 offsetHeight: 0,
318                 offsetWidth: 0,
319                 
320                 get disabled() {
321                         var val = this.getAttribute("disabled");
322                         return val != "false" && !!val;
323                 },
324                 set disabled(val) { return this.setAttribute("disabled",val); },
325                 
326                 get checked() {
327                         var val = this.getAttribute("checked");
328                         return val != "false" && !!val;
329                 },
330                 set checked(val) { return this.setAttribute("checked",val); },
331                 
332                 get selected() {
333                         if ( !this._selectDone ) {
334                                 this._selectDone = true;
335                                 
336                                 if ( this.nodeName == "OPTION" && !this.parentNode.getAttribute("multiple") ) {
337                                         var opt = this.parentNode.getElementsByTagName("option");
338                                         
339                                         if ( this == opt[0] ) {
340                                                 var select = true;
341                                                 
342                                                 for ( var i = 1; i < opt.length; i++ )
343                                                         if ( opt[i].selected ) {
344                                                                 select = false;
345                                                                 break;
346                                                         }
347                                                         
348                                                 if ( select )
349                                                         this.selected = true;
350                                         }
351                                 }
352                         }
353                         
354                         var val = this.getAttribute("selected");
355                         return val != "false" && !!val;
356                 },
357                 set selected(val) { return this.setAttribute("selected",val); },
358
359                 get className() { return this.getAttribute("class") || ""; },
360                 set className(val) {
361                         return this.setAttribute("class",
362                                 val.replace(/(^\s*|\s*$)/g,""));
363                 },
364                 
365                 get type() { return this.getAttribute("type") || ""; },
366                 set type(val) { return this.setAttribute("type",val); },
367                 
368                 get value() { return this.getAttribute("value") || ""; },
369                 set value(val) { return this.setAttribute("value",val); },
370                 
371                 get src() { return this.getAttribute("src") || ""; },
372                 set src(val) { return this.setAttribute("src",val); },
373                 
374                 get id() { return this.getAttribute("id") || ""; },
375                 set id(val) { return this.setAttribute("id",val); },
376                 
377                 getAttribute: function(name){
378                         return this._dom.hasAttribute(name) ?
379                                 new String( this._dom.getAttribute(name) ) :
380                                 null;
381                 },
382                 setAttribute: function(name,value){
383                         this._dom.setAttribute(name,value);
384                 },
385                 removeAttribute: function(name){
386                         this._dom.removeAttribute(name);
387                 },
388                 
389                 get childNodes(){
390                         return new DOMNodeList( this._dom.getChildNodes() );
391                 },
392                 get firstChild(){
393                         return makeNode( this._dom.getFirstChild() );
394                 },
395                 get lastChild(){
396                         return makeNode( this._dom.getLastChild() );
397                 },
398                 appendChild: function(node){
399                         this._dom.appendChild( node._dom );
400                 },
401                 insertBefore: function(node,before){
402                         this._dom.insertBefore( node._dom, before ? before._dom : before );
403                 },
404                 removeChild: function(node){
405                         this._dom.removeChild( node._dom );
406                 },
407
408                 getElementsByTagName: DOMDocument.prototype.getElementsByTagName,
409                 addEventListener: function(){},
410                 removeEventListener: function(){},
411                 click: function(){},
412                 submit: function(){},
413                 focus: function(){},
414                 blur: function(){},
415                 get elements(){
416                         return this.getElementsByTagName("*");
417                 },
418                 get contentWindow(){
419                         return this.nodeName == "IFRAME" ? {
420                                 document: this.contentDocument
421                         } : null;
422                 },
423                 get contentDocument(){
424                         if ( this.nodeName == "IFRAME" ) {
425                                 if ( !this._doc )
426                                         this._doc = new DOMDocument(
427                                                 new java.io.ByteArrayInputStream((new java.lang.String(
428                                                 "<html><head><title></title></head><body></body></html>"))
429                                                 .getBytes("UTF8")));
430                                 return this._doc;
431                         } else
432                                 return null;
433                 }
434         });
435         
436         // Helper method for extending one object with another
437         
438         function extend(a,b) {
439                 for ( var i in b ) {
440                         var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);
441                         
442                         if ( g || s ) {
443                                 if ( g )
444                                         a.__defineGetter__(i, g);
445                                 if ( s )
446                                         a.__defineSetter__(i, s);
447                         } else
448                                 a[i] = b[i];
449                 }
450                 return a;
451         }
452         
453         // Helper method for generating the right
454         // DOM objects based upon the type
455         
456         var obj_nodes = new java.util.HashMap();
457         
458         function makeNode(node){
459                 if ( node ) {
460                         if ( !obj_nodes.containsKey( node ) )
461                                 obj_nodes.put( node, node.getNodeType() == 
462                                         Packages.org.w3c.dom.Node.ELEMENT_NODE ?
463                                                 new DOMElement( node ) : new DOMNode( node ) );
464                         
465                         return obj_nodes.get(node);
466                 } else
467                         return null;
468         }
469         
470         // XMLHttpRequest
471
472         window.XMLHttpRequest = function(){ };
473         
474         XMLHttpRequest.prototype = {
475                 open: function(){ },
476                 setRequestHeader: function(){ },
477                 getResponseHeader: function(){ },
478                 readyState: 0,
479                 responseText: "",
480                 responseXML: {},
481                 status: 0
482         };
483 })();