]> dev.renevier.net Git - syp.git/blob - openlayers/tests/auto-tests.html
fixes notices
[syp.git] / openlayers / tests / auto-tests.html
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
2 <html><head>
3 <meta http-equiv="refresh" content="1200" />
4 <title> Run the testsuite</title>
5 <noscript>Javascript is disabled in your browser. This page cannot be displayed correctly without Javascript. Sorry. <br/> If you want to view this page, please change your browser settings so that Javascript is enabled.</noscript>
6 <!--
7 Test.AnotherWay version 0.5
8
9 Copyright (c) 2005 Artem Khodush, http://straytree.org
10
11 Permission is hereby granted, free of charge, to any person obtaining
12 a copy of this software and associated documentation files (the
13 "Software"), to deal in the Software without restriction, including
14 without limitation the rights to use, copy, modify, merge, publish,
15 distribute, sublicense, and/or sell copies of the Software, and to
16 permit persons to whom the Software is furnished to do so, subject to
17 the following conditions:
18
19 The above copyright notice and this permission notice shall be
20 included in all copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 -->
30 <style type="text/css">
31 * { padding: 0; margin: 0; }
32 html { height: 99%; }
33 body { height: 98%; font: normal normal 10pt sans-serif }
34 #col1 {  float: left; width: 27em; margin: 0 0 0 1em; overflow: visible; }
35 #col2 {  position: relative; height: 98%; margin: 0 0.5em 0 28em; }
36 #col1_header { margin-top: 0.5em; }
37 #scroller { height: 400px; overflow: auto;}
38 #testtable { margin: 0 0 2em 0; width: 97%; }
39 #run_buttons { margin-bottom: 4em; }
40
41 #right_header { padding-top: 0.8em; }
42 #results_count { float: left; }
43 .active_tab                     { float: right; padding: 0 1em 0.2em 1em; background: #0af; border: 1px solid #048; border-bottom: none; cursor: pointer; cursor: hand;
44                                          position: relative; top: -0.2em; }
45 .inactive_tab                   { float: right; padding: 0 1em 0 1em; background: #9bb; color: #444; border: 1px solid #9bb; border-bottom: none; cursor: pointer; cursor: hand; }
46 .inactive_mouseover_tab         { float: right; padding: 0 1em 0 1em; background: #9bb; color: #062; border: 1px solid #062; border-bottom: none; cursor: pointer; cursor: hand; }
47
48 #right_frame { overflow: auto; position: relative; top: -0.2em; clear: right; height: 95%; border: 1px solid #048; }
49
50 #debug { display: none; }
51 #debug p { margin: 2px 0 0 5em; text-indent: -4.8em; }
52
53 #error { display: none; color: #c22; }
54
55 #results p { margin: 0 0 2px 0; }
56 /* cursor indicating that detailed results may be expanded/contracted */
57 #results p.badtest { cursor: text; }
58 #results p.ok, #results p.fail { cursor: pointer; cursor: hand; }
59
60 /* colored squares in the results window at the left of test page names */
61 #results p.ok .bullet { background: #6d6; }
62 #results p.fail .bullet { background:  #d46; }
63 #results p.badtest .bullet { background: #ea3; }
64 #results p.loading .bullet { background: #48f; }
65 #results p.running .bullet { background: #26e; }
66 #results p.waiting .bullet { background: #04d; }
67 /* highlight in the results line */
68 #results p .warning { background: #ffc; }
69
70 /* layout of the detailed results */
71 .result_detail { padding-left: 3em; }
72 .result_exception_detail { padding-left: 4em; }
73 .result_exception_stack_detail { padding-left: 5em;  }
74 .result_micro_detail { padding-left: 6em; }
75 /* colouring in the detailed results */
76 .result_detail .fail, .result_exception_detail .fail,  .result_micro_detail .fail { background: #ffd8d8; }
77
78 /* "start recording" controls*/
79 #record_div { margin-top: 3em; }
80 #record_div p { margin-bottom: 0.5em; }
81 #record_select { width: 88%; }
82 #record_input { width: 53%; }
83 </style>
84 <script type="text/javascript">
85 <!--
86
87 function report_results() {
88     req = false;
89     // branch for native XMLHttpRequest object
90     if(window.XMLHttpRequest && !(window.ActiveXObject)) {
91         try {
92             req = new XMLHttpRequest();
93         } catch(e) {
94             req = false;
95         }
96     // branch for IE/Windows ActiveX version
97     } else if(window.ActiveXObject) {
98         try {
99             req = new ActiveXObject("Msxml2.XMLHTTP");
100         } catch(e) {
101             try {
102                 req = new ActiveXObject("Microsoft.XMLHTTP");
103             } catch(e) {
104                 req = false;
105             }
106         }
107     } 
108     req.open("POST", "/test/results.cgi");
109     req.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded');
110     var results = document.getElementById('total').innerHTML;
111     var test_text = "";
112     if (results.match("fail")) {
113         test_text = document.getElementById("results").innerHTML;
114     }    
115     req.send("results="+escape(results)+"&test_text="+escape(test_text));
116 }
117
118 if( typeof( Test )=="undefined" ) {
119         Test={};
120 }
121 Test.AnotherWay={};
122
123 Test.AnotherWay._g_test_iframe=null; // frame where to load test pages
124 Test.AnotherWay._g_test_frame_no_clear=false; // true - leave last page displayed after tests end
125 Test.AnotherWay._g_test_page_urls=[]; // array of: { url: url, convention: "anotherway" or "jsan" }
126 Test.AnotherWay._g_test_object_for_jsan=null; // test object for filling by tests that adhere to jsan Test.Simple calling convention
127 Test.AnotherWay._g_pages_to_run=null; // list of pages to run automatically after loading
128 Test.AnotherWay._g_run_on_main_load=false; // special handling for run_pages_to_run when it might be called before onload or before list of test pages is known.
129 Test.AnotherWay._g_run_on_list_load=false;
130 Test.AnotherWay._g_main_loaded=false;
131
132 Test.AnotherWay._run_pages_to_run=function( called_from_outside )
133 {
134         if( !Test.AnotherWay._g_main_loaded ) {
135                 Test.AnotherWay._g_run_on_main_load=true;
136         }else {
137                 var a_pages=Test.AnotherWay._g_pages_to_run;
138                 if( a_pages=="all" ) {
139                         for( var i=0; i<Test.AnotherWay._g_test_page_urls.length; ++i ) {
140                                 Test.AnotherWay._run_test_page( "test"+i );
141                         }
142                 }else if( a_pages!=null ) {
143                         for( var run_i=0; run_i<a_pages.length; ++run_i ) {
144                                 var run_page=a_pages[run_i];
145                                 var found=false;
146                                 for( var all_i=0; all_i<Test.AnotherWay._g_test_page_urls.length; ++all_i ) {
147                                         if( run_page==Test.AnotherWay._g_test_page_urls[all_i].url ) {
148                                                 Test.AnotherWay._run_test_page( "test"+all_i, called_from_outside );
149                                                 found=true;
150                                                 break;
151                                         }
152                                 }
153                                 if( !found ) {
154                                         Test.AnotherWay._show_error( "page specified to run is not found in the page list: "+run_page );
155                                         break;
156                                 }
157                         }
158                 }
159         }
160 }
161
162 Test.AnotherWay._add_test_page_url=function( test_url, convention )
163 {
164         var table=document.getElementById( "testtable" );
165         var record_select=document.getElementById( "record_select" );
166         var index=Test.AnotherWay._g_test_page_urls.length;
167
168         // trim spaces.
169         if( test_url.match( "^(\\s*)(.*\\S)(\\s*)$" ) ) {
170                 test_url=RegExp.$2;
171         }
172
173         Test.AnotherWay._g_test_page_urls[index]={ url: test_url, convention: convention };
174         var row=table.insertRow( -1 );
175
176         var cell;
177         var cell_child;
178         cell=row.insertCell( -1 );
179         cell_child=document.createElement( "input" );
180         cell_child.type="checkbox";
181         cell_child.id="checkbox"+index;
182     cell_child.checked='checked';
183     cell_child.defaultChecked='checked';
184         cell.appendChild( cell_child );
185
186         cell=row.insertCell( -1 );
187         cell.setAttribute( "width", "75%" );
188         cell.appendChild( document.createTextNode( test_url ) );
189
190         cell=row.insertCell( -1 );
191         cell_child=document.createElement( "input" );
192         cell_child.type="button";
193         cell_child.id="test"+index;
194         cell_child.value=" run ";
195         cell_child.onclick=Test.AnotherWay._run_one_onclick;
196         cell.appendChild( cell_child );
197
198         cell=row.insertCell( -1 );
199         cell.setAttribute( "width", "8em" );
200         cell_child=document.createElement( "span" );
201         cell.appendChild( cell_child );
202
203         var option=document.createElement( "option" );
204         option.appendChild( document.createTextNode( test_url ) );
205         record_select.appendChild( option );
206 }
207 Test.AnotherWay._show_error=function( msg )
208 {
209         var error_div=document.getElementById( "error" );
210         error_div.innerHTML="";
211         error_div.appendChild( document.createTextNode( msg ) );
212         error_div.style.display="block";
213 }
214
215 // read urls from the list in the html file inside the list_iframe
216 // fill on-screen list with urls and "run" buttons, and fill the g_test_page_urls object.
217 Test.AnotherWay._list_iframe_onload=function()
218 {
219         if( window.frames.list_iframe!=null && window.frames.list_iframe.location!="" && window.frames.list_iframe.location!="about:blank" ) {
220                 var list_doc=window.frames.list_iframe.document;
221                 var list=list_doc.getElementById( "testlist" );
222                 if( list!=null ) {
223                         for( var i=0; i<list.childNodes.length; ++i ) {
224                                 var item=list.childNodes[i];
225                                 if( item.nodeName=="LI" || item.nodeName=="li" ) {
226                                         var convention="anotherway";
227                                         if( Test.AnotherWay._get_css_class( item )=="jsan" ) {
228                                                 convention="jsan";
229                                         }
230                                         Test.AnotherWay._add_test_page_url( item.innerHTML, convention );
231                                 }
232                         }
233                         if( Test.AnotherWay._g_run_on_list_load ) {
234                                 Test.AnotherWay._g_run_on_list_load=false;
235                                 Test.AnotherWay._run_pages_to_run();
236                         }
237                 }else {
238                         Test.AnotherWay._show_error( "no list with id 'testlist' in a list file "+window.frames.list_iframe.location );
239                 }
240         }
241 }
242
243 Test.AnotherWay._map_checkboxes=function( f )
244 {
245         var table=document.getElementById( "testtable" );
246         var checks=table.getElementsByTagName( "INPUT" );
247         for( var i=0; i<checks.length; ++i ) {
248                 if( checks[i].type=="checkbox" && checks[i].id.match( /^checkbox(\d+)$/ ) ) {
249                         f( checks[i], RegExp.$1 );
250                 }
251         }
252 }
253 Test.AnotherWay._run_all_onclick=function()
254 {
255         Test.AnotherWay._map_checkboxes( function( c, id ) { Test.AnotherWay._run_test_page( "test"+id ); } );
256 }
257 Test.AnotherWay._run_selected_onclick=function()
258 {
259         Test.AnotherWay._map_checkboxes( function( c, id ) { if( c.checked ) Test.AnotherWay._run_test_page( "test"+id ); } );
260 }
261 Test.AnotherWay._unselect_all_onclick=function()
262 {
263         Test.AnotherWay._map_checkboxes( function( c, id ) { c.checked=false; } );
264 }
265 Test.AnotherWay._run_one_onclick=function()
266 {
267         Test.AnotherWay._run_test_page( this.id );
268 }
269
270 // construct an object that will gather results of running one test function
271 Test.AnotherWay._test_object_t=function( fun_name )
272 {
273         this.name=fun_name; // name of the test function
274         this.n_plan=null; // planned number of assertions
275         this.n_ok=0; // # of ok assertions
276         this.n_fail=0; // # of failed assertions
277         this.exception=""; // if the function throwed an exception, it's its message
278         this.exception_stack=[]; // strings: function call stack from the exception
279         this.assertions=[]; // assertion results: array of { ok: 1 or 0, name: string }
280         this.wait_result_milliseconds=0; // how long to wait before collecting results from the test
281         this.second_wait_msg=null; // <p> status message (in addition to the page wait_msg)
282         this.delay_actions=[]; // array of actions to be perfomed after the test function returns
283                                 //      action : { acton_kind: "call" | "window" | "replay"
284                                 //                              when "call":            { call_fn call_delay_milliseconds } call_fn takes nothing
285                                 //                              when "window" :         { wnd_url wnd_wnd wnd_fn wnd_timeout_milliseconds wnd_dont_close } wnd_fn takes wnd
286                                 //                              wnen "replay" :         { replay_wnd replay_events replay_event_i replay_checkpoints } checkpoint_fn takes this, wnd
287                                 //      }
288         this.delay_action_i=null; // index of delay action currently being performed
289         this.delay_prev_timer_time=0;   // for counting time while performing delay_actions
290         this.delay_current_milliseconds_left=0; // time left before the next action, runs down
291         this.delay_total_milliseconds_left=0;   // for indication: total estimated time for all actions, runs up and down
292 }
293
294 Test.AnotherWay._test_object_t.prototype.ok=function( cond, name )
295 {
296         if( cond ) {
297                 ++this.n_ok;
298                 cond=1;
299         }else {
300                 ++this.n_fail;
301                 cond=0;
302         }
303         this.assertions.push( { ok: cond, name: name } );
304 }
305 Test.AnotherWay._test_object_t.prototype.fail=function( name )
306 {
307         this.ok( false, name );
308 }
309 Test.AnotherWay._test_object_t.prototype.plan=function( n )
310 {
311         this.n_plan=n;
312 }
313 Test.AnotherWay._test_object_t.prototype.wait_result=function( seconds )
314 {
315         this.wait_result_milliseconds=1000*seconds;
316 }
317 Test.AnotherWay._eq_fail_msg=function( path, what, expected, got )
318 {
319         return "eq: "+path+" "+what+" differ: got "+got+", but expected "+expected;
320 }
321 Test.AnotherWay._array_eq=function( expected, got, path, msg )
322 {
323         if( expected.length!=got.length ) {
324                 msg.msg=Test.AnotherWay._eq_fail_msg( path, "array length", expected.length, got.length );
325                 return false;
326         }
327         for( var i=0; i<expected.length; ++i ) {
328                 if( !Test.AnotherWay._thing_eq( expected[i], got[i], path+"["+i+"]", msg ) ) {
329                         return false;
330                 }
331         }
332         return true;
333 }
334 Test.AnotherWay._object_eq=function( expected, got, path, msg )
335 {
336         var v;
337         for( v in expected ) {
338                 if( ! (v in got) ) {
339                         msg.msg=Test.AnotherWay._eq_fail_msg( path+"."+v, "properties", expected[v], "undefined" );
340                         return false;
341                 }
342                 if( !Test.AnotherWay._thing_eq( expected[v], got[v], path+"."+v, msg ) ) {
343                         return false;
344                 }
345         }
346         for( v in got ) {
347                 if( ! (v in expected) ) {
348                         msg.msg=Test.AnotherWay._eq_fail_msg( path+"."+v, "properties", "undefined", got[v] );
349                         return false;
350                 }
351         }
352         return true;
353 }
354 Test.AnotherWay._constructor_name=function( x )
355 {
356         if( x==null ) {
357                 return "";
358         }
359         var s="unknown";
360         try {
361                 s=typeof( x.constructor );
362                 if( s!="unknown" ) {
363                         s=x.constructor.toString();
364                 }
365         }catch( e ) {
366                 s="unknown";
367         }
368         if( s=="unknown" ) {
369                 // hackish attempt to guess a type
370                 var is_array=true;
371                 var index=0;
372                 for( i in x ) {
373                         if( i!=index ) {
374                                 is_array=false;
375                         }
376                         ++index;
377                 }
378                 return is_array ? "Array" : "Object"; // for empty arrays/objects, this will be wrong half the time
379         }else if( s.match( /^\s*function\s+(\w+)\s*\(/ ) ) {
380                 return RegExp.$1;
381         }else {
382           var c = '';
383           switch(typeof x) {
384             case 'string':
385               c = 'String';
386               break;
387             case 'object':
388               c = 'Object';
389               break;
390             default:
391               c = '';
392           }
393                 return c;       }
394 }
395 Test.AnotherWay._is_array=function( x )
396 {
397         return Test.AnotherWay._constructor_name( x )=="Array";
398 }
399 Test.AnotherWay._is_value_type=function( x )
400 {
401         cn=Test.AnotherWay._constructor_name( x );
402         return cn=="Number" || cn=="String" || cn=="Boolean" || cn=="Date";
403 }
404 Test.AnotherWay._thing_eq=function( expected, got, path, msg )
405 {
406         if( expected==null && got==null ) {
407                 return true;
408         }else if( (expected==null && got!=null) || (expected!=null && got==null) ) {
409                 msg.msg=Test.AnotherWay._eq_fail_msg( path, "values", expected, got );
410                 return false;
411         }else {
412                 var expected_cn=Test.AnotherWay._constructor_name( expected );
413                 var got_cn=Test.AnotherWay._constructor_name( got );
414                 if( expected_cn!=got_cn ) {
415                         msg.msg=Test.AnotherWay._eq_fail_msg( path, "types", expected_cn, got_cn );
416                         return false;
417                 }else {
418                         if( Test.AnotherWay._is_array( expected ) ) {
419                                 return Test.AnotherWay._array_eq( expected, got, path, msg );
420                         }else if( Test.AnotherWay._is_value_type( expected ) ) {
421                                 if( expected!=got ) {
422                                         msg.msg=Test.AnotherWay._eq_fail_msg( path, "values", expected, got );
423                                         return false;
424                                 }else {
425                                         return true;
426                                 }
427                         }else { // just a plain object
428                                 return Test.AnotherWay._object_eq( expected, got, path, msg );
429                         }
430                 }
431         }
432 }
433 Test.AnotherWay._test_object_t.prototype.eq=function( got, expected, name )
434 {
435         var msg={};
436         if( Test.AnotherWay._thing_eq( expected, got, "", msg ) ) {
437                 this.ok( 1, name );
438         }else {
439                 this.fail( name+". "+msg.msg );
440         }
441 }
442 Test.AnotherWay._test_object_t.prototype.like=function( got, expected, name )
443 {
444         if( got.match( expected )!=null ) {
445                 this.ok( 1, name );
446         }else {
447                 this.fail( name+": got "+got+", but expected it to match: "+expected );
448         }
449 }
450 Test.AnotherWay._g_html_eq_span=null;
451 Test.AnotherWay._html_eq_string_to_node=function( string_or_node, what, msg )
452 {
453         if( string_or_node.nodeType!=null ) {
454                 string_or_node=Test.AnotherWay._html_eq_node_to_string( string_or_node ); // double trip - to make properties assigned in scripts available as html node attributes
455         }
456         if( Test.AnotherWay._g_html_eq_span==null ) {
457                 Test.AnotherWay._g_html_eq_span=document.createElement( "span" );
458         }
459         Test.AnotherWay._g_html_eq_span.innerHTML=string_or_node;
460         if( Test.AnotherWay._g_html_eq_span.childNodes.length!=1 ) {
461                 msg.msg="bad "+what+" html string given (should contain exactly one outermost element): "+string_or_node;
462         }
463         return Test.AnotherWay._g_html_eq_span.childNodes[0].cloneNode( true );
464 }
465 Test.AnotherWay._html_eq_node_to_string=function( node ) {
466         if( Test.AnotherWay._g_html_eq_span==null ) {
467                 Test.AnotherWay._g_html_eq_span=document.createElement( "span" );
468         }
469         Test.AnotherWay._g_html_eq_span.innerHTML="";
470         if( node.outerHTML!=null ) {
471                 Test.AnotherWay._g_html_eq_span.innerHTML=node.outerHTML;
472         }else {
473             var clone = node.cloneNode(true);
474             var node = Test.AnotherWay._g_html_eq_span;
475             if(node.ownerDocument && node.ownerDocument.importNode) {
476                 if(node.ownerDocument != clone.ownerDocument) {
477                     clone = node.ownerDocument.importNode(clone, true);
478                 }
479             }
480             node.appendChild(clone);
481         }
482         return Test.AnotherWay._g_html_eq_span.innerHTML;
483 }
484 Test.AnotherWay._html_eq_path_msg=function( path )
485 {
486         var msg="";
487         for( var i=0; i<path.length; ++i ) {
488                 msg+=" [node "+path[i].node;
489                 if( path[i].id!=null && path[i].id!="" ) {
490                         msg+=" id "+path[i].id;
491                 }else if( path[i].index!=null ) {
492                         msg+=" at index "+path[i].index;
493                 }
494                 msg+="] "
495         }
496         return msg;
497 }
498 Test.AnotherWay._html_eq_fail_msg=function( path, what, expected, got )
499 {
500         return Test.AnotherWay._html_eq_path_msg( path )+": "+what+" differ: got "+got+", but expected "+expected;
501 }
502 Test.AnotherWay._html_eq_remove_blank=function( text )
503 {
504         if( text==null ) {
505                 return "";
506         }else if( text.match( "^(\\s*)(.*\\S)(\\s*)$" ) ) {
507                 return RegExp.$2;
508         }else if( text.match( "\s*" ) ) {
509                 return "";
510         }
511         return text;
512 }
513 Test.AnotherWay._html_eq_remove_blank_nodes=function( node )
514 {
515         var to_remove=[];
516         for( var child=node.firstChild; child!=null; child=child.nextSibling ) {
517                 if( child.nodeType==3 ) {
518                         var value=Test.AnotherWay._html_eq_remove_blank( child.nodeValue );
519                         if( value=="" ) {
520                                 to_remove.push( child );
521                         }else {
522                                 child.nodeValue=value;
523                         }
524                 }
525         }
526         for( var i=0; i<to_remove.length; ++i ) {
527                 node.removeChild( to_remove[i] );
528         }
529 }
530 Test.AnotherWay._html_node_type_text=function( node_type )
531 {
532         if( node_type==1 ) {
533                 return "1 (html element)";
534         }else if( node_type==3 ) {
535                 return "3 (text)";
536         }else {
537                 return node_type;
538         }
539 }
540 Test.AnotherWay._html_eq_node=function( expected, got, path, msg, expected_loc_base, got_loc_base )
541 {
542         if( expected.nodeType!=got.nodeType ) {
543                 msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "node types", Test.AnotherWay._html_node_type_text( expected.nodeType ), Test.AnotherWay._html_node_type_text( got.nodeType ) );
544                 return false;
545         }else if( expected.nodeType==3 ) {
546                 if( expected.nodeValue!=got.nodeValue ) {
547                         msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "text", expected.nodeValue, got.nodeValue );
548                         return false;
549                 }
550         }else if( expected.nodeType==1 ) {
551                 if( expected.nodeName!=got.nodeName ) {
552                         msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "node names", expected.nodeName, got.nodeName );
553                         return false;
554                 }
555                 // compare attributes
556                 var expected_attrs={};
557                 var got_attrs={};
558                 var i;
559                 var a;
560                 for( i=0; i<expected.attributes.length; ++i ) {
561                         a=expected.attributes[i];
562                         if( a.specified ) {
563                                 expected_attrs[a.name]=1;
564                         }
565                 }
566                 for( i=0; i<got.attributes.length; ++i ) {
567                         a=got.attributes[i];
568                         if( a.specified ) {
569                                 got_attrs[a.name]=1;
570                         }
571                 }
572                 for( a in expected_attrs ) {
573                         if( ! (a in got_attrs) ) {
574                                 msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": attribute sets differ: expected attribute "+a+" is missing";
575                                 return false;
576                         }
577                 }
578                 for( a in got_attrs ) {
579                         if( ! (a in expected_attrs) ) {
580                                 msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": attribute sets differ: got extra attribute "+a;
581                                 return false;
582                         }
583                 }
584                 for( a in expected_attrs ) {
585                         var expected_value=expected.getAttribute( a );
586                         var got_value=got.getAttribute( a );
587                         if( typeof( expected_value )=="string" && typeof( got_value )=="string" ) {
588                                 expected_value=Test.AnotherWay._html_eq_remove_blank( expected_value );
589                                 got_value=Test.AnotherWay._html_eq_remove_blank( got_value );
590                                 var ok=expected_value==got_value;
591                                 if( !ok && (a=="href" || a=="HREF" )  ) { // try relative hrefs
592                                         var expected_relative_value=expected_value;
593                                         if( expected_loc_base!=null && expected_value.substring( 0, expected_loc_base.length )==expected_loc_base ) {
594                                                 expected_relative_value=expected_value.substring( expected_loc_base.length );
595                                         }
596                                         var got_relative_value=got_value;
597                                         if( got_loc_base!=null && got_value.substring( 0, got_loc_base.length )==got_loc_base ) {
598                                                 got_relative_value=got_value.substring( got_loc_base.length );
599                                         }
600                                         ok=expected_relative_value==got_relative_value;
601                                 }
602                                 if( !ok ) {
603                                         msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "attribute "+a+" values", expected_value, got_value );
604                                         return false;
605                                 }
606                         }else if( typeof( expected_value )=="function" && typeof( got_value )=="function" ) {
607                                 expected_value=expected_value.toString();
608                                 got_value=got_value.toString();
609                                 if( expected_value!=got_value ) {
610                                         msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "attribute "+a+" values", expected_value, got_value );
611                                         return false;
612                                 }
613                         }else {
614                                 var value_msg={};
615                                 if( !Test.AnotherWay._thing_eq( expected_value, got_value, "", value_msg ) ) {
616                                         msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": attribute "+a+" values differ: "+value_msg.msg;
617                                         return false;
618                                 }
619                         }
620                 }
621                 // compare child nodes
622                 Test.AnotherWay._html_eq_remove_blank_nodes( expected );
623                 Test.AnotherWay._html_eq_remove_blank_nodes( got );
624                 var expected_length=expected.childNodes.length;
625                 var got_length=got.childNodes.length;
626                 if( expected_length<got_length ) {
627                         msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": got "+(got_length-expected_length)+" extra child nodes";
628                         return false;
629                 }else if( expected_length>got_length ) {
630                         msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": expected "+(expected_length-got_length)+" more child nodes";
631                         return false;
632                 }else {
633                         for( i=0; i<expected_length; ++i ) {
634                                 var expected_node=expected.childNodes[i];
635                                 path.push( { node: expected_node.nodeName, id: expected_node.id, index: i } );
636                                 var eq=Test.AnotherWay._html_eq_node( expected_node, got.childNodes[i], path, msg, expected_loc_base, got_loc_base );
637                                 path.pop();
638                                 if( !eq ) {
639                                         return false;
640                                 }
641                         }
642                 }
643         }
644         return true;
645 }
646 Test.AnotherWay._html_eq_get_loc_base=function( node )
647 {
648         var loc_base=document.location;
649         if( node.ownerDocument!=null ) {
650                 loc_base=node.ownerDocument.location;
651         }
652         if( loc_base!=null ) {
653                 loc_base=loc_base.href;
654                 var slash_pos=loc_base.lastIndexOf( "/" );
655                 if( slash_pos!=-1 ) {
656                         loc_base=loc_base.substring( 0, slash_pos+1 );
657                 }
658         }
659         return loc_base;
660 }
661 Test.AnotherWay._test_object_t.prototype.html_eq=function( got, expected, name )
662 {
663         var msg={};
664         var expected_node=Test.AnotherWay._html_eq_string_to_node( expected, "expected", msg );
665         if( msg.msg!=null ) {
666                 this.fail( name+" html_eq: "+msg.msg );
667         }else {
668                 var got_node=Test.AnotherWay._html_eq_string_to_node( got, "got", msg );
669                 if( msg.msg!=null ) {
670                         this.fail( name+" html_eq: "+msg.msg );
671                 }else {
672                         var expected_loc_base=Test.AnotherWay._html_eq_get_loc_base( expected );
673                         var got_loc_base=Test.AnotherWay._html_eq_get_loc_base( got );
674                         if( Test.AnotherWay._html_eq_node( expected_node, got_node, [], msg, expected_loc_base, got_loc_base ) ) {
675                                 this.ok( 1, name );
676                         }else {
677                                 var msg=name+" html_eq "+msg.msg;
678                                 var expected_str=Test.AnotherWay._html_eq_node_to_string( expected_node );
679                                 var got_str=Test.AnotherWay._html_eq_node_to_string( got_node );
680                                 msg+=".\n got html: "+got_str;
681                                 msg+=".\n expected html: "+expected_str;
682                                 this.fail( msg );
683                         }
684                 }
685         }
686 }
687 Test.AnotherWay._debug_pane_print=function( msg )
688 {
689         var d=new Date();
690         var p=document.createElement( "p" );
691         p.appendChild( document.createTextNode( d.toLocaleTimeString()+" "+msg ) );
692         var debug_pane=document.getElementById( "debug" );
693         debug_pane.appendChild( p );
694         var debug_tab=document.getElementById( "debug_tab" );
695         var results_tab=document.getElementById( "results_tab" );
696         debug_tab.style.visibility="visible";
697         results_tab.style.visibility="visible";
698 }
699 Test.AnotherWay._test_object_t.prototype.debug_print=function( msg )
700 {
701         Test.AnotherWay._debug_pane_print( this.name+": "+msg );
702 }
703 Test.AnotherWay._test_object_t.prototype.delay_call=function()
704 {
705         var timeout_ms=200;
706         for( var i=0; i<arguments.length; ++i ) {
707                 if( typeof( arguments[i] )!="function" ) {
708                         timeout_ms=3000*arguments[i];
709                 }else {
710                         var action={ action_kind: "call", call_delay_milliseconds: timeout_ms, call_fn: arguments[i] };
711                         this.delay_total_milliseconds_left+=Test.AnotherWay._action_estimate_milliseconds( action );
712                         this.delay_actions.push( action );
713                 }
714         }
715 }
716 Test.AnotherWay._test_object_t.prototype.open_window=function( url, fn, timeout_seconds )
717 {
718         if( timeout_seconds==null ) {
719                 timeout_seconds=4;
720         }
721         var no_close=document.getElementById( "dont_close_test_windows" );
722         var action={ action_kind: "window", wnd_url: url.toString(), wnd_wnd: null, wnd_fn: fn, wnd_timeout_milliseconds: timeout_seconds*1000, wnd_no_close: no_close.checked };
723         this.delay_total_milliseconds_left+=Test.AnotherWay._action_estimate_milliseconds( action );
724         this.delay_actions.push( action );
725 }
726 Test.AnotherWay._test_object_t.prototype.replay_events=function( wnd, events )
727 {
728         if( Test.AnotherWay._g_no_record_msg!=null ) {
729                 this.fail( "replay_events: "+Test.AnotherWay._g_no_record_msg );
730         }else {
731                 var action={ action_kind: "replay", replay_wnd: wnd, replay_events: events.events, replay_event_i: null, replay_checkpoints: events.checkpoints };
732                 this.delay_total_milliseconds_left+=Test.AnotherWay._action_estimate_milliseconds( action );
733                 this.delay_actions.push( action );
734         }
735 }
736 Test.AnotherWay._action_estimate_milliseconds=function( action )
737 {
738         var ms=0;
739         if( action.action_kind=="call" ) {
740                 ms=action.call_delay_milliseconds;
741         }else if( action.action_kind=="window" ) {
742                 ms=0;
743         }else if( action.action_kind=="replay" ) {
744                 ms=0;
745                 for( var i=0; i<action.replay_events.length; ++i ) {
746                         ms+=action.replay_events[i]["time"]-0;
747                 }
748         }
749         return ms;
750 }
751
752 Test.AnotherWay._g_timeout_granularity=200;
753 Test.AnotherWay._g_tests_queue=[]; // vector of { url: string, test_objects : array of test_object_t, test_object_i: int, wait_msg: <p> object, loading_timeout_milliseconds: int, timeout_id: id }
754
755 // load one html page, schedule further processing
756 Test.AnotherWay._run_test_page=function( id, called_from_outside )
757 {
758         if( id.match( /^test(\d+)/ ) ) {
759                 id=RegExp.$1;
760                 Test.AnotherWay._g_tests_queue.push( {
761                         url: Test.AnotherWay._g_test_page_urls[id].url,
762                         convention: Test.AnotherWay._g_test_page_urls[id].convention,
763                         test_objects: []
764                         } );
765                 if( Test.AnotherWay._g_tests_queue.length==1 ) {
766                         if( !called_from_outside ) {
767                                 // Crap. Be careful stepping around.
768                                 // For Mozilla and Opera, when this file is included into the frameset page that is in another directory (and _g_outside_path_correction!=null)
769                                 // but the test pages are started from within it (by "run" buttons), then:
770                                 // depending on whether the page is the first one loaded into the test frame or not,
771                                 // the base url for relative test pages differs.
772                                 // Crap, like I said.
773                                 Test.AnotherWay._g_tests_queue[0].suppress_outside_path_correction=true;
774                         }
775                         Test.AnotherWay._start_loading_page();
776                 }
777         }
778 }
779 Test.AnotherWay._load_next_page=function()
780 {
781         Test.AnotherWay._g_tests_queue.splice( 0, 1 );
782         if( Test.AnotherWay._g_tests_queue.length>0 ) {
783                 Test.AnotherWay._start_loading_page();
784         }else {
785                 if( !Test.AnotherWay._g_test_frame_no_clear ) {
786                         Test.AnotherWay._g_test_iframe.location.replace( "about:blank" );
787                 }
788         report_results();
789     }
790 }
791 Test.AnotherWay._g_opera_path_correction=null; // ugly wart to support opera
792 Test.AnotherWay._g_outside_path_correction=null; // ugly wart to accomodate Opera and Mozilla, where relative url relates to the directory where the page that calls this function is located
793 Test.AnotherWay._set_iframe_location=function( iframe, loc, outside_path_correction )
794 {
795         // allow to load only locations with the same origin
796         var proto_end=loc.indexOf( "://" );
797         if( proto_end!=-1 ) { // otherwise, it's safe to assume (for Opera, Mozilla and IE ) that loc will be treated as relative
798                 var main_loc=window.location.href;
799                 var host_end=loc.substring( proto_end+3 ).indexOf( "/" );
800                 var ok=false;
801                 if( host_end!=-1 ) {
802                         var loc_origin=loc.substring( 0, proto_end+3+host_end+1 );
803                         if( main_loc.length>=loc_origin.length && main_loc.substring( 0, loc_origin.length )==loc_origin ) {
804                                 ok=true;
805                         }
806                 }
807                 if( !ok ) {
808                         return { msg: "test pages may have only urls with the same origin as "+main_loc };
809                 }
810         }
811         // opera cannot handle urls relative to file:// without assistance
812         if( window.opera!=null && window.location.protocol=="file:" && loc.indexOf( ":" )==-1 ) {
813                 var base=window.location.href;
814                 var q_pos=base.indexOf( "?" );
815                 if( q_pos!=-1 ) {
816                         base=base.substring( 0, q_pos );
817                 }
818                 var slash_pos=base.lastIndexOf( "/" );
819                 if( slash_pos!=-1 ) {
820                         base=base.substring( 0, slash_pos+1 );
821                         Test.AnotherWay._g_opera_path_correction=base;
822                         loc=base+loc;
823                 }
824         }
825         // if this function is called from another page, and if that page is in another directory, correction is needed
826         if( outside_path_correction!=null ) {
827                 var pos=loc.indexOf( outside_path_correction );
828                 if( pos==0 ) {
829                         loc=loc.substring( outside_path_correction.length+1 );
830                 }
831         }
832         if( iframe.location!=null ) {
833                 iframe.location.replace( loc );
834         }else {
835                 iframe.src=loc;
836         }
837         return {};
838 }
839 Test.AnotherWay._start_loading_page=function()
840 {
841         var test_page=Test.AnotherWay._g_tests_queue[0];
842         test_page.loading_timeout_milliseconds=20000;
843         test_page.timeout_id=setTimeout( Test.AnotherWay._loading_timeout, Test.AnotherWay._g_timeout_granularity );
844         test_page.wait_msg=Test.AnotherWay._print_counter_result( test_page.url, "loading...", test_page.loading_timeout_milliseconds, "loading" );
845         if( test_page.convention=="jsan" ) {
846                 // the tests in that page will run when it's loading, so the test object must be ready
847                 Test.AnotherWay._g_test_object_for_jsan=new Test.AnotherWay._test_object_t( test_page.url );
848         }
849         var outside_path_correction=null;
850         if( Test.AnotherWay._g_outside_path_correction!=null && !test_page.suppress_outside_path_correction ) {
851                 outside_path_correction=Test.AnotherWay._g_outside_path_correction;
852         }
853         var result=Test.AnotherWay._set_iframe_location( Test.AnotherWay._g_test_iframe, test_page.url, outside_path_correction );
854         if( result.msg!=null ) {
855                 Test.AnotherWay._unprint_result( test_page.wait_msg );
856                 Test.AnotherWay._print_result( test_page.url, result.msg, "badtest", null );
857                 Test.AnotherWay._load_next_page();
858         }
859 }
860
861 Test.AnotherWay._loading_timeout=function()
862 {
863         var test_page=Test.AnotherWay._g_tests_queue[0];
864         test_page.loading_timeout_milliseconds-=Test.AnotherWay._g_timeout_granularity;
865         if( test_page.loading_timeout_milliseconds>0 ) {
866                 Test.AnotherWay._update_msg_counter( test_page.wait_msg, (test_page.loading_timeout_milliseconds/1000).toFixed() );
867                 test_page.timeout_id=setTimeout( Test.AnotherWay._loading_timeout, Test.AnotherWay._g_timeout_granularity );
868         }else {
869                 Test.AnotherWay._unprint_result( test_page.wait_msg );
870                 Test.AnotherWay._print_result( test_page.url, "Unable to load test page. Timeout expired", "badtest", null );
871                 Test.AnotherWay._load_next_page();
872         }
873 }
874
875 Test.AnotherWay._strip_query_and_hash=function( s )
876 {
877         var i=s.lastIndexOf( "#" );
878         if( i!=-1 ) {
879                 s=s.substring( 0, i );
880         }
881         i=s.lastIndexOf( "?" );
882         if( i!=-1 ) {
883                 s=s.substring( 0, i );
884         }
885         return s;
886 }
887 Test.AnotherWay._is_url_loaded=function( url, wnd )
888 {
889         var loaded=false;
890         if( wnd!=null && wnd.location!=null ) {
891                 // after some popup blocker interference, location may behave strange..
892                 var location_s="";
893                 location_s+=wnd.location;
894                 if( location_s!="" ) {
895                         var pathname=wnd.location.pathname;
896                         var expected_url=url;
897                         var i=expected_url.lastIndexOf( "#" );
898                         if( i!=-1 ) {
899                                 expected_url=expected_url.substring( 0, i );
900                         }
901                         i=expected_url.lastIndexOf( "?" );
902                         if( i!=-1 ) {
903                                 expected_url=expected_url.substring( 0, i );
904                         }
905                         i=expected_url.lastIndexOf( "/" );
906                         if( i!=-1 && i!=expected_url.length-1 ) {
907                                 expected_url=expected_url.substring( i+1 );
908                         }
909                         i=pathname.indexOf( expected_url )
910                         if( wnd.location.href==url || (i!=-1 && i==pathname.length-expected_url.length) ) {
911                                 if( /*window.opera==null*/wnd.document.readyState==null || wnd.document.readyState=="complete" ) { // for opera (and IE?), getElementById does not work until..
912                                         loaded=true;
913                                 }
914                         }
915                 }
916         }
917         return loaded;
918 }
919 // find and run all test functions in the g_cur_page html page.
920 Test.AnotherWay._test_page_onload=function()
921 {
922         if( Test.AnotherWay._g_tests_queue.length==0 ) {
923                 return;
924         }
925         var test_page=Test.AnotherWay._g_tests_queue[0];
926         if( !Test.AnotherWay._is_url_loaded( test_page.url, Test.AnotherWay._g_test_iframe ) ) {
927                 return;
928         }
929         clearTimeout( test_page.timeout_id );
930         Test.AnotherWay._unprint_result( test_page.wait_msg );
931
932         if( test_page.convention=="anotherway" ) {
933                 // get test function names (those beginning with "test")
934                 if( typeof( Test.AnotherWay._g_test_iframe.document.scripts )!='undefined' ) { // IE
935                         for( var i=0; i<Test.AnotherWay._g_test_iframe.document.scripts.length; ++i ) {
936                                 var script_text=Test.AnotherWay._g_test_iframe.document.scripts[i].text;
937                                 var fun_sig="function test";
938                                 var fun_start=script_text.indexOf( fun_sig );
939
940                                 while( fun_start!=-1 ) {
941                                         script_text=script_text.substring( fun_start, script_text.length );
942                                         var fun_end=script_text.indexOf( '(' );
943                                         var fun_name=script_text.substring( "function ".length,  fun_end );
944                                         var whitespace = fun_name.indexOf( ' ' );
945                                         if (whitespace >= 0)
946                                             fun_name = fun_name.substring( 0, whitespace );
947                                         test_page.test_objects.push( new Test.AnotherWay._test_object_t( fun_name ) );
948                                         script_text=script_text.substring( fun_end, script_text.length );
949                                         fun_start=script_text.indexOf( fun_sig  );
950                                 }
951                         }
952                 }else { // otherwise (not IE) it ought to work like this
953                         for( var i in Test.AnotherWay._g_test_iframe) {
954                                 // Hack to prevent failure in FF3.0b1 
955                 if (i == "innerWidth" || i == "innerHeight") { continue; }
956                                 if( typeof( Test.AnotherWay._g_test_iframe[i] )=='function' ) {
957                                         if( i.substring( 0, 4 )=="test" ) {
958                                                 test_page.test_objects.push( new Test.AnotherWay._test_object_t( i ) );
959                                         }
960                                 }
961                         }
962                 }
963         }else if( test_page.convention=="jsan" ) {
964                 // the test object is already filled with results
965                 test_page.test_objects.push( Test.AnotherWay._g_test_object_for_jsan );
966         }
967
968         if( test_page.test_objects.length==0 ) {
969                 Test.AnotherWay._print_result( test_page.url,  "No test functions defined in the page", "badtest", null );
970                 Test.AnotherWay._load_next_page();
971                 return;
972         }
973
974         test_page.wait_msg=Test.AnotherWay._print_result( test_page.url, "running tests..<span class=\"counter\">"+test_page.test_objects.length+"</span>", "running", null );
975
976         test_page.test_object_i=0;
977         Test.AnotherWay._run_more_tests();
978 }
979
980 Test.AnotherWay._handle_exception=function( o, e, title )
981 {
982         var s=title+": "+typeof( e )+": ";
983         if( e.message!=null ) {
984                 s+=e.message;
985         }else if( e.description!=null ) {
986                 s+=e.description;
987         }else {
988                 s+=e.toString();
989         }
990 //      if( e.location!=null ) {  // XXX figure out how to display exception location if it's present (like in mozilla)
991 //              s+=" location: "+e.location.toString();
992 //      }
993         o.exception=s;
994         s=[];
995         if( e.stack ) {
996                 var lines=e.stack.split( "\n" );
997                 for( var i=0; i<lines.length; ++i ) {
998                         // format of the line: func_name(args)@file_name:line_no
999                         if( lines[i].match( /(\w*)\(([^\)]*)\)@(.*):([^:]*)$/ ) ) {
1000                                 var func_name=RegExp.$1;
1001                                 if( func_name.length==0 ) {
1002                                         func_name="<anonymous>";
1003                                 }
1004                                 s.push( "in "+func_name+"( "+RegExp.$2+") at "+RegExp.$3+" line "+RegExp.$4+"\n" );
1005                         }
1006                 }
1007         }
1008         o.exception_stack=s;
1009 }
1010
1011 Test.AnotherWay._run_more_tests=function()
1012 {
1013         var test_page=Test.AnotherWay._g_tests_queue[0];
1014         while( test_page.test_object_i<test_page.test_objects.length ) {
1015                 Test.AnotherWay._update_msg_counter( test_page.wait_msg, (1+test_page.test_object_i)+"/"+test_page.test_objects.length );
1016                 var o=test_page.test_objects[test_page.test_object_i];
1017                 if( test_page.convention=="anotherway" ) {
1018                         try {
1019                                 Test.AnotherWay._g_test_iframe[o.name]( o );
1020                         }catch( e ) {
1021                                 Test.AnotherWay._handle_exception( o, e, "" );
1022                         }
1023                 } // for "jsan" convention, test has run already
1024                 if( o.delay_actions.length>0 || o.wait_result_milliseconds>0 ) {
1025                         o.delay_total_milliseconds_left+=o.wait_result_milliseconds;
1026                         Test.AnotherWay._delay_actions_timeout();
1027                         return;
1028                 }
1029                 ++test_page.test_object_i;
1030         }
1031         Test.AnotherWay._unprint_result( test_page.wait_msg );
1032         Test.AnotherWay._print_result( test_page.url, null, null, test_page.test_objects );
1033         Test.AnotherWay._load_next_page();
1034 }
1035
1036 Test.AnotherWay._delay_actions_timeout=function()
1037 {
1038         var test_page=Test.AnotherWay._g_tests_queue[0];
1039         var test_object=test_page.test_objects[test_page.test_object_i];
1040         var finished=true;
1041         if( test_object.delay_action_i==null ) {
1042                 // set up to start first action
1043                 test_object.delay_action_i=-1;
1044         }else {
1045                 // perform current action
1046                 var milliseconds_passed=(new Date()).getTime()-test_object.delay_prev_timer_time;
1047                 test_object.delay_current_milliseconds_left-=milliseconds_passed;
1048                 test_object.delay_total_milliseconds_left-=milliseconds_passed;
1049                 finished=Test.AnotherWay._delay_continue_action( test_object, milliseconds_passed );
1050         }
1051         while( finished && test_object.delay_action_i<test_object.delay_actions.length ) {
1052                 ++test_object.delay_action_i; // start next action
1053                 finished=Test.AnotherWay._delay_start_action( test_object );
1054         }
1055         if( test_object.delay_action_i<=test_object.delay_actions.length ) { // any more actions left ?
1056                 test_object.delay_prev_timer_time=(new Date()).getTime();
1057                 var next_timeout=Test.AnotherWay._g_timeout_granularity;
1058                 if( test_object.delay_current_milliseconds_left<next_timeout ) {
1059                         next_timeout=test_object.delay_current_milliseconds_left;
1060                 }
1061                 if( test_object.second_wait_msg!=null ) {
1062                         Test.AnotherWay._update_msg_counter( test_object.second_wait_msg, (test_object.delay_total_milliseconds_left/1000).toFixed() );
1063                 }
1064                 setTimeout( Test.AnotherWay._delay_actions_timeout, next_timeout );
1065         }else { // no more actions left. run the next test.
1066                 if( test_object.second_wait_msg!=null ) {
1067                         Test.AnotherWay._unprint_result( test_object.second_wait_msg );
1068                         test_object.second_wait_msg=null;
1069                 }
1070                 ++test_page.test_object_i;
1071                 Test.AnotherWay._run_more_tests();
1072         }
1073 }
1074 Test.AnotherWay._delay_start_action=function( test_object )
1075 {
1076         var finished=false;
1077         var wait_msg="";
1078         if( test_object.delay_action_i==test_object.delay_actions.length ) {
1079                 if( test_object.wait_result_milliseconds>0 ) {
1080                         test_object.delay_current_milliseconds_left=test_object.wait_result_milliseconds; // wait for result
1081                         wait_msg="waiting for results..";
1082                 }else {
1083                         ++test_object.delay_action_i; // dont wait for result
1084                 }
1085         }else {
1086                 var action=test_object.delay_actions[test_object.delay_action_i];
1087                 if( action.action_kind=="call" ) {
1088                         test_object.delay_current_milliseconds_left=action.call_delay_milliseconds;
1089                         wait_msg="performing delayed calls..";
1090                 }else if( action.action_kind=="window" ) {
1091                         if( Test.AnotherWay._g_opera_path_correction!=null && action.wnd_url.indexOf( ":" )==-1 ) {
1092                                 action.wnd_url=Test.AnotherWay._g_opera_path_correction+action.wnd_url;
1093                         }
1094                         action.wnd_wnd=window.open( action.wnd_url, "_blank" );
1095                         if( action.wnd_wnd==null ) {
1096                                 finished=true;
1097                                 test_object.fail( "unable to open window for "+action.wnd_url );
1098                         }else {
1099                                 test_object.delay_current_milliseconds_left=action.wnd_timeout_milliseconds;
1100                                 wait_msg="opening window..";
1101                         }
1102                 }else if( action.action_kind=="replay" ) {
1103                         if( action.replay_events.length==0 ) {
1104                                 finished=true;
1105                         }else {
1106                                 action.replay_event_i=0;
1107                                 test_object.delay_current_milliseconds_left=action.replay_events[0]["time"];
1108                                 wait_msg="replaying events..";
1109                         }
1110                 }
1111         }
1112         if( test_object.second_wait_msg!=null ) {
1113                 Test.AnotherWay._unprint_result( test_object.second_wait_msg );
1114         }
1115         if( wait_msg!="" ) {
1116                 var test_page=Test.AnotherWay._g_tests_queue[0];
1117                 test_object.second_wait_msg=Test.AnotherWay._print_counter_result( test_page.url, wait_msg, test_object.delay_total_milliseconds_left, "waiting" );
1118         }else {
1119                 test_object.second_wait_msg=null;
1120         }
1121         return finished;
1122 }
1123 Test.AnotherWay._delay_continue_action=function( test_object, milliseconds_passed )
1124 {
1125         var finished=test_object.delay_current_milliseconds_left<=0;
1126         if( test_object.delay_action_i==test_object.delay_actions.length ) { // action is "waiting for results"
1127                 if( test_object.n_plan!=null && test_object.n_plan==test_object.n_ok+test_object.n_fail ) {
1128                         finished=true; // if all assertions results are recorded, don't wait any more
1129                 }
1130                 if( finished ) {
1131                         ++test_object.delay_action_i; // move on to the next test
1132                 }
1133         }else {
1134                 var action=test_object.delay_actions[test_object.delay_action_i];
1135                 if( action.action_kind=="call" ) {
1136                         if( finished ) {
1137                                 try {
1138                                         action.call_fn();
1139                                 }catch( e ) {
1140                                         Test.AnotherWay._handle_exception( test_object, e, "in delay_call" );
1141                                 }
1142                         }
1143                 }else if( action.action_kind=="window" ) {
1144                         test_object.delay_total_milliseconds_left+=milliseconds_passed; // for "window", the countdown is suspended since it's unknown how long it will take
1145                         if( Test.AnotherWay._is_url_loaded( action.wnd_url, action.wnd_wnd ) ) {
1146                                 try {
1147                                         action.wnd_fn( action.wnd_wnd );
1148                                 }catch( e ) {
1149                                         Test.AnotherWay._handle_exception( test_object, e, "in open_window function call" );
1150                                 }
1151                                 finished=true;
1152                         }else if( finished ) {
1153                                 test_object.fail(  "unable to open window for url '"+action.wnd_url+"'. timeout expired" );
1154                         }
1155                 }else if( action.action_kind=="replay" ) {
1156                         if( finished ) {
1157 //                              try {
1158                                         Test.AnotherWay._delay_replay_event( test_object, action.replay_wnd, action.replay_events[action.replay_event_i], action.replay_checkpoints );
1159 //                              }catch( e ) { // disabled, until I know how to gel location info from an exception
1160 //                                      Test.AnotherWay._handle_exception( test_object, e, "while replaying event" );
1161 //                              }
1162                                 ++action.replay_event_i;
1163                                 finished=action.replay_event_i==action.replay_events.length;
1164                                 if( !finished ) {
1165                                         test_object.delay_current_milliseconds_left=action.replay_events[action.replay_event_i]["time"];
1166                                 }
1167                         }
1168                 }
1169         }
1170         return finished;
1171 }
1172 Test.AnotherWay._delay_replay_event=function( test_object, wnd, event, checkpoints )
1173 {
1174         if( event.type=="_checkpoint" ) {
1175                 var checkpoint_n=event.which;
1176                 var prev_n_fail=test_object.n_fail;
1177                 checkpoints[checkpoint_n]( test_object, wnd );
1178                 var flash_color= prev_n_fail==test_object.n_fail ? "#2f2" : "#f22" ;
1179                 Test.AnotherWay._record_flash_border( flash_color );
1180         }else if( event.type=="click" || event.type=="mouseover" || event.type=="mouseout" || event.type=="mousemove" || event.type=="mousedown" || event.type=="mouseup" ) {
1181                 var target=Test.AnotherWay._record_node_path_to_node( event["target"], wnd.document );
1182                 if( target!=null ) {
1183                         Test.AnotherWay._record_control_update_highlight( target, "ball", event );
1184                         var e=wnd.document.createEvent( "MouseEvents" );
1185                         var related_target=Test.AnotherWay._record_node_path_to_node( event["relatedTarget"], wnd.document );
1186                         e.initMouseEvent(
1187                                 event["type"],
1188                                 event["cancelable"],
1189                                 event["bubbles"],
1190                                 wnd.document.defaultView,
1191                                 event["detail"],
1192                                 event["screenX"],
1193                                 event["screenY"],
1194                                 event["clientX"],
1195                                 event["clientY"],
1196                                 event["ctrlKey"],
1197                                 event["altKey"],
1198                                 event["shiftKey"],
1199                                 event["metaKey"],
1200                                 event["button"],
1201                                 Test.AnotherWay._record_node_path_to_node( event["relatedTarget"], wnd.document )
1202                         );
1203                         // Firefox 1.0.6 somehow loses relatedTarget somewhere on the way. Pass through our own, for those who choose to care.
1204                         e.passThroughRelatedTarget=related_target;
1205                         target.dispatchEvent( e );
1206                 }
1207         }else if( event.type=="keyup" || event.type=="keydown" || event.type=="keypress" ) {
1208                 var e=wnd.document.createEvent( "KeyboardEvents" ); // forget it. Apparently it's not supported neither by mozilla nor by opera.
1209                 e.initKeyboardEvent(
1210                                 event["type"],
1211                                 event["cancelable"],
1212                                 event["bubbles"],
1213                                 wnd.document.defaultView,
1214                                 event["which"],
1215                                 event["which"],
1216                                 event["ctrlKey"],
1217                                 event["altKey"],
1218                                 event["shiftKey"],
1219                                 event["metaKey"],
1220                                 false
1221                 );
1222                 wnd.document.dispatchEvent( e );
1223         }
1224 }
1225
1226 Test.AnotherWay._print_counter_result=function( url, msg, milliseconds, style )
1227 {
1228         return Test.AnotherWay._print_result( url, msg+"<span class=\"counter\">"+(milliseconds/1000).toFixed()+"</span>", style, null );
1229 }
1230
1231 Test.AnotherWay._g_result_count=0; // for assigning unique ids to result paragraphs
1232
1233 // number of pages tested
1234 Test.AnotherWay._g_ok_pages=0;
1235 Test.AnotherWay._g_fail_pages=0;
1236
1237 Test.AnotherWay._print_result=function( url, msg, style, test_objects )
1238 {
1239         var results=document.getElementById( "results" );
1240         var r=results.appendChild( document.createElement( "p" ) );
1241         r.id="result"+Test.AnotherWay._g_result_count;
1242         ++Test.AnotherWay._g_result_count;
1243         r.onclick=Test.AnotherWay._toggle_detail;
1244         var text="<span class=\"bullet\">&nbsp;&nbsp;&nbsp;</span>&nbsp;";
1245         if( url!="" ) {
1246                 text+=url+":  ";
1247         }
1248         if( msg!=null ) {
1249                 text+=msg;
1250         }
1251         if( test_objects!=null ) {
1252                 // compose summary and detail texts
1253                 var total_ok=0;
1254                 var total_detail_ok=0;
1255                 var total_fail=0;
1256                 var total_detail_fail=0;
1257                 var no_plan=0;
1258
1259                 var detail=results.appendChild( document.createElement( "div" ) );
1260
1261                 if( r.id.match( /^result(\d+)$/ ) ) {
1262                         detail.id="result_detail"+RegExp.$1;
1263                 }
1264
1265                 for( var i=0; i<test_objects.length; ++i ) {
1266                         var o=test_objects[i];
1267                         var p;
1268                         var p_text;
1269                         p=document.createElement( "P" );
1270                         Test.AnotherWay._set_css_class( p, "result_detail" );
1271                         p_text=o.name;
1272                         if( o.n_fail>0 || o.exception || (o.n_plan!=null && o.n_plan!=o.n_ok+o.n_fail) || (o.n_plan==null && o.n_ok==0 && o.n_fail==0)) {
1273                                 ++total_fail;
1274                                 p_text+=" <span class=\"fail\">";
1275                                 if( o.n_plan!=null && o.n_plan!=o.n_ok+o.n_fail) {
1276                                         p_text+="planned "+o.n_plan+" assertions but got "+(o.n_ok+o.n_fail)+"; ";
1277                                 }
1278                                 if(o.n_plan==null && o.n_ok==0 && o.n_fail==0) {
1279                                         p_text+="test did not output anything";
1280                                 }else {
1281                                         p_text+=" fail "+o.n_fail;
1282                                 }
1283                                 p_text+="</span>";
1284                         }else {
1285                                 ++total_ok;
1286                         }
1287                         p_text+=" ok "+o.n_ok;
1288                         if( o.n_plan==null ) {
1289                                 no_plan=1;
1290                                 p_text+=" <span class=\"warning\">no plan</span>";
1291                         }
1292                         p.innerHTML=p_text;
1293                         detail.appendChild( p );
1294                         if( o.exception ) {
1295                                 p=document.createElement( "P" );
1296                                 Test.AnotherWay._set_css_class( p, "result_exception_detail" );
1297                                 p.innerHTML="<span class=\"fail\">exception:</span> "+o.exception;
1298                                 detail.appendChild( p );
1299                                 p=document.createElement( "P" );
1300                                 Test.AnotherWay._set_css_class( p, "result_exception_stack_detail" );
1301                                 p.innerHTML=o.exception_stack.join( "<br/>" );
1302                                 detail.appendChild( p );
1303                         }
1304                         for( var ii=0; ii<o.assertions.length; ++ii ) {
1305                                 var oo=o.assertions[ii];
1306                                 var status=oo.ok ? "ok" : "<span class=\"fail\">fail</span>";
1307                                 p=document.createElement( "P" );
1308                                 Test.AnotherWay._set_css_class( p, "result_micro_detail" );
1309                                 p.innerHTML=status;
1310                                 p.appendChild( document.createTextNode( " "+oo.name ) );
1311                                 detail.appendChild( p );
1312                         }
1313                         total_detail_ok+=o.n_ok;
1314                         total_detail_fail+=o.n_fail;
1315                 }
1316                 if( total_fail || total_detail_fail ) {
1317                         text+=" fail "+total_fail;
1318                 }
1319                 text+=" ok "+total_ok+" (detailed:";
1320                 if( total_fail || total_detail_fail ) {
1321                         text+=" fail "+total_detail_fail;
1322                 }
1323                 text+=" ok "+total_detail_ok+")";
1324                 if( no_plan ) {
1325                         text+=" <span class=\"warning\">no plan</span>";
1326                 }
1327                 style= total_fail==0 ? "ok" : "fail";
1328                 detail.style.display= style=="fail" ? "block" : "none";
1329                 detail.style.cursor="text";
1330         }
1331         if( style!=null ) {
1332                 Test.AnotherWay._set_css_class( r, style );
1333                 if( style=="ok" ) {
1334                         ++Test.AnotherWay._g_ok_pages;
1335                 }else if( style=="fail" || style=="badtest" ) {
1336                         ++Test.AnotherWay._g_fail_pages;
1337                 }
1338                 var pages_total="";
1339                 if( Test.AnotherWay._g_fail_pages>0 ) {
1340                         pages_total+=" fail "+Test.AnotherWay._g_fail_pages;
1341                 }
1342                 pages_total+=" ok "+Test.AnotherWay._g_ok_pages;
1343                 Test.AnotherWay._update_results_total( pages_total );
1344         }
1345         r.innerHTML=text;
1346         if( results.scrollHeight!=null && results.scrollTop!=null && results.offsetHeight!=null ) {
1347                 results.scrollTop=results.scrollHeight-results.offsetHeight;
1348         }
1349         // when test_objects is not null, the results are final - good time to clean up
1350         if( test_objects!=null ) {
1351                 for( var i=0; i<test_objects.length; ++i ) {
1352                         var actions=test_objects[i].delay_actions;
1353                         for( var action_i=0; action_i<actions.length; ++action_i ) {
1354                                 var action=actions[action_i];
1355                                 if( action.action_kind=="window" && action.wnd_wnd!=null && !action.wnd_no_close ) {
1356                                         action.wnd_wnd.close();
1357                                         action.wnd_wnd=null;
1358                                 }
1359                         }
1360                 }
1361         }
1362         return r;
1363 }
1364 Test.AnotherWay._unprint_result=function( child )
1365 {
1366         var results=document.getElementById( "results" );
1367         results.removeChild( child );
1368 }
1369 Test.AnotherWay._toggle_detail=function()
1370 {
1371         if( this.id.match( /^result(\d+)$/ ) ) {
1372                 var detail=document.getElementById( "result_detail"+RegExp.$1 );
1373                 if( detail!=null ) {
1374                         if( detail.style.display=="none" ) {
1375                                 detail.style.display="block";
1376                         }else if( detail.style.display=="block" ) {
1377                                 detail.style.display="none";
1378                         }
1379                 }
1380         }
1381 }
1382 Test.AnotherWay._update_msg_counter=function( msg, text )
1383 {
1384         for( var i=0; i<msg.childNodes.length; ++i ) {
1385                 var item=msg.childNodes[i];
1386                 if( item.nodeName=="SPAN" && Test.AnotherWay._get_css_class( item )=="counter" ) {
1387                         item.innerHTML=text;
1388                 }
1389         }
1390 }
1391 Test.AnotherWay._update_results_total=function( msg )
1392 {
1393         var total=document.getElementById( "total" );
1394         if( total ) {
1395                 total.innerHTML=msg;
1396         }
1397 }
1398 Test.AnotherWay._results_clear_onclick=function()
1399 {
1400         var results=document.getElementById( "results" );
1401         results.innerHTML="";
1402         Test.AnotherWay._update_results_total( "" );
1403         Test.AnotherWay._g_ok_pages=0;
1404         Test.AnotherWay._g_fail_pages=0;
1405         var debug=document.getElementById( "debug" );
1406         debug.innerHTML="";
1407 }
1408
1409 Test.AnotherWay._get_css_class=function( o )
1410 {
1411         var c=o.getAttribute( "className" );
1412         if( c==null || c=="" ) {
1413                 c=o.getAttribute( "class" );
1414         }
1415         return c;
1416 }
1417 Test.AnotherWay._set_css_class=function( o, css_class )
1418 {
1419         o.setAttribute( "className", css_class );
1420         o.setAttribute( "class", css_class );
1421 }
1422
1423 Test.AnotherWay._tab_onclick=function()
1424 {
1425         var tab=this;
1426         var tabs=[ document.getElementById( "debug_tab" ), document.getElementById( "results_tab" ) ];
1427         var panes=[ document.getElementById( "debug" ), document.getElementById( "results" ) ];
1428         for( var i=0; i<tabs.length; ++i ) {
1429                 if( tab==tabs[i] ) {
1430                         Test.AnotherWay._set_css_class( tabs[i], "active_tab" );
1431                         panes[i].style.display="block";
1432                 }else {
1433                         Test.AnotherWay._set_css_class( tabs[i], "inactive_tab" );
1434                         panes[i].style.display="none";
1435                 }
1436         }
1437 }
1438 Test.AnotherWay._tab_mouseover=function()
1439 {
1440         if( Test.AnotherWay._get_css_class( this )=="inactive_tab" ) {
1441                 Test.AnotherWay._set_css_class( this, "inactive_mouseover_tab" );
1442         }
1443 }
1444 Test.AnotherWay._tab_mouseout=function()
1445 {
1446         if( Test.AnotherWay._get_css_class( this )=="inactive_mouseover_tab" ) {
1447                 Test.AnotherWay._set_css_class( this, "inactive_tab" );
1448         }
1449 }
1450
1451 // recording mouse input
1452 Test.AnotherWay._record_check_onfocus=function()
1453 {
1454         var o=this;
1455         var check_select=o.type!="text";
1456         var div=document.getElementById( "record_div" );
1457         var inputs=div.getElementsByTagName( "input" );
1458         for( var i=0; i<inputs.length; ++i ) {
1459                 var input=inputs[i];
1460                 if( input.type=="radio" ) {
1461                         if( input.value=="select" ) {
1462                                 input.checked=check_select;
1463                         }else if( input.value=="input" ) {
1464                                 input.checked=!check_select;
1465                         }
1466                 }
1467         }
1468 }
1469
1470 Test.AnotherWay._g_no_record_msg=null; // not null - recording is unavailable
1471 Test.AnotherWay._g_record_timeout_cnt=0; // opening window for a page for recording
1472 Test.AnotherWay._g_record_url=null;
1473 Test.AnotherWay._g_record_wnd=null;
1474 Test.AnotherWay._g_record_random_id=null; // added to element ids of record_control div so that they do not clash with ids already in the page for which input is recorded
1475 Test.AnotherWay._g_record_keydown=null; // recording control - which key is down
1476 Test.AnotherWay._g_record_ctrl_keydown=false;
1477 Test.AnotherWay._g_record_shift_keydown=false;
1478 Test.AnotherWay._g_record_control_visible=true; // recording control ui state
1479 Test.AnotherWay._g_record_started;
1480 Test.AnotherWay._g_record_paused;
1481 Test.AnotherWay._g_record_include_mousemove=false;
1482 Test.AnotherWay._g_record_start_time; // for time references
1483 Test.AnotherWay._g_record_pause_start_time;
1484 Test.AnotherWay._g_record_update_time_interval; // showing time in the control ui
1485 Test.AnotherWay._g_record_waiting_for_results=false; // waiting for results window to open
1486 Test.AnotherWay._g_record_events; // recorded events
1487 Test.AnotherWay._g_record_under_cursor; // track element under cursor
1488 Test.AnotherWay._g_record_checkpoint_count; // for checkpoint numbering
1489 Test.AnotherWay._g_record_mouse_over_record_control; // for avoiding record control highlight on mouseover
1490 Test.AnotherWay._g_record_highlighted_element={ element: null, x: null, y: null };
1491
1492 Test.AnotherWay._record_control_get_element=function( id )
1493 {
1494         if( Test.AnotherWay._g_record_wnd!=null && Test.AnotherWay._g_record_wnd.document!=null ) {
1495                 return Test.AnotherWay._g_record_wnd.document.getElementById( id+Test.AnotherWay._g_record_random_id );
1496         }else {
1497                 return null;
1498         }
1499 }
1500 Test.AnotherWay._record_start_onclick=function() // "record" button on the run_tests.html: open a window for a page for which input is recorded
1501 {
1502         if( Test.AnotherWay._g_no_record_msg!=null ) {
1503                 alert( Test.AnotherWay._g_no_record_msg );
1504                 return;
1505         }
1506         if( Test.AnotherWay._g_record_timeout_cnt>0
1507             || (Test.AnotherWay._g_record_wnd!=null && (Test.AnotherWay._g_record_wnd.closed!=null && !Test.AnotherWay._g_record_wnd.closed)) ) { // in opera, closed is null.
1508                 alert( "there is already window opened for recording input for a page "+Test.AnotherWay._g_record_url );
1509                 return;
1510         }
1511         var div=document.getElementById( "record_div" );
1512         var inputs=div.getElementsByTagName( "input" );
1513         var url=null;
1514         for( var i=0; i<inputs.length; ++i ) {
1515                 var input=inputs[i];
1516                 if( input.type=="radio" ) {
1517                         if( input.value=="select" && input.checked ) {
1518                                 var index=document.getElementById( "record_select" ).selectedIndex;
1519                                 if( index>0 ) {
1520                                         url=Test.AnotherWay._g_test_page_urls[index-1].url;
1521                                 }
1522                         }else if( input.value=="input" && input.checked ) {
1523                                 url=document.getElementById( "record_input" ).value;
1524                         }
1525                 }
1526         }
1527         if( url!=null ) {
1528                 Test.AnotherWay._g_record_url=url;
1529                 Test.AnotherWay._g_record_wnd=window.open( url, "_blank" );
1530                 if( Test.AnotherWay._g_record_wnd==null ) {
1531                         alert( "unable to open new window for a page: "+url );
1532                 }else {
1533                         Test.AnotherWay._g_record_timeout_cnt=50;
1534                         setTimeout( Test.AnotherWay._record_window_timeout, 100 );
1535                 }
1536         }
1537 }
1538 Test.AnotherWay._record_window_timeout=function()
1539 {
1540         if( Test.AnotherWay._is_url_loaded( Test.AnotherWay._g_record_url, Test.AnotherWay._g_record_wnd ) ) {
1541                 Test.AnotherWay._record_window_setup( Test.AnotherWay._g_record_wnd );
1542         }else {
1543                 if( --Test.AnotherWay._g_record_timeout_cnt>0 ) {
1544                         setTimeout( Test.AnotherWay._record_window_timeout, 100 );
1545                 }else {
1546                         alert( "timeout expired while opening new window for a page: "+Test.AnotherWay._g_record_url );
1547                         Test.AnotherWay._g_record_wnd=null;
1548                         Test.AnotherWay._g_record_url=null;
1549                         Test.AnotherWay._g_record_timeout_cnt=0;
1550                 }
1551         }
1552 }
1553 Test.AnotherWay._record_control_randomize_id=function( e, r )
1554 {
1555         if( e.id!="" ) {
1556                 e.id=e.id+r;
1557         }
1558         for( var c=e.firstChild; c!=null; c=c.nextSibling ) {
1559                 Test.AnotherWay._record_control_randomize_id( c, r );
1560         }
1561 }
1562 Test.AnotherWay._record_window_setup=function( wnd ) // insert recording control into the page for which input is recorded
1563 {
1564         Test.AnotherWay._g_record_timeout_cnt=0;
1565         var this_div=document.getElementById( "record_control" );
1566         var record_control=wnd.document.importNode( this_div, true );
1567         Test.AnotherWay._g_record_random_id=(1000*Math.random()).toFixed();
1568         Test.AnotherWay._record_control_randomize_id( record_control, Test.AnotherWay._g_record_random_id );
1569         Test.AnotherWay._g_record_control_visible=true;
1570         Test.AnotherWay._g_record_started=false;
1571         Test.AnotherWay._g_record_paused=false;
1572         Test.AnotherWay._g_record_checkpoint_count=0;
1573         Test.AnotherWay._g_record_mouse_over_record_control=false;
1574         var doc=wnd.document;
1575         doc.body.appendChild( record_control );
1576         // opera sans-serif font is different
1577         if( window.opera ) {
1578                 cursor_over_indicator=Test.AnotherWay._record_control_get_element( "record_cursor_over" );
1579                 cursor_over_indicator.style.width="18em";
1580                 cursor_over_indicator.style.height="2em";
1581                 cursor_over_indicator.style.fontSize="7pt";
1582         }
1583         doc.addEventListener( "keydown", Test.AnotherWay._record_control_keydown, true );
1584         doc.addEventListener( "keyup", Test.AnotherWay._record_control_keyup, true );
1585 //      doc.addEventListener( "keypress", Test.AnotherWay._record_event, true ); // replaying is not supported by any known browser
1586
1587         doc.body.addEventListener( "mousemove", Test.AnotherWay._record_on_mousemove, true );
1588         doc.body.addEventListener( "click", Test.AnotherWay._record_event, true );
1589         doc.body.addEventListener( "mouseover", Test.AnotherWay._record_event, true );
1590         doc.body.addEventListener( "mouseout", Test.AnotherWay._record_event, true );
1591         doc.body.addEventListener( "mousedown", Test.AnotherWay._record_event, true );
1592         doc.body.addEventListener( "mouseup", Test.AnotherWay._record_event, true );
1593 }
1594 Test.AnotherWay._record_control_key_disabled=function( k )
1595 {
1596         if( k=="c" ) {
1597                 return !Test.AnotherWay._g_record_started;
1598         }else if( k=="p" ) {
1599                 return !Test.AnotherWay._g_record_started;
1600         }else if( k=="s" ) {
1601                 return Test.AnotherWay._g_record_waiting_for_results;
1602         }else {
1603                 return false;
1604         }
1605 }
1606
1607 Test.AnotherWay._record_control_update_ui=function()
1608 {
1609         var keydown_color="#fff";
1610         var disabled_color="#aaa";
1611         var button_color="#adf";
1612         var active_color="#fdf";
1613
1614         var display={};
1615         display[false]="none";
1616         display[true]="inline";
1617
1618         var s_button=Test.AnotherWay._record_control_get_element( "record_s" );
1619         var record_on=Test.AnotherWay._record_control_get_element( "record_on" );
1620         var record_off=Test.AnotherWay._record_control_get_element( "record_off" );
1621
1622         s_button.style.backgroundColor= Test.AnotherWay._record_control_key_disabled( "s" ) ? disabled_color
1623                 : Test.AnotherWay._g_record_keydown=="s" ? keydown_color : Test.AnotherWay._g_record_started ? active_color : button_color;
1624         record_on.style.display=display[!Test.AnotherWay._g_record_started];
1625         record_off.style.display=display[Test.AnotherWay._g_record_started];
1626
1627         var h_button=Test.AnotherWay._record_control_get_element( "record_h" );
1628         h_button.style.backgroundColor= Test.AnotherWay._g_record_keydown=="h" ? keydown_color : button_color;
1629
1630         var p_button=Test.AnotherWay._record_control_get_element( "record_p" );
1631         var record_pause_on=Test.AnotherWay._record_control_get_element( "record_pause_on" );
1632         var record_pause_off=Test.AnotherWay._record_control_get_element( "record_pause_off" );
1633         p_button.style.backgroundColor= Test.AnotherWay._record_control_key_disabled( "p" ) ? disabled_color
1634                 : Test.AnotherWay._g_record_keydown=="p" ? keydown_color : Test.AnotherWay._g_record_paused ? active_color : button_color;
1635         record_pause_on.style.display=display[!Test.AnotherWay._g_record_paused];
1636         record_pause_off.style.display=display[Test.AnotherWay._g_record_paused];
1637
1638         var m_button=Test.AnotherWay._record_control_get_element( "record_m" );
1639         var record_include_mousemove=Test.AnotherWay._record_control_get_element( "record_include_mousemove" );
1640         var record_omit_mousemove=Test.AnotherWay._record_control_get_element( "record_omit_mousemove" );
1641         m_button.style.backgroundColor= Test.AnotherWay._g_record_keydown=="m" ? keydown_color : Test.AnotherWay._g_record_include_mousemove ? active_color : button_color;
1642         record_include_mousemove.style.display=display[!Test.AnotherWay._g_record_include_mousemove];
1643         record_omit_mousemove.style.display=display[Test.AnotherWay._g_record_include_mousemove];
1644
1645         var c_button=Test.AnotherWay._record_control_get_element( "record_c" );
1646         c_button.style.backgroundColor= Test.AnotherWay._record_control_key_disabled( "c" ) ? disabled_color
1647                 : Test.AnotherWay._g_record_keydown=="c" ? keydown_color : button_color;
1648
1649         var record_indicator=Test.AnotherWay._record_control_get_element( "record_indicator" );
1650         record_indicator.style.display=display[Test.AnotherWay._g_record_started];
1651
1652         var pause_indicator=Test.AnotherWay._record_control_get_element( "record_pause_indicator" );
1653         pause_indicator.style.display=display[Test.AnotherWay._g_record_paused];
1654
1655         var record_control=Test.AnotherWay._record_control_get_element( "record_control" );
1656         record_control.style.display= Test.AnotherWay._g_record_control_visible ? "block" : "none";
1657
1658         var shift_button=Test.AnotherWay._record_control_get_element( "record_shift_key" );
1659         shift_button.style.backgroundColor= Test.AnotherWay._g_record_shift_keydown ? keydown_color : button_color;
1660
1661         var ctrl_button=Test.AnotherWay._record_control_get_element( "record_ctrl_key" );
1662         ctrl_button.style.backgroundColor= Test.AnotherWay._g_record_ctrl_keydown ? keydown_color : button_color;
1663 }
1664 Test.AnotherWay._record_format_time=function( t )
1665 {
1666         t=new Date( t );
1667         var m=t.getMinutes();
1668         var s=t.getSeconds();
1669         var str= m==0 ? "" : m+"m ";
1670         str+=s+"s.";
1671         return str;
1672 }
1673 Test.AnotherWay._record_control_update_time=function()
1674 {
1675         var time_display=Test.AnotherWay._record_control_get_element( "record_time" );
1676         if( time_display!=null ) {
1677                 time_display.innerHTML=Test.AnotherWay._record_format_time( (new Date()).getTime()-Test.AnotherWay._g_record_start_time );
1678         }
1679 }
1680 Test.AnotherWay._record_control_update_highlight=function( elem, style, event )
1681 {
1682         if( elem==null ) {
1683                 Test.AnotherWay._record_highlight_border( null );
1684         }else {
1685                 var pos=Test.AnotherWay._get_page_coords( elem );
1686                 if( style=="ball" || elem!=Test.AnotherWay._g_record_highlighted_element.element || pos.x!=Test.AnotherWay._g_record_highlighted_element.x || pos.y!=Test.AnotherWay._g_record_highlighted_element.y ) {
1687                         Test.AnotherWay._g_record_highlighted_element={ element: elem, x: pos.x, y: pos.y };
1688                         Test.AnotherWay._record_highlight_border( elem, style, event );
1689                 }
1690         }
1691 }
1692 Test.AnotherWay._record_decode_key=function( event )
1693 {
1694         var k=null;
1695         if( event==null ) {
1696                 k=Test.AnotherWay._g_record_wnd.event.keyCode;
1697         }else {
1698                 k=event.which;
1699         }
1700         if( k==83 ) {
1701                 return "s";
1702         }else if( k==72 ) {
1703                 return "h";
1704         }else if( k==73 ) {
1705                 return "i";
1706         }else if( k==80 ) {
1707                 return "p";
1708         }else if( k==67 ) {
1709                 return "c";
1710         }else if( k==77 ) {
1711                 return "m";
1712         }else if( k==16 ) {
1713                 return "shift";
1714         }else if( k==17 ) {
1715                 return "ctrl";
1716         }else if( k==18 ) {
1717                 return "alt";
1718         }else if( k==19 ) {
1719                 return "pause";
1720         }else if( k==123 ) {
1721                 return "f12";
1722         }
1723         return "";
1724 }
1725 Test.AnotherWay._record_control_keydown=function( event )
1726 {
1727         var handled=false;
1728         var k=Test.AnotherWay._record_decode_key( event );
1729         if( k=="shift" ) {
1730                 Test.AnotherWay._g_record_shift_keydown=true;
1731         }else if( k=="ctrl" ) {
1732                 Test.AnotherWay._g_record_ctrl_keydown=true;
1733         }else if( k!="" && (Test.AnotherWay._g_record_keydown==null || Test.AnotherWay._g_record_keydown==k) ) {
1734                 if( Test.AnotherWay._g_record_ctrl_keydown && Test.AnotherWay._g_record_shift_keydown && !Test.AnotherWay._record_control_key_disabled( k ) ) {
1735                         Test.AnotherWay._g_record_keydown=k;
1736                         handled=true;
1737                 }
1738         }else {
1739                 Test.AnotherWay._g_record_keydown="";
1740         }
1741         Test.AnotherWay._record_control_update_ui();
1742         if( !handled ) {
1743 //              Test.AnotherWay._record_event( event ); // replaying is not supported in any known browser
1744         }
1745         return;
1746 }
1747 Test.AnotherWay._record_control_keyup=function( event )
1748 {
1749         var handled=false;
1750         var k=Test.AnotherWay._record_decode_key( event );
1751         if( k=="shift" ) {
1752                 Test.AnotherWay._g_record_shift_keydown=false;
1753         }else if( k=="ctrl" ) {
1754                 Test.AnotherWay._g_record_ctrl_keydown=false;
1755         }else if( k!="" && k==Test.AnotherWay._g_record_keydown && Test.AnotherWay._g_record_ctrl_keydown && Test.AnotherWay._g_record_shift_keydown  ) {
1756                 if( k=="s" ) {
1757                         Test.AnotherWay._g_record_started=!Test.AnotherWay._g_record_started;
1758                         if( Test.AnotherWay._g_record_started ) {
1759                                 Test.AnotherWay._g_record_events=[];
1760                                 Test.AnotherWay._g_record_start_time=(new Date()).getTime();
1761                                 Test.AnotherWay._record_control_update_time();
1762                                 Test.AnotherWay._g_record_update_time_interval=window.setInterval( Test.AnotherWay._record_control_update_time, 200 );
1763                         }else {
1764                                 Test.AnotherWay._record_control_update_highlight( null );
1765                                 if( !Test.AnotherWay._g_record_paused ) {
1766                                         window.clearInterval( Test.AnotherWay._g_record_update_time_interval );
1767                                 }
1768                                 Test.AnotherWay._g_record_waiting_for_results=true;
1769                                 // open a new window for self, pass a parameter to dump recorded events as javascript code there
1770                                 // (the easiest way to obtain a document from the same origin, so it's writable, is to open this same page again)
1771                                 Test.AnotherWay._g_record_paused=false;
1772                                 var loc=window.location;
1773                                 loc=loc.protocol+"//"+loc.host+loc.pathname+"?recording_results="+Test.AnotherWay._g_record_random_id;
1774                                 if( window.open( loc, "_blank" )==null ) {
1775                                         alert( "unable to open new window for results" );
1776                                 }
1777                         }
1778                         handled=true;
1779                 }else if( k=="h" ) {
1780                         Test.AnotherWay._g_record_control_visible=!Test.AnotherWay._g_record_control_visible;
1781                         handled=true;
1782                 }else if( k=="p" ) {
1783                         Test.AnotherWay._g_record_paused=!Test.AnotherWay._g_record_paused;
1784                         if( Test.AnotherWay._g_record_paused ) {
1785                                 Test.AnotherWay._g_record_pause_start_time=(new Date()).getTime();
1786                                 if( Test.AnotherWay._g_record_started ) {
1787                                         window.clearInterval( Test.AnotherWay._g_record_update_time_interval );
1788                                 }
1789                                 Test.AnotherWay._record_control_update_highlight( null );
1790                         }else {
1791                                 var pause_duration=(new Date()).getTime()-Test.AnotherWay._g_record_pause_start_time;
1792                                 Test.AnotherWay._g_record_start_time+=pause_duration;
1793                                 Test.AnotherWay._g_record_update_time_interval=window.setInterval( Test.AnotherWay._record_control_update_time, 200 );
1794                         }
1795                         handled=true;
1796                 }else if( k=="m" ) {
1797                         Test.AnotherWay._g_record_include_mousemove=!Test.AnotherWay._g_record_include_mousemove;
1798                         handled=true;
1799                 }else if( k=="c" ) {
1800                         var o=Test.AnotherWay._record_checkpoint();
1801                         Test.AnotherWay._record_display_checkpoint( o );
1802                         Test.AnotherWay._record_flash_border( "#24d" );
1803                         handled=true;
1804                 }
1805         }
1806         Test.AnotherWay._g_record_keydown=null;
1807         Test.AnotherWay._record_control_update_ui();
1808         if( !handled ) {
1809 //              Test.AnotherWay._record_event( event ); // replaying is not supported in any known browser
1810         }
1811         return;
1812 }
1813 Test.AnotherWay._record_html_node_path=function( node )
1814 {
1815         if( node==null ) {
1816                 return null;
1817         }
1818         var path=[];
1819         while( true ) {
1820                 if( node.id!=null && node.id!="" ) {
1821                         path.unshift( "#"+node.id+" "+node.nodeName );
1822                         break;
1823                 }else {
1824                         var parent_node=node.parentNode;
1825                         if( parent_node==null ) {
1826                                 return []; // no BODY up the path - this node is screwed (browsers differ in what's above the body), discard
1827                         }else {
1828                                 var i=0;
1829                                 var found=false;
1830                                 for( var child=parent_node.firstChild; child!=null; child=child.nextSibling ) {
1831                                         if( child==node ) {
1832                                                 found=true;
1833                                                 break;
1834                                         }
1835                                         if( child.nodeType==1 ) { // count only HTML element nodes
1836                                                 ++i;
1837                                         }
1838                                 }
1839                                 if( !found ) {
1840                                         i=-1;
1841                                 }
1842                                 path.unshift( i+" "+node.nodeName );
1843                                 if( parent_node.nodeName=="BODY" || parent_node.nodeName=="body" ) {
1844                                         break;
1845                                 }
1846                                 node=parent_node;
1847                         }
1848                 }
1849         }
1850         return path;
1851 }
1852 Test.AnotherWay._record_node_path_to_string=function( path )
1853 {
1854         var s="";
1855         if( path!=null ) {
1856                 for( var i=0; i<path.length; ++i ) {
1857                         s+= i==0 ? "" : ", ";
1858                         var elem=path[i].split( " " );
1859                         if( elem[0].charAt( 0 )=="#" ) {
1860                                 s+=elem[1]+" "+elem[0];
1861                         }else {
1862                                 s+=elem[1]+" ["+elem[0]+"]";
1863                         }
1864                 }
1865         }
1866         return s;
1867 }
1868 Test.AnotherWay._record_node_path_to_node=function( path_str, doc )
1869 {
1870         if( path_str==null ) {
1871                 return null;
1872         }
1873         var path=path_str.split( "," );
1874         var node=doc.body;
1875         for( var i=0; i<path.length; ++i ) {
1876                 var node_i=path[i].split( " " )[0];
1877                 if( node_i.charAt( 0 )=="#" ) {
1878                         node=doc.getElementById( node_i.substring( 1 ) );
1879                 }else {
1880                         if( node_i<0 || node_i>=node.childNodes.length ) {
1881                                 node=null;
1882                         }else {
1883                                 node=node.firstChild;
1884                                 while( node!=null ) {
1885                                         if( node.nodeType==1 ) {  // count only HTML element nodes
1886                                                 if( node_i==0 ) {
1887                                                         break;
1888                                                 }
1889                                                 --node_i;
1890                                         }
1891                                         node=node.nextSibling;
1892                                 }
1893                         }
1894                 }
1895                 if( node==null ) {
1896                         return null;
1897                 }
1898         }
1899         return node;
1900 }
1901 Test.AnotherWay._record_control_contains_id=function( s )
1902 {
1903         return s.match( /^#record_[\w_]+/ ) && s.match( Test.AnotherWay._g_record_random_id );
1904 }
1905 Test.AnotherWay._record_checkpoint=function()
1906 {
1907         var o={ type: "_checkpoint", time: (new Date()).getTime()-Test.AnotherWay._g_record_start_time, which: Test.AnotherWay._g_record_checkpoint_count++,
1908                         target: Test.AnotherWay._record_html_node_path( Test.AnotherWay._g_record_under_cursor ) };
1909         Test.AnotherWay._g_record_events.push( o );
1910         return o;
1911 }
1912 Test.AnotherWay._record_event=function( event )
1913 {
1914         var unneeded=["rangeOffset","eventPhase","timeStamp","isTrusted","popupWindowFeatures","rangeOffset"];
1915         if( Test.AnotherWay._g_record_started && !Test.AnotherWay._g_record_paused ) {
1916                 var o={};
1917                 for( var n in event ) {
1918                         var needed=!n.match( /^[A-Z0-9_]+$/ );
1919                         if( needed ) {
1920                                 for( var ui=0; ui<unneeded.length; ++ui ) {
1921                                         if( unneeded[ui]==n ) {
1922                                                 needed=false;
1923                                                 break;
1924                                         }
1925                                 }
1926                                 if( needed ) {
1927                                         var value=event[n];
1928                                         if( typeof( value )!="object" && typeof( value )!="function" ) {
1929                                                 o[n]=value;
1930                                         }else if( n=="target" || n=="relatedTarget" ) {
1931                                                 o[n]=Test.AnotherWay._record_html_node_path( value );
1932                                         }
1933                                 }
1934                         }
1935                 }
1936                 o["time"]=(new Date()).getTime()-Test.AnotherWay._g_record_start_time;
1937                 var over_record_control= o["target"]!=null && o["target"][0]!=null && Test.AnotherWay._record_control_contains_id( o["target"][0] );
1938                 if( !over_record_control ) {
1939                         Test.AnotherWay._g_record_events.push( o );
1940                 }
1941         }
1942         return true;
1943 }
1944 Test.AnotherWay._record_on_mousemove=function( event )
1945 {
1946         var path=Test.AnotherWay._record_html_node_path( event.target );
1947         var new_mouse_over_record_control= path!=null && path[0]!=null && Test.AnotherWay._record_control_contains_id( path[0] );
1948         if( new_mouse_over_record_control!=Test.AnotherWay._g_record_mouse_over_record_control ) {
1949                 Test.AnotherWay._g_record_mouse_over_record_control=new_mouse_over_record_control;
1950                 Test.AnotherWay._record_control_update_ui();
1951         }
1952         if( event.target!=null && event.target!=Test.AnotherWay._g_record_under_cursor ) {
1953                 Test.AnotherWay._g_record_under_cursor=event.target;
1954                 var s="";
1955                 if( path==null || path[0]==null || !Test.AnotherWay._record_control_contains_id( path[0] ) ) {
1956                         s=Test.AnotherWay._record_node_path_to_string( path );
1957                 }
1958                 if( s=="" ) {
1959                         s="&nbsp;";
1960                 }
1961                 var cursor_over_indicator=Test.AnotherWay._record_control_get_element( "record_cursor_over" );
1962                 cursor_over_indicator.innerHTML=s;
1963         }
1964
1965         var highlight_element=null;
1966         if( !Test.AnotherWay._g_record_mouse_over_record_control && Test.AnotherWay._g_record_started && !Test.AnotherWay._g_record_paused ) {
1967                 highlight_element=event.target;
1968         }
1969         // highlight border disabled on recording - it causes page to scroll, issuing spurious mouseover/mouseout event
1970         //Test.AnotherWay._record_control_update_highlight( highlight_element, "border" );
1971
1972         if( Test.AnotherWay._g_record_include_mousemove ) {
1973                 Test.AnotherWay._record_event( event );
1974         }
1975         return true;
1976 }
1977 Test.AnotherWay._record_display_checkpoint=function( o )
1978 {
1979         var checkpoints_div=Test.AnotherWay._record_control_get_element( "record_checkpoints" );
1980         var p=checkpoints_div.appendChild( checkpoints_div.ownerDocument.createElement( "div" ) );
1981         p.style.marginTop="3px";
1982         p.style.font="normal normal 8pt sans-serif";
1983         p.style.color="#000";
1984         p.style.textAligh="left";
1985         p.style.position="relative";
1986         p.style.width="100%";
1987         var checkpoint_text="";
1988         checkpoint_text+="#"+(o.which+1);
1989         checkpoint_text+="  "+Test.AnotherWay._record_format_time( o.time );
1990         if( o.target!=null ) {
1991                 checkpoint_text+=Test.AnotherWay._record_node_path_to_string( o.target );
1992         }
1993         p.appendChild( p.ownerDocument.createTextNode( checkpoint_text ) );
1994 }
1995 Test.AnotherWay._record_save_results=function( doc )
1996 {
1997         // strange, but DOM-style append does not work here in opera 8.
1998         var append=function( s ) { doc.write( "<div>"+s+"</div>" ); };
1999         append( "/* paste this data into your javascript and pass it as an argument to replay_events method */" );
2000         append( "{ checkpoints: [" );
2001         var first_checkpoint=true;
2002         for( var i=0; i<Test.AnotherWay._g_record_events.length; ++i ) {
2003                 var o=Test.AnotherWay._g_record_events[i];
2004                 if( o.type=="_checkpoint" ) {
2005                         var str= first_checkpoint ? "" : "}, ";
2006                         str+="function( tst, wnd ) { // #"+o.which+" time "+Test.AnotherWay._record_format_time( o.time )+" cursor was over "+Test.AnotherWay._record_node_path_to_string( o.target );
2007                         append( str );
2008                         first_checkpoint=false;
2009                 }
2010         }
2011         if( !first_checkpoint ) {
2012                 append( "}" );
2013         }
2014         append( "], events: [ " );
2015         var prev_time=0;
2016         for( var i=0; i<Test.AnotherWay._g_record_events.length; ++i ) {
2017                 var o=Test.AnotherWay._g_record_events[i];
2018                 var s="";
2019                 s+= "{";
2020                 var n_first=true;
2021                 for( var n in o ) {
2022                         if( n=="time" ) { // convert to relative time
2023                                 var cur_time=o[n]-0;
2024                                 o[n]=cur_time-prev_time;
2025                                 prev_time=cur_time;
2026                         }
2027                         s+=n_first ? n : ", "+n;
2028                         s+=":";
2029                         if( o[n]==null ) {
2030                                 s+="null";
2031                         }else {
2032                                 s+="\""+o[n]+"\"";
2033                         }
2034                         n_first=false;
2035                 }
2036                 s+= i==Test.AnotherWay._g_record_events.length-1 ? "}" : "},";
2037                 append( s );
2038         }
2039         append( "] }" );
2040         append( ";" );
2041 }
2042
2043 Test.AnotherWay._g_record_border; // border highlighting element under cursor
2044 Test.AnotherWay._g_record_border_flashes=[]; // array of { color: color, timeout: milliseconds }
2045 Test.AnotherWay._g_record_border_flashing=false;
2046 Test.AnotherWay._g_record_border_normal_color="#d4b";
2047 Test.AnotherWay._record_flash_border_timeout=function()
2048 {
2049         var color=Test.AnotherWay._g_record_border_normal_color;
2050         var timeout=null;
2051         if( Test.AnotherWay._g_record_border_flashes.length!=0 ) {
2052                 color=Test.AnotherWay._g_record_border_flashes[0].color;
2053                 timeout=Test.AnotherWay._g_record_border_flashes[0].timeout;
2054                 Test.AnotherWay._g_record_border_flashes.splice( 0, 1 );
2055         }
2056         if( Test.AnotherWay._g_record_border!=null ) {
2057                 for( var i=0; i<Test.AnotherWay._g_record_border.length; ++i ) {
2058                         Test.AnotherWay._g_record_border[i].style.backgroundColor=color;
2059                 }
2060         }
2061         if( timeout!=null ) {
2062                 setTimeout( Test.AnotherWay._record_flash_border_timeout, timeout );
2063         }else {
2064                 Test.AnotherWay._g_record_border_flashing=false;
2065         }
2066 }
2067 Test.AnotherWay._get_page_coords=function( elm )
2068 {
2069         var point = { x: 0, y: 0 };
2070         while( elm )  {
2071                 point.x+=elm.offsetLeft;
2072                 point.y+=elm.offsetTop;
2073                 elm=elm.offsetParent;
2074          }
2075         return point;
2076 }
2077 Test.AnotherWay._set_page_coords=function( elm, x, y )
2078 {
2079         var parent_coords={ x: 0, y: 0 };
2080         if( elm.offsetParent )  {
2081                 parent_coords=Test.AnotherWay._get_page_coords( elm.offsetParent );
2082         }
2083         var new_x=x-parent_coords.x;
2084         if( new_x<0 ) {
2085                 new_x=0;
2086         }
2087         elm.style.left=new_x+'px';
2088         var new_y=y-parent_coords.y;
2089         if( new_y<0 ) {
2090                 new_y=0;
2091         }
2092         elm.style.top=new_y+'px';
2093 }
2094 Test.AnotherWay._record_setup_highlight_positions=function( element, style, coords, positions )
2095 {
2096         if( style=="border" ) {
2097                 var width=element.clientWidth;
2098                 var height=element.clientHeight;
2099                 var step=0;
2100                 var thickness=2;
2101                 var fudge_expand=4;
2102                 positions.push( { x: coords.x-step-thickness, y: coords.y-step-thickness, width: width+2*step+2*thickness+fudge_expand, height: thickness } );
2103                 positions.push( { x: coords.x+width+step+fudge_expand, y: coords.y-step-thickness, width: thickness, height: height+2*step+2*thickness+fudge_expand } );
2104                 positions.push( { x:positions[0].x, y:positions[0].y, width:positions[0].width, height:positions[0].height } );
2105                 positions.push( { x:positions[1].x, y:positions[1].y, width:positions[1].width, height:positions[1].height } );
2106                 positions[2].y+=height+thickness+2*step+fudge_expand;
2107                 positions[3].x-=width+thickness+2*step+fudge_expand;
2108         }else if( style=="ball" ) {
2109                 positions.push( { x: coords.x+2, y: coords.y, width: 2, height: 6 } );
2110                 positions.push( { x: coords.x, y: coords.y+2, width: 6, height: 2 } );
2111                 positions.push( { x: coords.x+1, y: coords.y+1, width: 4, height: 4 } );
2112         }
2113 }
2114 Test.AnotherWay._record_highlight_border=function( element, style, event ) // null - hide border
2115 {
2116         if( element!=null ) {
2117                 if( Test.AnotherWay._g_record_border==null || Test.AnotherWay._g_record_border[0].ownerDocument!=element.ownerDocument ) {
2118                         Test.AnotherWay._g_record_border=[];
2119                         var n= style=="border" ? 4 : style=="ball" ? 3 : 0;
2120                         for( var i=0; i<4; ++i ) {
2121                                 var b=element.ownerDocument.createElement( "div" );
2122                                 b.style.position="absolute";
2123                                 b.style.zIndex="1";
2124                                 b.style.backgroundColor=Test.AnotherWay._g_record_border_normal_color;
2125                                 element.ownerDocument.body.appendChild( b );
2126                                 Test.AnotherWay._g_record_border.push( b );
2127                         }
2128                 }
2129                 var coords=null;
2130                 if( style=="border" ) {
2131                         coords=Test.AnotherWay._get_page_coords( element );
2132                 }else if( style=="ball" ) {
2133                         if( event!=null ) {
2134                                 if( event.pageX!=null && event.pageY!=null ) {
2135                                         coords={ x: event.pageX-0, y: event.pageY-0 };
2136                                 }else if( event.clientX!=null && event.clientY!=null ) {
2137                                         var doc=element.ownerDocument;
2138                                         if( doc!=null ) {
2139                                                 coords={ x: (event.clientX-0)+doc.body.scrollLeft, y: (event.clientY-0)+doc.body.scrollTop };
2140                                         }
2141                                 }
2142                         }
2143                 }
2144                 if( coords!=null && element.clientWidth!=null && element.clientHeight!=null ) {
2145                         var positions=[];
2146                         Test.AnotherWay._record_setup_highlight_positions( element, style, coords, positions );
2147                         for( var i=0; i<positions.length; ++i ) {
2148                                 var b=Test.AnotherWay._g_record_border[i];
2149                                 var p=positions[i];
2150                                 Test.AnotherWay._set_page_coords( b, p.x, p.y );
2151                                 b.style.width=p.width+"px";
2152                                 b.style.height=p.height+"px";
2153                                 b.style.display="block";
2154                         }
2155                 }
2156         }else {
2157                 if( Test.AnotherWay._g_record_border!=null ) {
2158                         for( var i=0; i<Test.AnotherWay._g_record_border.length; ++i ) {
2159                                 Test.AnotherWay._g_record_border[i].style.display="none";
2160                         }
2161                 }
2162         }
2163 }
2164 Test.AnotherWay._record_flash_border=function( color )
2165 {
2166         if( Test.AnotherWay._g_record_border_flashing ) { //already
2167                 Test.AnotherWay._g_record_border_flashes.push( { color: Test.AnotherWay._g_record_border_normal_color, timeout:300 } );
2168                 Test.AnotherWay._g_record_border_flashes.push( { color: color, timeout:600 } );
2169         }else {
2170                 Test.AnotherWay._g_record_border_flashing=true;
2171                 Test.AnotherWay._g_record_border_flashes.push( { color: color, timeout:600 } );
2172                 Test.AnotherWay._record_flash_border_timeout();
2173         }
2174 }
2175 Test.AnotherWay._record_prepare_doc_for_results=function()
2176 {
2177         document.open();
2178         document.write( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">" );
2179         document.write( "<html><head><title> Input recording results</title>" );
2180         document.write( "<style type=\"text/css\">" );
2181         document.write( "body { font: normal normal smaller sans-serif; }" );
2182         document.write( "div { margin-top: 3px; }" );
2183         document.write( "</style></head><body>" );
2184         // opera and mozilla disagree over who the opener is.
2185         if( typeof( window.opener.Test )!="undefined" && typeof( window.opener.Test.AnotherWay )!="undefined" ) {
2186                 window.opener.Test.AnotherWay._record_save_results( document );
2187                 window.opener.Test.AnotherWay._g_record_waiting_for_results=false;
2188                 window.opener.Test.AnotherWay._record_control_update_ui();
2189         }else if( typeof( window.opener.opener.Test  )!="undefined" && typeof( window.opener.opener.Test.AnotherWay )!="undefined" ) {
2190                 window.opener.opener.Test.AnotherWay._record_save_results( document );
2191                 window.opener.opener.Test.AnotherWay._g_record_waiting_for_results=false;
2192                 window.opener.opener.Test.AnotherWay._record_control_update_ui();
2193         }
2194         document.write( "</body>" );
2195         document.close();
2196 }
2197
2198 // global initialization
2199 onload=function()
2200 {
2201         if( window.opera ) {
2202                 var good_opera=typeof( window.opera.version )=="function";
2203                 good_opera=good_opera && window.opera.version().match( /^\s*(\d+)/ );
2204                 good_opera=good_opera && RegExp.$1>=8;
2205         }
2206         var span=document.createElement( "SPAN" );
2207         span.innerHTML="<!--[if IE]><br /><![endif]-"+"->";
2208         var is_ie=span.getElementsByTagName( "BR" ).length>0;
2209
2210         Test.AnotherWay._g_test_iframe=window.frames.test_iframe;
2211
2212         var query_str=window.location.search;
2213         if( query_str.charAt( 0 )=="?" ) {
2214                 query_str=query_str.substring( 1 );
2215         }
2216         var testlist_page="list-tests.html";
2217         var auto_run=false;
2218         if( query_str!="" ) {
2219                 var params=[query_str];
2220                 if( query_str.indexOf( ";" )!=-1 ) {
2221                         params=query_str.split( ";" );
2222                 }else if( query_str.indexOf( "&" )!=-1 ) {
2223                         params=query_str.split( "&" );
2224                 }
2225                 for( var param_i=0; param_i<params.length; ++param_i ) {
2226                         var param=params[param_i].split( "=" );
2227                         if( param[0]=="recording_results" ) {
2228                                 if( window.opener!=null ) {
2229                                         // we were told to show recording results - replace everything in the document with the results
2230                                         Test.AnotherWay._record_prepare_doc_for_results();
2231                                         return;
2232                                 }
2233                         }else if( param[0]=="testpage" ) {
2234                                 Test.AnotherWay._add_test_page_url( decodeURIComponent( param[1] ), "anotherway" );
2235                         }else if( param[0]=="jsantestpage" ) {
2236                                 Test.AnotherWay._add_test_page_url( decodeURIComponent( param[1] ), "jsan" );
2237                         }else if( param[0]=="testlist" ) {
2238                                 testlist_page=decodeURIComponent( param[1] );
2239                         }else if( param[0]=="testframe" ) {
2240                                 if( window.opera && !good_opera ) {
2241                                         Test.AnotherWay._show_error( "testframe parameter does not work in versions of Opera prior to 8.0. Sorry (pathches are welcome)." );
2242                                         // Opera 7 barfs on attempt to access frame.frameElement.
2243                                         // if someone knows a way to assign onload handler to that iframe in Opera 7
2244                                         // without disrupting code that works in other browsers, patches are welcome.
2245                                 }else {
2246                                         var frame_path=param[1].split( "." );
2247                                         var frame=top;
2248                                         for( var frame_path_i=0; frame_path_i<frame_path.length; ++frame_path_i ) {
2249                                                 frame=frame[frame_path[frame_path_i]];
2250                                         }
2251                                         if( frame==null ) {
2252                                                 Test.AnotherWay._show_error( "unable to find frame specified for loading test pages: "+param[1] );
2253                                         }else {
2254                                                 if( frame.frameElement!=null ) { // for the following assignement to onload to work, frameElement is required
2255                                                         frame=frame.frameElement;
2256                                                 }
2257                                                 Test.AnotherWay._g_test_iframe=frame;
2258                                         }
2259                                 }
2260                         }else if( param[0]=="testframe_no_clear" ) {
2261                                 Test.AnotherWay._g_test_frame_no_clear=true;
2262                         }else if( param[0]=="windows" ) {
2263                 if (param[1] == "none") {
2264                 }
2265                         }else if( param[0]=="run" ) {
2266                                 auto_run=true;
2267                                 if( param[1]=="all" ) {
2268                                         Test.AnotherWay._g_pages_to_run="all";
2269                                 }else {
2270                                         if( Test.AnotherWay._g_pages_to_run==null || Test.AnotherWay._g_pages_to_run=="all" ) {
2271                                                 Test.AnotherWay._g_pages_to_run=[];
2272                                         }
2273                                         var pages=param[1].split( "," );
2274                                         for( var i=0; i<pages.length; ++i ) {
2275                                                 Test.AnotherWay._g_pages_to_run.push( pages[i] );
2276                                         }
2277                                 }
2278                         }
2279                 }
2280         }
2281         if( Test.AnotherWay._g_test_page_urls.length==0 ) {  // if no individual pages were given on the command line, load the list
2282                 var result=Test.AnotherWay._set_iframe_location( window.frames["list_iframe"], testlist_page );
2283                 if( result.msg!=null ) {
2284                         Test.AnotherWay._show_error( result.msg );
2285                 }
2286                 Test.AnotherWay._g_run_on_list_load=auto_run;
2287         }else {
2288                 Test.AnotherWay._g_run_on_main_load=auto_run;
2289         }
2290
2291         var f=Test.AnotherWay._g_test_iframe;
2292         try {
2293                 if( f.attachEvent!=null ) {
2294                         f.attachEvent( "onload", Test.AnotherWay._test_page_onload );
2295                 }else {
2296                         f.onload=Test.AnotherWay._test_page_onload;
2297                 }
2298                 if( Test.AnotherWay._g_test_iframe.nodeType!=null && Test.AnotherWay._g_test_iframe.contentWindow!=null ) { // it's iframe element, not the iframe. we need iframe.
2299                         Test.AnotherWay._g_test_iframe=Test.AnotherWay._g_test_iframe.contentWindow;
2300                 }
2301         }catch(e) {
2302                 // ignore stupid opera error if the frame has onload handler assigned in the inline html
2303         }
2304         var handlers={
2305                 "run_all": { "onclick": Test.AnotherWay._run_all_onclick },
2306                 "run_selected": { "onclick": Test.AnotherWay._run_selected_onclick },
2307                 "unselect_all": { "onclick": Test.AnotherWay._unselect_all_onclick },
2308                 "record_select": { "onfocus": Test.AnotherWay._record_check_onfocus },
2309                 "record_input": { "onfocus": Test.AnotherWay._record_check_onfocus },
2310                 "record_start": { "onclick": Test.AnotherWay._record_start_onclick },
2311                 "clear_btn": { "onclick": Test.AnotherWay._results_clear_onclick },
2312                 "results_tab": { "onclick": Test.AnotherWay._tab_onclick, "onmouseover": Test.AnotherWay._tab_mouseover, "onmouseout": Test.AnotherWay._tab_mouseout },
2313                 "debug_tab": { "onclick": Test.AnotherWay._tab_onclick, "onmouseover": Test.AnotherWay._tab_mouseover, "onmouseout": Test.AnotherWay._tab_mouseout }
2314         };
2315         for( var hs in handlers ) {
2316                 var o=document.getElementById( hs );
2317                 if( o!=null ) {
2318                         for( var h in handlers[hs] ) {
2319                                 o[h]=handlers[hs][h];
2320                         }
2321                 }else {
2322                         Test.AnotherWay._show_error( "unable to set "+h+" handler: id "+hs+" not found" );
2323                 }
2324         }
2325
2326         if( window.opera && !good_opera ) {
2327                 Test.AnotherWay._g_no_record_msg="Input events recording and replaying is not available in opera versions prior to 8.0.";
2328         }
2329         if( is_ie ) {
2330                 Test.AnotherWay._g_no_record_msg="Input events recording and replaying is not available in internet explorer.";
2331         }
2332         if( Test.AnotherWay._g_no_record_msg!=null ) {
2333                 var no_record_p=document.getElementById( "record_not_supported" );
2334                 no_record_p.style.display="block";
2335                 no_record_p.appendChild( document.createTextNode( Test.AnotherWay._g_no_record_msg ) );
2336         }
2337
2338         Test.AnotherWay._g_main_loaded=true;
2339         if( Test.AnotherWay._g_run_on_main_load ) {
2340                 Test.AnotherWay._g_run_on_main_load=false;
2341                 Test.AnotherWay._run_pages_to_run();
2342         }
2343 }
2344 Test.AnotherWay._test_object_t.prototype.open_window=null;
2345 // -->
2346 </script>
2347 <script type="text/javascript" src="xml_eq.js"></script>
2348 <script type="text/javascript" src="geom_eq.js"></script>
2349 </head><body>
2350
2351 <div id="col1">
2352 <div id="col1_header">Test pages:</div>
2353 <div id="scroller">
2354 <table id="testtable">
2355 </table>
2356 </div>
2357 <div id="run_buttons">
2358 <input type="button" value=" clear " id="clear_btn" />
2359 <input type="button" value=" run all " id="run_all" />
2360 <input type="button" value=" run selected " id="run_selected" />
2361 <input type="button" value=" unselect all " id="unselect_all" />
2362 </div>
2363 <input type="checkbox" id="dont_close_test_windows" /> do not close windows opened by tests
2364 <div id="error"></div>
2365 <div id="record_div">
2366 <p id="record_not_supported" style="display:none"></p>
2367 <p>Record mouse input for the page:</p>
2368 <p><input type="radio" name="record_choose" value="select" checked="checked" /> <select id="record_select"><option selected="selected">-- select a page: --</option></select></p>
2369 <p><input type="radio" name="record_choose" value="input" /> or enter page url: <input type="text" id="record_input" /></p>
2370 <p><input type="button" value=" record " id="record_start" /></p>
2371 </div>
2372 </div>
2373
2374 <div id="col2">
2375 <div id="right_header">
2376 <span id="results_count">Results: <span id="total"></span></span>
2377 <span id="results_tab" class="active_tab" style="visibility:hidden">Results</span>
2378 <span id="debug_tab" class="inactive_tab" style="visibility:hidden">Debug</span>
2379 </div>
2380 <div id="right_frame">
2381 <div id="results"></div>
2382 <div id="debug"></div>
2383 </div>
2384 </div>
2385
2386 <span style="display:none">
2387 <iframe name="list_iframe" onload="Test.AnotherWay._list_iframe_onload();"></iframe>
2388 <iframe name="test_iframe" onload="Test.AnotherWay._test_page_onload();"></iframe>
2389
2390 <!-- record_control div is to be imported into other documents, so all its styles are inline -->
2391 -<div id="record_control" style="position:absolute;bottom:0;left:0;margin:0;padding:0.5em;width:22em;height:22em;border:1px solid;background:#ffd;font: normal normal 8pt sans-serif; color:#000; text-align: left">
2392
2393 <p style="margin:0 0 0 0; padding:0">
2394 &nbsp;
2395 <span style="display:none;font-weight:bold;color:#408" id="record_indicator">
2396 recording. <span style="font-weight:normal">time: <span id="record_time"></span></span><span id="record_pause_indicator"> paused</span>
2397 </span>
2398 </p>
2399
2400 <div id="record_cursor_over" style="margin:0;padding:2px;width:14em;height:1.1em;overflow:hidden;float:right;border:1px solid #777;background:#fff;font: normal normal 8pt sans-serif;position:relative;top:3px;color:#000;text-align:left;">&nbsp;</div>
2401 <p style="margin:2px 0 0 0; padding:0">
2402 cursor is over
2403 </p>
2404
2405 <p style="margin:8px 0 0 0; padding:0;">
2406  keyboard control: press
2407  <span id="record_ctrl_key" style="border:1px solid #226;background:#adf;padding:0 0.5em">ctrl</span> -
2408  <span id="record_shift_key" style="border:1px solid #226;background:#adf;padding:0 0.5em">shift</span> -
2409 </p>
2410
2411 <p style="margin:4px 0 0 0; padding:0">
2412 <span id="record_s" style="border:1px solid #226;background:#adf;width:1.2em;float:left;font-weight:bold;text-align:center;margin-right:0.5em">s</span>
2413 <span id="record_on">to <b>start</b> recording</span>
2414 <span id="record_off" style="display:none">to <b>stop</b> recording</span>
2415 </p>
2416
2417 <p style="margin:4px 0 0 0; padding:0">
2418 <span id="record_h" style="border:1px solid #226;background:#adf;width:1.2em;float:left;font-weight:bold;text-align:center;margin-right:0.5em">h</span>
2419 <span>to <b>hide/show</b> this window</span>
2420 </p>
2421
2422 <p style="margin:4px 0 0 0; padding:0">
2423 <span id="record_m" style="border:1px solid #226;background:#adf;width:1.2em;float:left;font-weight:bold;text-align:center;margin-right:0.5em">m</span>
2424 <span id="record_include_mousemove">to <b> record</b> mousemove</span>
2425 <span id="record_omit_mousemove" style="display:none">to <b>omit</b> mousemove</span>
2426 </p>
2427
2428 <p style="margin:4px 0 0 0; padding:0">
2429 <span id="record_p" style="border:1px solid #226;background:#aaa;width:1.2em;float:left;font-weight:bold;text-align:center;margin-right:0.5em">p</span>
2430 <span id="record_pause_on">to <b> pause</b> recording</span>
2431 <span id="record_pause_off" style="display:none">to <b>continue</b> recording</span>
2432 </p>
2433
2434 <p style="margin:4px 0 0 0; padding:0">
2435 <span id="record_c" style="border:1px solid #226;background:#aaa;width:1.2em;float:left;font-weight:bold;text-align:center;margin-right:0.5em">c</span>
2436 <span>to add checkpoint</span>
2437 </p>
2438
2439 <p style="margin:6px 0 0 0; padding:0">
2440 checkpoints:
2441 </p>
2442 <div id="record_checkpoints" style="position:relative;width:100%;height:6em;overflow:auto;font: normal normal 8pt sans-serif; color:#000; text-align: left">
2443 </div>
2444 </div>
2445
2446 </span>
2447 </body></html>