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