Project

General

Profile

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 27em; }
34
#col1_header { margin-top: 0.5em; }
35
#scroller { height: 550px; 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.appendChild( cell_child );
149

    
150
	cell=row.insertCell( -1 );
151
	cell.setAttribute( "width", "75%" );
152
	cell.appendChild( document.createTextNode( test_url ) );
153

    
154
	cell=row.insertCell( -1 );
155
	cell_child=document.createElement( "input" );
156
	cell_child.type="button";
157
	cell_child.id="test"+index;
158
	cell_child.value=" run ";
159
	cell_child.onclick=Test.AnotherWay._run_one_onclick;
160
	cell.appendChild( cell_child );
161

    
162
	cell=row.insertCell( -1 );
163
	cell.setAttribute( "width", "8em" );
164
	cell_child=document.createElement( "span" );
165
	cell.appendChild( cell_child );
166

    
167
	var option=document.createElement( "option" );
168
	option.appendChild( document.createTextNode( test_url ) );
169
	record_select.appendChild( option );
170
}
171
Test.AnotherWay._show_error=function( msg )
172
{
173
	var error_div=document.getElementById( "error" );
174
	error_div.innerHTML="";
175
	error_div.appendChild( document.createTextNode( msg ) );
176
	error_div.style.display="block";
177
}
178

    
179
// read urls from the list in the html file inside the list_iframe
180
// fill on-screen list with urls and "run" buttons, and fill the g_test_page_urls object.
181
Test.AnotherWay._list_iframe_onload=function()
182
{
183
	if( window.frames.list_iframe!=null && window.frames.list_iframe.location!="" && window.frames.list_iframe.location!="about:blank" ) {
184
		var list_doc=window.frames.list_iframe.document;
185
		var list=list_doc.getElementById( "testlist" );
186
		if( list!=null ) {
187
			for( var i=0; i<list.childNodes.length; ++i ) {
188
				var item=list.childNodes[i];
189
				if( item.nodeName=="LI" || item.nodeName=="li" ) {
190
					var convention="anotherway";
191
					if( Test.AnotherWay._get_css_class( item )=="jsan" ) {
192
						convention="jsan";
193
					}
194
					Test.AnotherWay._add_test_page_url( item.innerHTML, convention );
195
				}
196
			}
197
			if( Test.AnotherWay._g_run_on_list_load ) {
198
				Test.AnotherWay._g_run_on_list_load=false;
199
				Test.AnotherWay._run_pages_to_run();
200
			}
201
		}else {
202
			Test.AnotherWay._show_error( "no list with id 'testlist' in a list file "+window.frames.list_iframe.location );
203
		}
204
	}
205
}
206

    
207
Test.AnotherWay._map_checkboxes=function( f )
208
{
209
	var table=document.getElementById( "testtable" );
210
	var checks=table.getElementsByTagName( "INPUT" );
211
	for( var i=0; i<checks.length; ++i ) {
212
		if( checks[i].type=="checkbox" && checks[i].id.match( /^checkbox(\d+)$/ ) ) {
213
			f( checks[i], RegExp.$1 );
214
		}
215
	}
216
}
217
Test.AnotherWay._run_all_onclick=function()
218
{
219
	Test.AnotherWay._map_checkboxes( function( c, id ) { Test.AnotherWay._run_test_page( "test"+id ); } );
220
}
221
Test.AnotherWay._run_selected_onclick=function()
222
{
223
	Test.AnotherWay._map_checkboxes( function( c, id ) { if( c.checked ) Test.AnotherWay._run_test_page( "test"+id ); } );
224
}
225
Test.AnotherWay._unselect_all_onclick=function()
226
{
227
	Test.AnotherWay._map_checkboxes( function( c, id ) { c.checked=false; } );
228
}
229
Test.AnotherWay._run_one_onclick=function()
230
{
231
	Test.AnotherWay._run_test_page( this.id );
232
}
233

    
234
// construct an object that will gather results of running one test function
235
Test.AnotherWay._test_object_t=function( fun_name )
236
{
237
	this.name=fun_name; // name of the test function
238
	this.n_plan=null; // planned number of assertions
239
	this.n_ok=0; // # of ok assertions
240
	this.n_fail=0; // # of failed assertions
241
	this.exception=""; // if the function throwed an exception, it's its message
242
	this.exception_stack=[]; // strings: function call stack from the exception
243
	this.assertions=[]; // assertion results: array of { ok: 1 or 0, name: string }
244
	this.wait_result_milliseconds=0; // how long to wait before collecting results from the test
245
	this.second_wait_msg=null; // <p> status message (in addition to the page wait_msg)
246
	this.delay_actions=[]; // array of actions to be perfomed after the test function returns
247
				//	action : { acton_kind: "call" | "window" | "replay"
248
				//				when "call": 		{ call_fn call_delay_milliseconds } call_fn takes nothing
249
				//				when "window" : 	{ wnd_url wnd_wnd wnd_fn wnd_timeout_milliseconds wnd_dont_close } wnd_fn takes wnd
250
				//				wnen "replay" : 	{ replay_wnd replay_events replay_event_i replay_checkpoints } checkpoint_fn takes this, wnd
251
				//	}
252
	this.delay_action_i=null; // index of delay action currently being performed
253
	this.delay_prev_timer_time=0;	// for counting time while performing delay_actions
254
	this.delay_current_milliseconds_left=0; // time left before the next action, runs down
255
	this.delay_total_milliseconds_left=0; 	// for indication: total estimated time for all actions, runs up and down
256
}
257

    
258
Test.AnotherWay._test_object_t.prototype.ok=function( cond, name )
259
{
260
	if( cond ) {
261
		++this.n_ok;
262
		cond=1;
263
	}else {
264
		++this.n_fail;
265
		cond=0;
266
	}
267
	this.assertions.push( { ok: cond, name: name } );
268
}
269
Test.AnotherWay._test_object_t.prototype.fail=function( name )
270
{
271
	this.ok( false, name );
272
}
273
Test.AnotherWay._test_object_t.prototype.plan=function( n )
274
{
275
	this.n_plan=n;
276
}
277
Test.AnotherWay._test_object_t.prototype.wait_result=function( seconds )
278
{
279
	this.wait_result_milliseconds=1000*seconds;
280
}
281
Test.AnotherWay._eq_fail_msg=function( path, what, expected, got )
282
{
283
	return "eq: "+path+" "+what+" differ: got "+got+", but expected "+expected;
284
}
285
Test.AnotherWay._array_eq=function( expected, got, path, msg )
286
{
287
	if( expected.length!=got.length ) {
288
		msg.msg=Test.AnotherWay._eq_fail_msg( path, "array length", expected.length, got.length );
289
		return false;
290
	}
291
	for( var i=0; i<expected.length; ++i ) {
292
		if( !Test.AnotherWay._thing_eq( expected[i], got[i], path+"["+i+"]", msg ) ) {
293
			return false;
294
		}
295
	}
296
	return true;
297
}
298
Test.AnotherWay._object_eq=function( expected, got, path, msg )
299
{
300
	var v;
301
	for( v in expected ) {
302
		if( ! (v in got) ) {
303
			msg.msg=Test.AnotherWay._eq_fail_msg( path+"."+v, "properties", expected[v], "undefined" );
304
			return false;
305
		}
306
		if( !Test.AnotherWay._thing_eq( expected[v], got[v], path+"."+v, msg ) ) {
307
			return false;
308
		}
309
	}
310
	for( v in got ) {
311
		if( ! (v in expected) ) {
312
			msg.msg=Test.AnotherWay._eq_fail_msg( path+"."+v, "properties", "undefined", got[v] );
313
			return false;
314
		}
315
	}
316
	return true;
317
}
318
Test.AnotherWay._constructor_name=function( x )
319
{
320
	if( x==null ) {
321
		return "";
322
	}
323
	var s="unknown";
324
	try {
325
		s=typeof( x.constructor );
326
		if( s!="unknown" ) {
327
			s=x.constructor.toString();
328
		}
329
	}catch( e ) {
330
		s="unknown";
331
	}
332
	if( s=="unknown" ) {
333
		// hackish attempt to guess a type
334
		var is_array=true;
335
		var index=0;
336
		for( i in x ) {
337
			if( i!=index ) {
338
				is_array=false;
339
			}
340
			++index;
341
		}
342
		return is_array ? "Array" : "Object"; // for empty arrays/objects, this will be wrong half the time
343
	}else if( s.match( /^\s*function\s+(\w+)\s*\(/ ) ) {
344
		return RegExp.$1;
345
	}else {
346
		return "";
347
	}
348
}
349
Test.AnotherWay._is_array=function( x )
350
{
351
	return Test.AnotherWay._constructor_name( x )=="Array";
352
}
353
Test.AnotherWay._is_value_type=function( x )
354
{
355
	cn=Test.AnotherWay._constructor_name( x );
356
	return cn=="Number" || cn=="String" || cn=="Boolean" || cn=="Date";
357
}
358
Test.AnotherWay._thing_eq=function( expected, got, path, msg )
359
{
360
	if( expected==null && got==null ) {
361
		return true;
362
	}else if( (expected==null && got!=null) || (expected!=null && got==null) ) {
363
		msg.msg=Test.AnotherWay._eq_fail_msg( path, "values", expected, got );
364
		return false;
365
	}else {
366
		var expected_cn=Test.AnotherWay._constructor_name( expected );
367
		var got_cn=Test.AnotherWay._constructor_name( got );
368
		if( expected_cn!=got_cn ) {
369
			msg.msg=Test.AnotherWay._eq_fail_msg( path, "types", expected_cn, got_cn );
370
			return false;
371
		}else {
372
			if( Test.AnotherWay._is_array( expected ) ) {
373
				return Test.AnotherWay._array_eq( expected, got, path, msg );
374
			}else if( Test.AnotherWay._is_value_type( expected ) ) {
375
				if( expected!=got ) {
376
					msg.msg=Test.AnotherWay._eq_fail_msg( path, "values", expected, got );
377
					return false;
378
				}else {
379
					return true;
380
				}
381
			}else { // just a plain object
382
				return Test.AnotherWay._object_eq( expected, got, path, msg );
383
			}
384
		}
385
	}
386
}
387
Test.AnotherWay._test_object_t.prototype.eq=function( got, expected, name )
388
{
389
	var msg={};
390
	if( Test.AnotherWay._thing_eq( expected, got, "", msg ) ) {
391
		this.ok( 1, name );
392
	}else {
393
		this.fail( name+". "+msg.msg );
394
	}
395
}
396
Test.AnotherWay._test_object_t.prototype.like=function( got, expected, name )
397
{
398
	if( got.match( expected )!=null ) {
399
		this.ok( 1, name );
400
	}else {
401
		this.fail( name+": got "+got+", but expected it to match: "+expected );
402
	}
403
}
404
Test.AnotherWay._g_html_eq_span=null;
405
Test.AnotherWay._html_eq_string_to_node=function( string_or_node, what, msg )
406
{
407
	if( string_or_node.nodeType!=null ) {
408
		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
409
	}
410
	if( Test.AnotherWay._g_html_eq_span==null ) {
411
		Test.AnotherWay._g_html_eq_span=document.createElement( "span" );
412
	}
413
	Test.AnotherWay._g_html_eq_span.innerHTML=string_or_node;
414
	if( Test.AnotherWay._g_html_eq_span.childNodes.length!=1 ) {
415
		msg.msg="bad "+what+" html string given (should contain exactly one outermost element): "+string_or_node;
416
	}
417
	return Test.AnotherWay._g_html_eq_span.childNodes[0].cloneNode( true );
418
}
419
Test.AnotherWay._html_eq_node_to_string=function( node ) {
420
	if( Test.AnotherWay._g_html_eq_span==null ) {
421
		Test.AnotherWay._g_html_eq_span=document.createElement( "span" );
422
	}
423
	Test.AnotherWay._g_html_eq_span.innerHTML="";
424
	if( node.outerHTML!=null ) {
425
		Test.AnotherWay._g_html_eq_span.innerHTML=node.outerHTML;
426
	}else {
427
		Test.AnotherWay._g_html_eq_span.appendChild( node.cloneNode( true ) );
428
	}
429
	return Test.AnotherWay._g_html_eq_span.innerHTML;
430
}
431
Test.AnotherWay._html_eq_path_msg=function( path )
432
{
433
	var msg="";
434
	for( var i=0; i<path.length; ++i ) {
435
		msg+=" [node "+path[i].node;
436
		if( path[i].id!=null && path[i].id!="" ) {
437
			msg+=" id "+path[i].id;
438
		}else if( path[i].index!=null ) {
439
			msg+=" at index "+path[i].index;
440
		}
441
		msg+="] "
442
	}
443
	return msg;
444
}
445
Test.AnotherWay._html_eq_fail_msg=function( path, what, expected, got )
446
{
447
	return Test.AnotherWay._html_eq_path_msg( path )+": "+what+" differ: got "+got+", but expected "+expected;
448
}
449
Test.AnotherWay._html_eq_remove_blank=function( text )
450
{
451
	if( text==null ) {
452
		return "";
453
	}else if( text.match( "^(\\s*)(.*\\S)(\\s*)$" ) ) {
454
		return RegExp.$2;
455
	}else if( text.match( "\s*" ) ) {
456
		return "";
457
	}
458
	return text;
459
}
460
Test.AnotherWay._html_eq_remove_blank_nodes=function( node )
461
{
462
	var to_remove=[];
463
	for( var child=node.firstChild; child!=null; child=child.nextSibling ) {
464
		if( child.nodeType==3 ) {
465
			var value=Test.AnotherWay._html_eq_remove_blank( child.nodeValue );
466
			if( value=="" ) {
467
				to_remove.push( child );
468
			}else {
469
				child.nodeValue=value;
470
			}
471
		}
472
	}
473
	for( var i=0; i<to_remove.length; ++i ) {
474
		node.removeChild( to_remove[i] );
475
	}
476
}
477
Test.AnotherWay._html_node_type_text=function( node_type )
478
{
479
	if( node_type==1 ) {
480
		return "1 (html element)";
481
	}else if( node_type==3 ) {
482
		return "3 (text)";
483
	}else {
484
		return node_type;
485
	}
486
}
487
Test.AnotherWay._html_eq_node=function( expected, got, path, msg, expected_loc_base, got_loc_base )
488
{
489
	if( expected.nodeType!=got.nodeType ) {
490
		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 ) );
491
		return false;
492
	}else if( expected.nodeType==3 ) {
493
		if( expected.nodeValue!=got.nodeValue ) {
494
			msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "text", expected.nodeValue, got.nodeValue );
495
			return false;
496
		}
497
	}else if( expected.nodeType==1 ) {
498
		if( expected.nodeName!=got.nodeName ) {
499
			msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "node names", expected.nodeName, got.nodeName );
500
			return false;
501
		}
502
		// compare attributes
503
		var expected_attrs={};
504
		var got_attrs={};
505
		var i;
506
		var a;
507
		for( i=0; i<expected.attributes.length; ++i ) {
508
			a=expected.attributes[i];
509
			if( a.specified ) {
510
				expected_attrs[a.name]=1;
511
			}
512
		}
513
		for( i=0; i<got.attributes.length; ++i ) {
514
			a=got.attributes[i];
515
			if( a.specified ) {
516
				got_attrs[a.name]=1;
517
			}
518
		}
519
		for( a in expected_attrs ) {
520
			if( ! (a in got_attrs) ) {
521
				msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": attribute sets differ: expected attribute "+a+" is missing";
522
				return false;
523
			}
524
		}
525
		for( a in got_attrs ) {
526
			if( ! (a in expected_attrs) ) {
527
				msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": attribute sets differ: got extra attribute "+a;
528
				return false;
529
			}
530
		}
531
		for( a in expected_attrs ) {
532
			var expected_value=expected.getAttribute( a );
533
			var got_value=got.getAttribute( a );
534
			if( typeof( expected_value )=="string" && typeof( got_value )=="string" ) {
535
				expected_value=Test.AnotherWay._html_eq_remove_blank( expected_value );
536
				got_value=Test.AnotherWay._html_eq_remove_blank( got_value );
537
				var ok=expected_value==got_value;
538
				if( !ok && (a=="href" || a=="HREF" )  ) { // try relative hrefs
539
					var expected_relative_value=expected_value;
540
					if( expected_loc_base!=null && expected_value.substring( 0, expected_loc_base.length )==expected_loc_base ) {
541
						expected_relative_value=expected_value.substring( expected_loc_base.length );
542
					}
543
					var got_relative_value=got_value;
544
					if( got_loc_base!=null && got_value.substring( 0, got_loc_base.length )==got_loc_base ) {
545
						got_relative_value=got_value.substring( got_loc_base.length );
546
					}
547
					ok=expected_relative_value==got_relative_value;
548
				}
549
				if( !ok ) {
550
					msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "attribute "+a+" values", expected_value, got_value );
551
					return false;
552
				}
553
			}else if( typeof( expected_value )=="function" && typeof( got_value )=="function" ) {
554
				expected_value=expected_value.toString();
555
				got_value=got_value.toString();
556
				if( expected_value!=got_value ) {
557
					msg.msg=Test.AnotherWay._html_eq_fail_msg( path, "attribute "+a+" values", expected_value, got_value );
558
					return false;
559
				}
560
			}else {
561
				var value_msg={};
562
				if( !Test.AnotherWay._thing_eq( expected_value, got_value, "", value_msg ) ) {
563
					msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": attribute "+a+" values differ: "+value_msg.msg;
564
					return false;
565
				}
566
			}
567
		}
568
		// compare child nodes
569
		Test.AnotherWay._html_eq_remove_blank_nodes( expected );
570
		Test.AnotherWay._html_eq_remove_blank_nodes( got );
571
		var expected_length=expected.childNodes.length;
572
		var got_length=got.childNodes.length;
573
		if( expected_length<got_length ) {
574
			msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": got "+(got_length-expected_length)+" extra child nodes";
575
			return false;
576
		}else if( expected_length>got_length ) {
577
			msg.msg=Test.AnotherWay._html_eq_path_msg( path )+": expected "+(expected_length-got_length)+" more child nodes";
578
			return false;
579
		}else {
580
			for( i=0; i<expected_length; ++i ) {
581
				var expected_node=expected.childNodes[i];
582
				path.push( { node: expected_node.nodeName, id: expected_node.id, index: i } );
583
				var eq=Test.AnotherWay._html_eq_node( expected_node, got.childNodes[i], path, msg, expected_loc_base, got_loc_base );
584
				path.pop();
585
				if( !eq ) {
586
					return false;
587
				}
588
			}
589
		}
590
	}
591
	return true;
592
}
593
Test.AnotherWay._html_eq_get_loc_base=function( node )
594
{
595
	var loc_base=document.location;
596
	if( node.ownerDocument!=null ) {
597
		loc_base=node.ownerDocument.location;
598
	}
599
	if( loc_base!=null ) {
600
		loc_base=loc_base.href;
601
		var slash_pos=loc_base.lastIndexOf( "/" );
602
		if( slash_pos!=-1 ) {
603
			loc_base=loc_base.substring( 0, slash_pos+1 );
604
		}
605
	}
606
	return loc_base;
607
}
608
Test.AnotherWay._test_object_t.prototype.html_eq=function( got, expected, name )
609
{
610
	var msg={};
611
	var expected_node=Test.AnotherWay._html_eq_string_to_node( expected, "expected", msg );
612
	if( msg.msg!=null ) {
613
		this.fail( name+" html_eq: "+msg.msg );
614
	}else {
615
		var got_node=Test.AnotherWay._html_eq_string_to_node( got, "got", msg );
616
		if( msg.msg!=null ) {
617
			this.fail( name+" html_eq: "+msg.msg );
618
		}else {
619
			var expected_loc_base=Test.AnotherWay._html_eq_get_loc_base( expected );
620
			var got_loc_base=Test.AnotherWay._html_eq_get_loc_base( got );
621
			if( Test.AnotherWay._html_eq_node( expected_node, got_node, [], msg, expected_loc_base, got_loc_base ) ) {
622
				this.ok( 1, name );
623
			}else {
624
				var msg=name+" html_eq "+msg.msg;
625
				var expected_str=Test.AnotherWay._html_eq_node_to_string( expected_node );
626
				var got_str=Test.AnotherWay._html_eq_node_to_string( got_node );
627
				msg+=".\n got html: "+got_str;
628
				msg+=".\n expected html: "+expected_str;
629
				this.fail( msg );
630
			}
631
		}
632
	}
633
}
634
Test.AnotherWay._debug_pane_print=function( msg )
635
{
636
	var d=new Date();
637
	var p=document.createElement( "p" );
638
	p.appendChild( document.createTextNode( d.toLocaleTimeString()+" "+msg ) );
639
	var debug_pane=document.getElementById( "debug" );
640
	debug_pane.appendChild( p );
641
	var debug_tab=document.getElementById( "debug_tab" );
642
	var results_tab=document.getElementById( "results_tab" );
643
	debug_tab.style.visibility="visible";
644
	results_tab.style.visibility="visible";
645
}
646
Test.AnotherWay._test_object_t.prototype.debug_print=function( msg )
647
{
648
	Test.AnotherWay._debug_pane_print( this.name+": "+msg );
649
}
650
Test.AnotherWay._test_object_t.prototype.delay_call=function()
651
{
652
	var timeout_ms=200;
653
	for( var i=0; i<arguments.length; ++i ) {
654
		if( typeof( arguments[i] )!="function" ) {
655
			timeout_ms=1000*arguments[i];
656
		}else {
657
			var action={ action_kind: "call", call_delay_milliseconds: timeout_ms, call_fn: arguments[i] };
658
			this.delay_total_milliseconds_left+=Test.AnotherWay._action_estimate_milliseconds( action );
659
			this.delay_actions.push( action );
660
		}
661
	}
662
}
663
Test.AnotherWay._test_object_t.prototype.open_window=function( url, fn, timeout_seconds )
664
{
665
	if( timeout_seconds==null ) {
666
		timeout_seconds=2;
667
	}
668
	var no_close=document.getElementById( "dont_close_test_windows" );
669
	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 };
670
	this.delay_total_milliseconds_left+=Test.AnotherWay._action_estimate_milliseconds( action );
671
	this.delay_actions.push( action );
672
}
673
Test.AnotherWay._test_object_t.prototype.replay_events=function( wnd, events )
674
{
675
	if( Test.AnotherWay._g_no_record_msg!=null ) {
676
		this.fail( "replay_events: "+Test.AnotherWay._g_no_record_msg );
677
	}else {
678
		var action={ action_kind: "replay", replay_wnd: wnd, replay_events: events.events, replay_event_i: null, replay_checkpoints: events.checkpoints };
679
		this.delay_total_milliseconds_left+=Test.AnotherWay._action_estimate_milliseconds( action );
680
		this.delay_actions.push( action );
681
	}
682
}
683
Test.AnotherWay._action_estimate_milliseconds=function( action )
684
{
685
	var ms=0;
686
	if( action.action_kind=="call" ) {
687
		ms=action.call_delay_milliseconds;
688
	}else if( action.action_kind=="window" ) {
689
		ms=0;
690
	}else if( action.action_kind=="replay" ) {
691
		ms=0;
692
		for( var i=0; i<action.replay_events.length; ++i ) {
693
			ms+=action.replay_events[i]["time"]-0;
694
		}
695
	}
696
	return ms;
697
}
698

    
699
Test.AnotherWay._g_timeout_granularity=200;
700
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 }
701

    
702
// load one html page, schedule further processing
703
Test.AnotherWay._run_test_page=function( id, called_from_outside )
704
{
705
	if( id.match( /^test(\d+)/ ) ) {
706
		id=RegExp.$1;
707
		Test.AnotherWay._g_tests_queue.push( {
708
			url: Test.AnotherWay._g_test_page_urls[id].url,
709
			convention: Test.AnotherWay._g_test_page_urls[id].convention,
710
			test_objects: []
711
			} );
712
		if( Test.AnotherWay._g_tests_queue.length==1 ) {
713
			if( !called_from_outside ) {
714
				// Crap. Be careful stepping around.
715
				// For Mozilla and Opera, when this file is included into the frameset page that is in another directory (and _g_outside_path_correction!=null)
716
				// but the test pages are started from within it (by "run" buttons), then:
717
				// depending on whether the page is the first one loaded into the test frame or not,
718
				// the base url for relative test pages differs.
719
				// Crap, like I said.
720
				Test.AnotherWay._g_tests_queue[0].suppress_outside_path_correction=true;
721
			}
722
			Test.AnotherWay._start_loading_page();
723
		}
724
	}
725
}
726
Test.AnotherWay._load_next_page=function()
727
{
728
	Test.AnotherWay._g_tests_queue.splice( 0, 1 );
729
	if( Test.AnotherWay._g_tests_queue.length>0 ) {
730
		Test.AnotherWay._start_loading_page();
731
	}else {
732
		if( !Test.AnotherWay._g_test_frame_no_clear ) {
733
			Test.AnotherWay._g_test_iframe.location.replace( "about:blank" );
734
		}
735
	}
736
}
737
Test.AnotherWay._g_opera_path_correction=null; // ugly wart to support opera
738
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
739
Test.AnotherWay._set_iframe_location=function( iframe, loc, outside_path_correction )
740
{
741
	// allow to load only locations with the same origin
742
	var proto_end=loc.indexOf( "://" );
743
	if( proto_end!=-1 ) { // otherwise, it's safe to assume (for Opera, Mozilla and IE ) that loc will be treated as relative
744
		var main_loc=window.location.href;
745
		var host_end=loc.substring( proto_end+3 ).indexOf( "/" );
746
		var ok=false;
747
		if( host_end!=-1 ) {
748
			var loc_origin=loc.substring( 0, proto_end+3+host_end+1 );
749
			if( main_loc.length>=loc_origin.length && main_loc.substring( 0, loc_origin.length )==loc_origin ) {
750
				ok=true;
751
			}
752
		}
753
		if( !ok ) {
754
			return { msg: "test pages may have only urls with the same origin as "+main_loc };
755
		}
756
	}
757
	// opera cannot handle urls relative to file:// without assistance
758
	if( window.opera!=null && window.location.protocol=="file:" && loc.indexOf( ":" )==-1 ) {
759
		var base=window.location.href;
760
		var q_pos=base.indexOf( "?" );
761
		if( q_pos!=-1 ) {
762
			base=base.substring( 0, q_pos );
763
		}
764
		var slash_pos=base.lastIndexOf( "/" );
765
		if( slash_pos!=-1 ) {
766
			base=base.substring( 0, slash_pos+1 );
767
			Test.AnotherWay._g_opera_path_correction=base;
768
			loc=base+loc;
769
		}
770
	}
771
	// if this function is called from another page, and if that page is in another directory, correction is needed
772
	if( outside_path_correction!=null ) {
773
		var pos=loc.indexOf( outside_path_correction );
774
		if( pos==0 ) {
775
			loc=loc.substring( outside_path_correction.length+1 );
776
		}
777
	}
778
	if( iframe.location!=null ) {
779
		iframe.location.replace( loc );
780
	}else {
781
		iframe.src=loc;
782
	}
783
	return {};
784
}
785
Test.AnotherWay._start_loading_page=function()
786
{
787
	var test_page=Test.AnotherWay._g_tests_queue[0];
788
	test_page.loading_timeout_milliseconds=2000;
789
	test_page.timeout_id=setTimeout( Test.AnotherWay._loading_timeout, Test.AnotherWay._g_timeout_granularity );
790
	test_page.wait_msg=Test.AnotherWay._print_counter_result( test_page.url, "loading...", test_page.loading_timeout_milliseconds, "loading" );
791
	if( test_page.convention=="jsan" ) {
792
		// the tests in that page will run when it's loading, so the test object must be ready
793
		Test.AnotherWay._g_test_object_for_jsan=new Test.AnotherWay._test_object_t( test_page.url );
794
	}
795
	var outside_path_correction=null;
796
	if( Test.AnotherWay._g_outside_path_correction!=null && !test_page.suppress_outside_path_correction ) {
797
		outside_path_correction=Test.AnotherWay._g_outside_path_correction;
798
	}
799
	var result=Test.AnotherWay._set_iframe_location( Test.AnotherWay._g_test_iframe, test_page.url, outside_path_correction );
800
	if( result.msg!=null ) {
801
		Test.AnotherWay._unprint_result( test_page.wait_msg );
802
		Test.AnotherWay._print_result( test_page.url, result.msg, "badtest", null );
803
		Test.AnotherWay._load_next_page();
804
	}
805
}
806

    
807
Test.AnotherWay._loading_timeout=function()
808
{
809
	var test_page=Test.AnotherWay._g_tests_queue[0];
810
	test_page.loading_timeout_milliseconds-=Test.AnotherWay._g_timeout_granularity;
811
	if( test_page.loading_timeout_milliseconds>0 ) {
812
		Test.AnotherWay._update_msg_counter( test_page.wait_msg, (test_page.loading_timeout_milliseconds/1000).toFixed() );
813
		test_page.timeout_id=setTimeout( Test.AnotherWay._loading_timeout, Test.AnotherWay._g_timeout_granularity );
814
	}else {
815
		Test.AnotherWay._unprint_result( test_page.wait_msg );
816
		Test.AnotherWay._print_result( test_page.url, "Unable to load test page. Timeout expired", "badtest", null );
817
		Test.AnotherWay._load_next_page();
818
	}
819
}
820

    
821
Test.AnotherWay._strip_query_and_hash=function( s )
822
{
823
	var i=s.lastIndexOf( "#" );
824
	if( i!=-1 ) {
825
		s=s.substring( 0, i );
826
	}
827
	i=s.lastIndexOf( "?" );
828
	if( i!=-1 ) {
829
		s=s.substring( 0, i );
830
	}
831
	return s;
832
}
833
Test.AnotherWay._is_url_loaded=function( url, wnd )
834
{
835
	var loaded=false;
836
	if( wnd!=null && wnd.location!=null ) {
837
		// after some popup blocker interference, location may behave strange..
838
		var location_s="";
839
		location_s+=wnd.location;
840
		if( location_s!="" ) {
841
			var pathname=wnd.location.pathname;
842
			var expected_url=url;
843
			var i=expected_url.lastIndexOf( "#" );
844
			if( i!=-1 ) {
845
				expected_url=expected_url.substring( 0, i );
846
			}
847
			i=expected_url.lastIndexOf( "?" );
848
			if( i!=-1 ) {
849
				expected_url=expected_url.substring( 0, i );
850
			}
851
			i=expected_url.lastIndexOf( "/" );
852
			if( i!=-1 && i!=expected_url.length-1 ) {
853
				expected_url=expected_url.substring( i+1 );
854
			}
855
			i=pathname.indexOf( expected_url )
856
			if( wnd.location.href==url || (i!=-1 && i==pathname.length-expected_url.length) ) {
857
				if( /*window.opera==null*/wnd.document.readyState==null || wnd.document.readyState=="complete" ) { // for opera (and IE?), getElementById does not work until..
858
					loaded=true;
859
				}
860
			}
861
		}
862
	}
863
	return loaded;
864
}
865
// find and run all test functions in the g_cur_page html page.
866
Test.AnotherWay._test_page_onload=function()
867
{
868
	if( Test.AnotherWay._g_tests_queue.length==0 ) {
869
		return;
870
	}
871
	var test_page=Test.AnotherWay._g_tests_queue[0];
872
	if( !Test.AnotherWay._is_url_loaded( test_page.url, Test.AnotherWay._g_test_iframe ) ) {
873
		return;
874
	}
875
	clearTimeout( test_page.timeout_id );
876
	Test.AnotherWay._unprint_result( test_page.wait_msg );
877

    
878
	if( test_page.convention=="anotherway" ) {
879
		// get test function names (those beginning with "test")
880
		if( typeof( Test.AnotherWay._g_test_iframe.document.scripts )!='undefined' ) { // IE
881
			for( var i=0; i<Test.AnotherWay._g_test_iframe.document.scripts.length; ++i ) {
882
				var script_text=Test.AnotherWay._g_test_iframe.document.scripts[i].text;
883
				var fun_sig="function test";
884
				var fun_start=script_text.indexOf( fun_sig );
885

    
886
				while( fun_start!=-1 ) {
887
					script_text=script_text.substring( fun_start, script_text.length );
888
					var fun_end=script_text.indexOf( '(' );
889
					var fun_name=script_text.substring( "function ".length,  fun_end );
890
                                        var whitespace = fun_name.indexOf( ' ' );
891
                                        if (whitespace >= 0)
892
                                            fun_name = fun_name.substring( 0, whitespace );
893
					test_page.test_objects.push( new Test.AnotherWay._test_object_t( fun_name ) );
894
					script_text=script_text.substring( fun_end, script_text.length );
895
					fun_start=script_text.indexOf( fun_sig  );
896
				}
897
			}
898
		}else { // otherwise (not IE) it ought to work like this
899
			for( var i in Test.AnotherWay._g_test_iframe) {
900
				if( typeof( Test.AnotherWay._g_test_iframe[i] )=='function' ) {
901
					if( i.substring( 0, 4 )=="test" ) {
902
						test_page.test_objects.push( new Test.AnotherWay._test_object_t( i ) );
903
					}
904
				}
905
			}
906
		}
907
	}else if( test_page.convention=="jsan" ) {
908
		// the test object is already filled with results
909
		test_page.test_objects.push( Test.AnotherWay._g_test_object_for_jsan );
910
	}
911

    
912
	if( test_page.test_objects.length==0 ) {
913
		Test.AnotherWay._print_result( test_page.url,  "No test functions defined in the page", "badtest", null );
914
		Test.AnotherWay._load_next_page();
915
		return;
916
	}
917

    
918
	test_page.wait_msg=Test.AnotherWay._print_result( test_page.url, "running tests..<span class=\"counter\">"+test_page.test_objects.length+"</span>", "running", null );
919

    
920
	test_page.test_object_i=0;
921
	Test.AnotherWay._run_more_tests();
922
}
923

    
924
Test.AnotherWay._handle_exception=function( o, e, title )
925
{
926
	var s=title+": "+typeof( e )+": ";
927
	if( e.message!=null ) {
928
		s+=e.message;
929
	}else if( e.description!=null ) {
930
		s+=e.description;
931
	}else {
932
		s+=e.toString();
933
	}
934
//	if( e.location!=null ) {  // XXX figure out how to display exception location if it's present (like in mozilla)
935
//		s+=" location: "+e.location.toString();
936
//	}
937
	o.exception=s;
938
	s=[];
939
	if( e.stack ) {
940
		var lines=e.stack.split( "\n" );
941
		for( var i=0; i<lines.length; ++i ) {
942
			// format of the line: func_name(args)@file_name:line_no
943
			if( lines[i].match( /(\w*)\(([^\)]*)\)@(.*):([^:]*)$/ ) ) {
944
				var func_name=RegExp.$1;
945
				if( func_name.length==0 ) {
946
					func_name="<anonymous>";
947
				}
948
				s.push( "in "+func_name+"( "+RegExp.$2+") at "+RegExp.$3+" line "+RegExp.$4+"\n" );
949
			}
950
		}
951
	}
952
	o.exception_stack=s;
953
}
954

    
955
Test.AnotherWay._run_more_tests=function()
956
{
957
	var test_page=Test.AnotherWay._g_tests_queue[0];
958
	while( test_page.test_object_i<test_page.test_objects.length ) {
959
		Test.AnotherWay._update_msg_counter( test_page.wait_msg, (1+test_page.test_object_i)+"/"+test_page.test_objects.length );
960
		var o=test_page.test_objects[test_page.test_object_i];
961
		if( test_page.convention=="anotherway" ) {
962
			try {
963
				Test.AnotherWay._g_test_iframe[o.name]( o );
964
			}catch( e ) {
965
				Test.AnotherWay._handle_exception( o, e, "" );
966
			}
967
		} // for "jsan" convention, test has run already
968
		if( o.delay_actions.length>0 || o.wait_result_milliseconds>0 ) {
969
			o.delay_total_milliseconds_left+=o.wait_result_milliseconds;
970
			Test.AnotherWay._delay_actions_timeout();
971
			return;
972
		}
973
		++test_page.test_object_i;
974
	}
975
	Test.AnotherWay._unprint_result( test_page.wait_msg );
976
	Test.AnotherWay._print_result( test_page.url, null, null, test_page.test_objects );
977
	Test.AnotherWay._load_next_page();
978
}
979

    
980
Test.AnotherWay._delay_actions_timeout=function()
981
{
982
	var test_page=Test.AnotherWay._g_tests_queue[0];
983
	var test_object=test_page.test_objects[test_page.test_object_i];
984
	var finished=true;
985
	if( test_object.delay_action_i==null ) {
986
		// set up to start first action
987
		test_object.delay_action_i=-1;
988
	}else {
989
		// perform current action
990
		var milliseconds_passed=(new Date()).getTime()-test_object.delay_prev_timer_time;
991
		test_object.delay_current_milliseconds_left-=milliseconds_passed;
992
		test_object.delay_total_milliseconds_left-=milliseconds_passed;
993
		finished=Test.AnotherWay._delay_continue_action( test_object, milliseconds_passed );
994
	}
995
	while( finished && test_object.delay_action_i<test_object.delay_actions.length ) {
996
		++test_object.delay_action_i; // start next action
997
		finished=Test.AnotherWay._delay_start_action( test_object );
998
	}
999
	if( test_object.delay_action_i<=test_object.delay_actions.length ) { // any more actions left ?
1000
		test_object.delay_prev_timer_time=(new Date()).getTime();
1001
		var next_timeout=Test.AnotherWay._g_timeout_granularity;
1002
		if( test_object.delay_current_milliseconds_left<next_timeout ) {
1003
			next_timeout=test_object.delay_current_milliseconds_left;
1004
		}
1005
		if( test_object.second_wait_msg!=null ) {
1006
			Test.AnotherWay._update_msg_counter( test_object.second_wait_msg, (test_object.delay_total_milliseconds_left/1000).toFixed() );
1007
		}
1008
		setTimeout( Test.AnotherWay._delay_actions_timeout, next_timeout );
1009
	}else { // no more actions left. run the next test.
1010
		if( test_object.second_wait_msg!=null ) {
1011
			Test.AnotherWay._unprint_result( test_object.second_wait_msg );
1012
			test_object.second_wait_msg=null;
1013
		}
1014
		++test_page.test_object_i;
1015
		Test.AnotherWay._run_more_tests();
1016
	}
1017
}
1018
Test.AnotherWay._delay_start_action=function( test_object )
1019
{
1020
	var finished=false;
1021
	var wait_msg="";
1022
	if( test_object.delay_action_i==test_object.delay_actions.length ) {
1023
		if( test_object.wait_result_milliseconds>0 ) {
1024
			test_object.delay_current_milliseconds_left=test_object.wait_result_milliseconds; // wait for result
1025
			wait_msg="waiting for results..";
1026
		}else {
1027
			++test_object.delay_action_i; // dont wait for result
1028
		}
1029
	}else {
1030
		var action=test_object.delay_actions[test_object.delay_action_i];
1031
		if( action.action_kind=="call" ) {
1032
			test_object.delay_current_milliseconds_left=action.call_delay_milliseconds;
1033
			wait_msg="performing delayed calls..";
1034
		}else if( action.action_kind=="window" ) {
1035
			if( Test.AnotherWay._g_opera_path_correction!=null && action.wnd_url.indexOf( ":" )==-1 ) {
1036
				action.wnd_url=Test.AnotherWay._g_opera_path_correction+action.wnd_url;
1037
			}
1038
			action.wnd_wnd=window.open( action.wnd_url, "_blank" );
1039
			if( action.wnd_wnd==null ) {
1040
				finished=true;
1041
				test_object.fail( "unable to open window for "+action.wnd_url );
1042
			}else {
1043
				test_object.delay_current_milliseconds_left=action.wnd_timeout_milliseconds;
1044
				wait_msg="opening window..";
1045
			}
1046
		}else if( action.action_kind=="replay" ) {
1047
			if( action.replay_events.length==0 ) {
1048
				finished=true;
1049
			}else {
1050
				action.replay_event_i=0;
1051
				test_object.delay_current_milliseconds_left=action.replay_events[0]["time"];
1052
				wait_msg="replaying events..";
1053
			}
1054
		}
1055
	}
1056
	if( test_object.second_wait_msg!=null ) {
1057
		Test.AnotherWay._unprint_result( test_object.second_wait_msg );
1058
	}
1059
	if( wait_msg!="" ) {
1060
		var test_page=Test.AnotherWay._g_tests_queue[0];
1061
		test_object.second_wait_msg=Test.AnotherWay._print_counter_result( test_page.url, wait_msg, test_object.delay_total_milliseconds_left, "waiting" );
1062
	}else {
1063
		test_object.second_wait_msg=null;
1064
	}
1065
	return finished;
1066
}
1067
Test.AnotherWay._delay_continue_action=function( test_object, milliseconds_passed )
1068
{
1069
	var finished=test_object.delay_current_milliseconds_left<=0;
1070
	if( test_object.delay_action_i==test_object.delay_actions.length ) { // action is "waiting for results"
1071
		if( test_object.n_plan!=null && test_object.n_plan==test_object.n_ok+test_object.n_fail ) {
1072
			finished=true; // if all assertions results are recorded, don't wait any more
1073
		}
1074
		if( finished ) {
1075
			++test_object.delay_action_i; // move on to the next test
1076
		}
1077
	}else {
1078
		var action=test_object.delay_actions[test_object.delay_action_i];
1079
		if( action.action_kind=="call" ) {
1080
			if( finished ) {
1081
				try {
1082
					action.call_fn();
1083
				}catch( e ) {
1084
					Test.AnotherWay._handle_exception( test_object, e, "in delay_call" );
1085
				}
1086
			}
1087
		}else if( action.action_kind=="window" ) {
1088
			test_object.delay_total_milliseconds_left+=milliseconds_passed; // for "window", the countdown is suspended since it's unknown how long it will take
1089
			if( Test.AnotherWay._is_url_loaded( action.wnd_url, action.wnd_wnd ) ) {
1090
				try {
1091
					action.wnd_fn( action.wnd_wnd );
1092
				}catch( e ) {
1093
					Test.AnotherWay._handle_exception( test_object, e, "in open_window function call" );
1094
				}
1095
				finished=true;
1096
			}else if( finished ) {
1097
				test_object.fail(  "unable to open window for url '"+action.wnd_url+"'. timeout expired" );
1098
			}
1099
		}else if( action.action_kind=="replay" ) {
1100
			if( finished ) {
1101
//				try {
1102
					Test.AnotherWay._delay_replay_event( test_object, action.replay_wnd, action.replay_events[action.replay_event_i], action.replay_checkpoints );
1103
//				}catch( e ) { // disabled, until I know how to gel location info from an exception
1104
//					Test.AnotherWay._handle_exception( test_object, e, "while replaying event" );
1105
//				}
1106
				++action.replay_event_i;
1107
				finished=action.replay_event_i==action.replay_events.length;
1108
				if( !finished ) {
1109
					test_object.delay_current_milliseconds_left=action.replay_events[action.replay_event_i]["time"];
1110
				}
1111
			}
1112
		}
1113
	}
1114
	return finished;
1115
}
1116
Test.AnotherWay._delay_replay_event=function( test_object, wnd, event, checkpoints )
1117
{
1118
	if( event.type=="_checkpoint" ) {
1119
		var checkpoint_n=event.which;
1120
		var prev_n_fail=test_object.n_fail;
1121
		checkpoints[checkpoint_n]( test_object, wnd );
1122
		var flash_color= prev_n_fail==test_object.n_fail ? "#2f2" : "#f22" ;
1123
		Test.AnotherWay._record_flash_border( flash_color );
1124
	}else if( event.type=="click" || event.type=="mouseover" || event.type=="mouseout" || event.type=="mousemove" || event.type=="mousedown" || event.type=="mouseup" ) {
1125
		var target=Test.AnotherWay._record_node_path_to_node( event["target"], wnd.document );
1126
		if( target!=null ) {
1127
			Test.AnotherWay._record_control_update_highlight( target, "ball", event );
1128
			var e=wnd.document.createEvent( "MouseEvents" );
1129
			var related_target=Test.AnotherWay._record_node_path_to_node( event["relatedTarget"], wnd.document );
1130
			e.initMouseEvent(
1131
				event["type"],
1132
				event["cancelable"],
1133
				event["bubbles"],
1134
				wnd.document.defaultView,
1135
				event["detail"],
1136
				event["screenX"],
1137
				event["screenY"],
1138
				event["clientX"],
1139
				event["clientY"],
1140
				event["ctrlKey"],
1141
				event["altKey"],
1142
				event["shiftKey"],
1143
				event["metaKey"],
1144
				event["button"],
1145
				Test.AnotherWay._record_node_path_to_node( event["relatedTarget"], wnd.document )
1146
			);
1147
			// Firefox 1.0.6 somehow loses relatedTarget somewhere on the way. Pass through our own, for those who choose to care.
1148
			e.passThroughRelatedTarget=related_target;
1149
			target.dispatchEvent( e );
1150
		}
1151
	}else if( event.type=="keyup" || event.type=="keydown" || event.type=="keypress" ) {
1152
		var e=wnd.document.createEvent( "KeyboardEvents" ); // forget it. Apparently it's not supported neither by mozilla nor by opera.
1153
		e.initKeyboardEvent(
1154
				event["type"],
1155
				event["cancelable"],
1156
				event["bubbles"],
1157
				wnd.document.defaultView,
1158
				event["which"],
1159
				event["which"],
1160
				event["ctrlKey"],
1161
				event["altKey"],
1162
				event["shiftKey"],
1163
				event["metaKey"],
1164
				false
1165
		);
1166
		wnd.document.dispatchEvent( e );
1167
	}
1168
}
1169

    
1170
Test.AnotherWay._print_counter_result=function( url, msg, milliseconds, style )
1171
{
1172
	return Test.AnotherWay._print_result( url, msg+"<span class=\"counter\">"+(milliseconds/1000).toFixed()+"</span>", style, null );
1173
}
1174

    
1175
Test.AnotherWay._g_result_count=0; // for assigning unique ids to result paragraphs
1176

    
1177
// number of pages tested
1178
Test.AnotherWay._g_ok_pages=0;
1179
Test.AnotherWay._g_fail_pages=0;
1180

    
1181
Test.AnotherWay._print_result=function( url, msg, style, test_objects )
1182
{
1183
	var results=document.getElementById( "results" );
1184
	var r=results.appendChild( document.createElement( "p" ) );
1185
	r.id="result"+Test.AnotherWay._g_result_count;
1186
	++Test.AnotherWay._g_result_count;
1187
	r.onclick=Test.AnotherWay._toggle_detail;
1188
	var text="<span class=\"bullet\">&nbsp;&nbsp;&nbsp;</span>&nbsp;";
1189
	if( url!="" ) {
1190
		text+=url+":  ";
1191
	}
1192
	if( msg!=null ) {
1193
		text+=msg;
1194
	}
1195
	if( test_objects!=null ) {
1196
		// compose summary and detail texts
1197
		var total_ok=0;
1198
		var total_detail_ok=0;
1199
		var total_fail=0;
1200
		var total_detail_fail=0;
1201
		var no_plan=0;
1202

    
1203
		var detail=results.appendChild( document.createElement( "div" ) );
1204

    
1205
		if( r.id.match( /^result(\d+)$/ ) ) {
1206
			detail.id="result_detail"+RegExp.$1;
1207
		}
1208

    
1209
		for( var i=0; i<test_objects.length; ++i ) {
1210
			var o=test_objects[i];
1211
			var p;
1212
			var p_text;
1213
			p=document.createElement( "P" );
1214
			Test.AnotherWay._set_css_class( p, "result_detail" );
1215
			p_text=o.name;
1216
			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)) {
1217
				++total_fail;
1218
				p_text+=" <span class=\"fail\">";
1219
				if( o.n_plan!=null && o.n_plan!=o.n_ok+o.n_fail) {
1220
					p_text+="planned "+o.n_plan+" assertions but got "+(o.n_ok+o.n_fail)+"; ";
1221
				}
1222
				if(o.n_plan==null && o.n_ok==0 && o.n_fail==0) {
1223
					p_text+="test did not output anything";
1224
				}else {
1225
					p_text+=" fail "+o.n_fail;
1226
				}
1227
				p_text+="</span>";
1228
			}else {
1229
				++total_ok;
1230
			}
1231
			p_text+=" ok "+o.n_ok;
1232
			if( o.n_plan==null ) {
1233
				no_plan=1;
1234
				p_text+=" <span class=\"warning\">no plan</span>";
1235
			}
1236
			p.innerHTML=p_text;
1237
			detail.appendChild( p );
1238
			if( o.exception ) {
1239
				p=document.createElement( "P" );
1240
				Test.AnotherWay._set_css_class( p, "result_exception_detail" );
1241
				p.innerHTML="<span class=\"fail\">exception:</span> "+o.exception;
1242
				detail.appendChild( p );
1243
				p=document.createElement( "P" );
1244
				Test.AnotherWay._set_css_class( p, "result_exception_stack_detail" );
1245
				p.innerHTML=o.exception_stack.join( "<br/>" );
1246
				detail.appendChild( p );
1247
			}
1248
			for( var ii=0; ii<o.assertions.length; ++ii ) {
1249
				var oo=o.assertions[ii];
1250
				var status=oo.ok ? "ok" : "<span class=\"fail\">fail</span>";
1251
				p=document.createElement( "P" );
1252
				Test.AnotherWay._set_css_class( p, "result_micro_detail" );
1253
				p.innerHTML=status;
1254
				p.appendChild( document.createTextNode( " "+oo.name ) );
1255
				detail.appendChild( p );
1256
			}
1257
			total_detail_ok+=o.n_ok;
1258
			total_detail_fail+=o.n_fail;
1259
		}
1260
		if( total_fail || total_detail_fail ) {
1261
			text+=" fail "+total_fail;
1262
		}
1263
		text+=" ok "+total_ok+" (detailed:";
1264
		if( total_fail || total_detail_fail ) {
1265
			text+=" fail "+total_detail_fail;
1266
		}
1267
		text+=" ok "+total_detail_ok+")";
1268
		if( no_plan ) {
1269
			text+=" <span class=\"warning\">no plan</span>";
1270
		}
1271
		style= total_fail==0 ? "ok" : "fail";
1272
		detail.style.display= style=="fail" ? "block" : "none";
1273
		detail.style.cursor="text";
1274
	}
1275
	if( style!=null ) {
1276
		Test.AnotherWay._set_css_class( r, style );
1277
		if( style=="ok" ) {
1278
			++Test.AnotherWay._g_ok_pages;
1279
		}else if( style=="fail" || style=="badtest" ) {
1280
			++Test.AnotherWay._g_fail_pages;
1281
		}
1282
		var pages_total="";
1283
		if( Test.AnotherWay._g_fail_pages>0 ) {
1284
			pages_total+=" fail "+Test.AnotherWay._g_fail_pages;
1285
		}
1286
		pages_total+=" ok "+Test.AnotherWay._g_ok_pages;
1287
		Test.AnotherWay._update_results_total( pages_total );
1288
	}
1289
	r.innerHTML=text;
1290
	if( results.scrollHeight!=null && results.scrollTop!=null && results.offsetHeight!=null ) {
1291
		results.scrollTop=results.scrollHeight-results.offsetHeight;
1292
	}
1293
	// when test_objects is not null, the results are final - good time to clean up
1294
	if( test_objects!=null ) {
1295
		for( var i=0; i<test_objects.length; ++i ) {
1296
			var actions=test_objects[i].delay_actions;
1297
			for( var action_i=0; action_i<actions.length; ++action_i ) {
1298
				var action=actions[action_i];
1299
				if( action.action_kind=="window" && action.wnd_wnd!=null && !action.wnd_no_close ) {
1300
					action.wnd_wnd.close();
1301
					action.wnd_wnd=null;
1302
				}
1303
			}
1304
		}
1305
	}
1306
	return r;
1307
}
1308
Test.AnotherWay._unprint_result=function( child )
1309
{
1310
	var results=document.getElementById( "results" );
1311
	results.removeChild( child );
1312
}
1313
Test.AnotherWay._toggle_detail=function()
1314
{
1315
	if( this.id.match( /^result(\d+)$/ ) ) {
1316
		var detail=document.getElementById( "result_detail"+RegExp.$1 );
1317
		if( detail!=null ) {
1318
			if( detail.style.display=="none" ) {
1319
				detail.style.display="block";
1320
			}else if( detail.style.display=="block" ) {
1321
				detail.style.display="none";
1322
			}
1323
		}
1324
	}
1325
}
1326
Test.AnotherWay._update_msg_counter=function( msg, text )
1327
{
1328
	for( var i=0; i<msg.childNodes.length; ++i ) {
1329
		var item=msg.childNodes[i];
1330
		if( item.nodeName=="SPAN" && Test.AnotherWay._get_css_class( item )=="counter" ) {
1331
			item.innerHTML=text;
1332
		}
1333
	}
1334
}
1335
Test.AnotherWay._update_results_total=function( msg )
1336
{
1337
	var total=document.getElementById( "total" );
1338
	if( total ) {
1339
		total.innerHTML=msg;
1340
	}
1341
}
1342
Test.AnotherWay._results_clear_onclick=function()
1343
{
1344
	var results=document.getElementById( "results" );
1345
	results.innerHTML="";
1346
	Test.AnotherWay._update_results_total( "" );
1347
	Test.AnotherWay._g_ok_pages=0;
1348
	Test.AnotherWay._g_fail_pages=0;
1349
	var debug=document.getElementById( "debug" );
1350
	debug.innerHTML="";
1351
}
1352

    
1353
Test.AnotherWay._get_css_class=function( o )
1354
{
1355
	var c=o.getAttribute( "className" );
1356
	if( c==null || c=="" ) {
1357
		c=o.getAttribute( "class" );
1358
	}
1359
	return c;
1360
}
1361
Test.AnotherWay._set_css_class=function( o, css_class )
1362
{
1363
	o.setAttribute( "className", css_class );
1364
	o.setAttribute( "class", css_class );
1365
}
1366

    
1367
Test.AnotherWay._tab_onclick=function()
1368
{
1369
	var tab=this;
1370
	var tabs=[ document.getElementById( "debug_tab" ), document.getElementById( "results_tab" ) ];
1371
	var panes=[ document.getElementById( "debug" ), document.getElementById( "results" ) ];
1372
	for( var i=0; i<tabs.length; ++i ) {
1373
		if( tab==tabs[i] ) {
1374
			Test.AnotherWay._set_css_class( tabs[i], "active_tab" );
1375
			panes[i].style.display="block";
1376
		}else {
1377
			Test.AnotherWay._set_css_class( tabs[i], "inactive_tab" );
1378
			panes[i].style.display="none";
1379
		}
1380
	}
1381
}
1382
Test.AnotherWay._tab_mouseover=function()
1383
{
1384
	if( Test.AnotherWay._get_css_class( this )=="inactive_tab" ) {
1385
		Test.AnotherWay._set_css_class( this, "inactive_mouseover_tab" );
1386
	}
1387
}
1388
Test.AnotherWay._tab_mouseout=function()
1389
{
1390
	if( Test.AnotherWay._get_css_class( this )=="inactive_mouseover_tab" ) {
1391
		Test.AnotherWay._set_css_class( this, "inactive_tab" );
1392
	}
1393
}
1394

    
1395
// recording mouse input
1396
Test.AnotherWay._record_check_onfocus=function()
1397
{
1398
	var o=this;
1399
	var check_select=o.type!="text";
1400
	var div=document.getElementById( "record_div" );
1401
	var inputs=div.getElementsByTagName( "input" );
1402
	for( var i=0; i<inputs.length; ++i ) {
1403
		var input=inputs[i];
1404
		if( input.type=="radio" ) {
1405
			if( input.value=="select" ) {
1406
				input.checked=check_select;
1407
			}else if( input.value=="input" ) {
1408
				input.checked=!check_select;
1409
			}
1410
		}
1411
	}
1412
}
1413

    
1414
Test.AnotherWay._g_no_record_msg=null; // not null - recording is unavailable
1415
Test.AnotherWay._g_record_timeout_cnt=0; // opening window for a page for recording
1416
Test.AnotherWay._g_record_url=null;
1417
Test.AnotherWay._g_record_wnd=null;
1418
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
1419
Test.AnotherWay._g_record_keydown=null; // recording control - which key is down
1420
Test.AnotherWay._g_record_ctrl_keydown=false;
1421
Test.AnotherWay._g_record_shift_keydown=false;
1422
Test.AnotherWay._g_record_control_visible=true; // recording control ui state
1423
Test.AnotherWay._g_record_started;
1424
Test.AnotherWay._g_record_paused;
1425
Test.AnotherWay._g_record_include_mousemove=false;
1426
Test.AnotherWay._g_record_start_time; // for time references
1427
Test.AnotherWay._g_record_pause_start_time;
1428
Test.AnotherWay._g_record_update_time_interval; // showing time in the control ui
1429
Test.AnotherWay._g_record_waiting_for_results=false; // waiting for results window to open
1430
Test.AnotherWay._g_record_events; // recorded events
1431
Test.AnotherWay._g_record_under_cursor; // track element under cursor
1432
Test.AnotherWay._g_record_checkpoint_count; // for checkpoint numbering
1433
Test.AnotherWay._g_record_mouse_over_record_control; // for avoiding record control highlight on mouseover
1434
Test.AnotherWay._g_record_highlighted_element={ element: null, x: null, y: null };
1435

    
1436
Test.AnotherWay._record_control_get_element=function( id )
1437
{
1438
	if( Test.AnotherWay._g_record_wnd!=null && Test.AnotherWay._g_record_wnd.document!=null ) {
1439
		return Test.AnotherWay._g_record_wnd.document.getElementById( id+Test.AnotherWay._g_record_random_id );
1440
	}else {
1441
		return null;
1442
	}
1443
}
1444
Test.AnotherWay._record_start_onclick=function() // "record" button on the run_tests.html: open a window for a page for which input is recorded
1445
{
1446
	if( Test.AnotherWay._g_no_record_msg!=null ) {
1447
		alert( Test.AnotherWay._g_no_record_msg );
1448
		return;
1449
	}
1450
	if( Test.AnotherWay._g_record_timeout_cnt>0
1451
	    || (Test.AnotherWay._g_record_wnd!=null && (Test.AnotherWay._g_record_wnd.closed!=null && !Test.AnotherWay._g_record_wnd.closed)) ) { // in opera, closed is null.
1452
		alert( "there is already window opened for recording input for a page "+Test.AnotherWay._g_record_url );
1453
		return;
1454
	}
1455
	var div=document.getElementById( "record_div" );
1456
	var inputs=div.getElementsByTagName( "input" );
1457
	var url=null;
1458
	for( var i=0; i<inputs.length; ++i ) {
1459
		var input=inputs[i];
1460
		if( input.type=="radio" ) {
1461
			if( input.value=="select" && input.checked ) {
1462
				var index=document.getElementById( "record_select" ).selectedIndex;
1463
				if( index>0 ) {
1464
					url=Test.AnotherWay._g_test_page_urls[index-1].url;
1465
				}
1466
			}else if( input.value=="input" && input.checked ) {
1467
				url=document.getElementById( "record_input" ).value;
1468
			}
1469
		}
1470
	}
1471
	if( url!=null ) {
1472
		Test.AnotherWay._g_record_url=url;
1473
		Test.AnotherWay._g_record_wnd=window.open( url, "_blank" );
1474
		if( Test.AnotherWay._g_record_wnd==null ) {
1475
			alert( "unable to open new window for a page: "+url );
1476
		}else {
1477
			Test.AnotherWay._g_record_timeout_cnt=50;
1478
			setTimeout( Test.AnotherWay._record_window_timeout, 100 );
1479
		}
1480
	}
1481
}
1482
Test.AnotherWay._record_window_timeout=function()
1483
{
1484
	if( Test.AnotherWay._is_url_loaded( Test.AnotherWay._g_record_url, Test.AnotherWay._g_record_wnd ) ) {
1485
		Test.AnotherWay._record_window_setup( Test.AnotherWay._g_record_wnd );
1486
	}else {
1487
		if( --Test.AnotherWay._g_record_timeout_cnt>0 ) {
1488
			setTimeout( Test.AnotherWay._record_window_timeout, 100 );
1489
		}else {
1490
			alert( "timeout expired while opening new window for a page: "+Test.AnotherWay._g_record_url );
1491
			Test.AnotherWay._g_record_wnd=null;
1492
			Test.AnotherWay._g_record_url=null;
1493
			Test.AnotherWay._g_record_timeout_cnt=0;
1494
		}
1495
	}
1496
}
1497
Test.AnotherWay._record_control_randomize_id=function( e, r )
1498
{
1499
	if( e.id!="" ) {
1500
		e.id=e.id+r;
1501
	}
1502
	for( var c=e.firstChild; c!=null; c=c.nextSibling ) {
1503
		Test.AnotherWay._record_control_randomize_id( c, r );
1504
	}
1505
}
1506
Test.AnotherWay._record_window_setup=function( wnd ) // insert recording control into the page for which input is recorded
1507
{
1508
	Test.AnotherWay._g_record_timeout_cnt=0;
1509
	var this_div=document.getElementById( "record_control" );
1510
	var record_control=wnd.document.importNode( this_div, true );
1511
	Test.AnotherWay._g_record_random_id=(1000*Math.random()).toFixed();
1512
	Test.AnotherWay._record_control_randomize_id( record_control, Test.AnotherWay._g_record_random_id );
1513
	Test.AnotherWay._g_record_control_visible=true;
1514
	Test.AnotherWay._g_record_started=false;
1515
	Test.AnotherWay._g_record_paused=false;
1516
	Test.AnotherWay._g_record_checkpoint_count=0;
1517
	Test.AnotherWay._g_record_mouse_over_record_control=false;
1518
	var doc=wnd.document;
1519
	doc.body.appendChild( record_control );
1520
	// opera sans-serif font is different
1521
	if( window.opera ) {
1522
		cursor_over_indicator=Test.AnotherWay._record_control_get_element( "record_cursor_over" );
1523
		cursor_over_indicator.style.width="18em";
1524
		cursor_over_indicator.style.height="2em";
1525
		cursor_over_indicator.style.fontSize="7pt";
1526
	}
1527
	doc.addEventListener( "keydown", Test.AnotherWay._record_control_keydown, true );
1528
	doc.addEventListener( "keyup", Test.AnotherWay._record_control_keyup, true );
1529
//	doc.addEventListener( "keypress", Test.AnotherWay._record_event, true ); // replaying is not supported by any known browser
1530

    
1531
	doc.body.addEventListener( "mousemove", Test.AnotherWay._record_on_mousemove, true );
1532
	doc.body.addEventListener( "click", Test.AnotherWay._record_event, true );
1533
	doc.body.addEventListener( "mouseover", Test.AnotherWay._record_event, true );
1534
	doc.body.addEventListener( "mouseout", Test.AnotherWay._record_event, true );
1535
	doc.body.addEventListener( "mousedown", Test.AnotherWay._record_event, true );
1536
	doc.body.addEventListener( "mouseup", Test.AnotherWay._record_event, true );
1537
}
1538
Test.AnotherWay._record_control_key_disabled=function( k )
1539
{
1540
	if( k=="c" ) {
1541
		return !Test.AnotherWay._g_record_started;
1542
	}else if( k=="p" ) {
1543
		return !Test.AnotherWay._g_record_started;
1544
	}else if( k=="s" ) {
1545
		return Test.AnotherWay._g_record_waiting_for_results;
1546
	}else {
1547
		return false;
1548
	}
1549
}
1550

    
1551
Test.AnotherWay._record_control_update_ui=function()
1552
{
1553
	var keydown_color="#fff";
1554
	var disabled_color="#aaa";
1555
	var button_color="#adf";
1556
	var active_color="#fdf";
1557

    
1558
	var display={};
1559
	display[false]="none";
1560
	display[true]="inline";
1561

    
1562
	var s_button=Test.AnotherWay._record_control_get_element( "record_s" );
1563
	var record_on=Test.AnotherWay._record_control_get_element( "record_on" );
1564
	var record_off=Test.AnotherWay._record_control_get_element( "record_off" );
1565

    
1566
	s_button.style.backgroundColor= Test.AnotherWay._record_control_key_disabled( "s" ) ? disabled_color
1567
		: Test.AnotherWay._g_record_keydown=="s" ? keydown_color : Test.AnotherWay._g_record_started ? active_color : button_color;
1568
	record_on.style.display=display[!Test.AnotherWay._g_record_started];
1569
	record_off.style.display=display[Test.AnotherWay._g_record_started];
1570

    
1571
	var h_button=Test.AnotherWay._record_control_get_element( "record_h" );
1572
	h_button.style.backgroundColor= Test.AnotherWay._g_record_keydown=="h" ? keydown_color : button_color;
1573

    
1574
	var p_button=Test.AnotherWay._record_control_get_element( "record_p" );
1575
	var record_pause_on=Test.AnotherWay._record_control_get_element( "record_pause_on" );
1576
	var record_pause_off=Test.AnotherWay._record_control_get_element( "record_pause_off" );
1577
	p_button.style.backgroundColor= Test.AnotherWay._record_control_key_disabled( "p" ) ? disabled_color
1578
		: Test.AnotherWay._g_record_keydown=="p" ? keydown_color : Test.AnotherWay._g_record_paused ? active_color : button_color;
1579
	record_pause_on.style.display=display[!Test.AnotherWay._g_record_paused];
1580
	record_pause_off.style.display=display[Test.AnotherWay._g_record_paused];
1581

    
1582
	var m_button=Test.AnotherWay._record_control_get_element( "record_m" );
1583
	var record_include_mousemove=Test.AnotherWay._record_control_get_element( "record_include_mousemove" );
1584
	var record_omit_mousemove=Test.AnotherWay._record_control_get_element( "record_omit_mousemove" );
1585
	m_button.style.backgroundColor= Test.AnotherWay._g_record_keydown=="m" ? keydown_color : Test.AnotherWay._g_record_include_mousemove ? active_color : button_color;
1586
	record_include_mousemove.style.display=display[!Test.AnotherWay._g_record_include_mousemove];
1587
	record_omit_mousemove.style.display=display[Test.AnotherWay._g_record_include_mousemove];
1588

    
1589
	var c_button=Test.AnotherWay._record_control_get_element( "record_c" );
1590
	c_button.style.backgroundColor= Test.AnotherWay._record_control_key_disabled( "c" ) ? disabled_color
1591
		: Test.AnotherWay._g_record_keydown=="c" ? keydown_color : button_color;
1592

    
1593
	var record_indicator=Test.AnotherWay._record_control_get_element( "record_indicator" );
1594
	record_indicator.style.display=display[Test.AnotherWay._g_record_started];
1595

    
1596
	var pause_indicator=Test.AnotherWay._record_control_get_element( "record_pause_indicator" );
1597
	pause_indicator.style.display=display[Test.AnotherWay._g_record_paused];
1598

    
1599
	var record_control=Test.AnotherWay._record_control_get_element( "record_control" );
1600
	record_control.style.display= Test.AnotherWay._g_record_control_visible ? "block" : "none";
1601

    
1602
	var shift_button=Test.AnotherWay._record_control_get_element( "record_shift_key" );
1603
	shift_button.style.backgroundColor= Test.AnotherWay._g_record_shift_keydown ? keydown_color : button_color;
1604

    
1605
	var ctrl_button=Test.AnotherWay._record_control_get_element( "record_ctrl_key" );
1606
	ctrl_button.style.backgroundColor= Test.AnotherWay._g_record_ctrl_keydown ? keydown_color : button_color;
1607
}
1608
Test.AnotherWay._record_format_time=function( t )
1609
{
1610
	t=new Date( t );
1611
	var m=t.getMinutes();
1612
	var s=t.getSeconds();
1613
	var str= m==0 ? "" : m+"m ";
1614
	str+=s+"s.";
1615
	return str;
1616
}
1617
Test.AnotherWay._record_control_update_time=function()
1618
{
1619
	var time_display=Test.AnotherWay._record_control_get_element( "record_time" );
1620
	if( time_display!=null ) {
1621
		time_display.innerHTML=Test.AnotherWay._record_format_time( (new Date()).getTime()-Test.AnotherWay._g_record_start_time );
1622
	}
1623
}
1624
Test.AnotherWay._record_control_update_highlight=function( elem, style, event )
1625
{
1626
	if( elem==null ) {
1627
		Test.AnotherWay._record_highlight_border( null );
1628
	}else {
1629
		var pos=Test.AnotherWay._get_page_coords( elem );
1630
		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 ) {
1631
			Test.AnotherWay._g_record_highlighted_element={ element: elem, x: pos.x, y: pos.y };
1632
			Test.AnotherWay._record_highlight_border( elem, style, event );
1633
		}
1634
	}
1635
}
1636
Test.AnotherWay._record_decode_key=function( event )
1637
{
1638
	var k=null;
1639
	if( event==null ) {
1640
		k=Test.AnotherWay._g_record_wnd.event.keyCode;
1641
	}else {
1642
		k=event.which;
1643
	}
1644
	if( k==83 ) {
1645
		return "s";
1646
	}else if( k==72 ) {
1647
		return "h";
1648
	}else if( k==73 ) {
1649
		return "i";
1650
	}else if( k==80 ) {
1651
		return "p";
1652
	}else if( k==67 ) {
1653
		return "c";
1654
	}else if( k==77 ) {
1655
		return "m";
1656
	}else if( k==16 ) {
1657
		return "shift";
1658
	}else if( k==17 ) {
1659
		return "ctrl";
1660
	}else if( k==18 ) {
1661
		return "alt";
1662
	}else if( k==19 ) {
1663
		return "pause";
1664
	}else if( k==123 ) {
1665
		return "f12";
1666
	}
1667
	return "";
1668
}
1669
Test.AnotherWay._record_control_keydown=function( event )
1670
{
1671
	var handled=false;
1672
	var k=Test.AnotherWay._record_decode_key( event );
1673
	if( k=="shift" ) {
1674
		Test.AnotherWay._g_record_shift_keydown=true;
1675
	}else if( k=="ctrl" ) {
1676
		Test.AnotherWay._g_record_ctrl_keydown=true;
1677
	}else if( k!="" && (Test.AnotherWay._g_record_keydown==null || Test.AnotherWay._g_record_keydown==k) ) {
1678
		if( Test.AnotherWay._g_record_ctrl_keydown && Test.AnotherWay._g_record_shift_keydown && !Test.AnotherWay._record_control_key_disabled( k ) ) {
1679
			Test.AnotherWay._g_record_keydown=k;
1680
			handled=true;
1681
		}
1682
	}else {
1683
		Test.AnotherWay._g_record_keydown="";
1684
	}
1685
	Test.AnotherWay._record_control_update_ui();
1686
	if( !handled ) {
1687
//		Test.AnotherWay._record_event( event ); // replaying is not supported in any known browser
1688
	}
1689
	return;
1690
}
1691
Test.AnotherWay._record_control_keyup=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=false;
1697
	}else if( k=="ctrl" ) {
1698
		Test.AnotherWay._g_record_ctrl_keydown=false;
1699
	}else if( k!="" && k==Test.AnotherWay._g_record_keydown && Test.AnotherWay._g_record_ctrl_keydown && Test.AnotherWay._g_record_shift_keydown  ) {
1700
		if( k=="s" ) {
1701
			Test.AnotherWay._g_record_started=!Test.AnotherWay._g_record_started;
1702
			if( Test.AnotherWay._g_record_started ) {
1703
				Test.AnotherWay._g_record_events=[];
1704
				Test.AnotherWay._g_record_start_time=(new Date()).getTime();
1705
				Test.AnotherWay._record_control_update_time();
1706
				Test.AnotherWay._g_record_update_time_interval=window.setInterval( Test.AnotherWay._record_control_update_time, 200 );
1707
			}else {
1708
				Test.AnotherWay._record_control_update_highlight( null );
1709
				if( !Test.AnotherWay._g_record_paused ) {
1710
					window.clearInterval( Test.AnotherWay._g_record_update_time_interval );
1711
				}
1712
				Test.AnotherWay._g_record_waiting_for_results=true;
1713
				// open a new window for self, pass a parameter to dump recorded events as javascript code there
1714
				// (the easiest way to obtain a document from the same origin, so it's writable, is to open this same page again)
1715
				Test.AnotherWay._g_record_paused=false;
1716
				var loc=window.location;
1717
				loc=loc.protocol+"//"+loc.host+loc.pathname+"?recording_results="+Test.AnotherWay._g_record_random_id;
1718
				if( window.open( loc, "_blank" )==null ) {
1719
					alert( "unable to open new window for results" );
1720
				}
1721
			}
1722
			handled=true;
1723
		}else if( k=="h" ) {
1724
			Test.AnotherWay._g_record_control_visible=!Test.AnotherWay._g_record_control_visible;
1725
			handled=true;
1726
		}else if( k=="p" ) {
1727
			Test.AnotherWay._g_record_paused=!Test.AnotherWay._g_record_paused;
1728
			if( Test.AnotherWay._g_record_paused ) {
1729
				Test.AnotherWay._g_record_pause_start_time=(new Date()).getTime();
1730
				if( Test.AnotherWay._g_record_started ) {
1731
					window.clearInterval( Test.AnotherWay._g_record_update_time_interval );
1732
				}
1733
				Test.AnotherWay._record_control_update_highlight( null );
1734
			}else {
1735
				var pause_duration=(new Date()).getTime()-Test.AnotherWay._g_record_pause_start_time;
1736
				Test.AnotherWay._g_record_start_time+=pause_duration;
1737
				Test.AnotherWay._g_record_update_time_interval=window.setInterval( Test.AnotherWay._record_control_update_time, 200 );
1738
			}
1739
			handled=true;
1740
		}else if( k=="m" ) {
1741
			Test.AnotherWay._g_record_include_mousemove=!Test.AnotherWay._g_record_include_mousemove;
1742
			handled=true;
1743
		}else if( k=="c" ) {
1744
			var o=Test.AnotherWay._record_checkpoint();
1745
			Test.AnotherWay._record_display_checkpoint( o );
1746
			Test.AnotherWay._record_flash_border( "#24d" );
1747
			handled=true;
1748
		}
1749
	}
1750
	Test.AnotherWay._g_record_keydown=null;
1751
	Test.AnotherWay._record_control_update_ui();
1752
	if( !handled ) {
1753
//		Test.AnotherWay._record_event( event ); // replaying is not supported in any known browser
1754
	}
1755
	return;
1756
}
1757
Test.AnotherWay._record_html_node_path=function( node )
1758
{
1759
	if( node==null ) {
1760
		return null;
1761
	}
1762
	var path=[];
1763
	while( true ) {
1764
		if( node.id!=null && node.id!="" ) {
1765
			path.unshift( "#"+node.id+" "+node.nodeName );
1766
			break;
1767
		}else {
1768
			var parent_node=node.parentNode;
1769
			if( parent_node==null ) {
1770
				return []; // no BODY up the path - this node is screwed (browsers differ in what's above the body), discard
1771
			}else {
1772
				var i=0;
1773
				var found=false;
1774
				for( var child=parent_node.firstChild; child!=null; child=child.nextSibling ) {
1775
					if( child==node ) {
1776
						found=true;
1777
						break;
1778
					}
1779
					if( child.nodeType==1 ) { // count only HTML element nodes
1780
						++i;
1781
					}
1782
				}
1783
				if( !found ) {
1784
					i=-1;
1785
				}
1786
				path.unshift( i+" "+node.nodeName );
1787
				if( parent_node.nodeName=="BODY" || parent_node.nodeName=="body" ) {
1788
					break;
1789
				}
1790
				node=parent_node;
1791
			}
1792
		}
1793
	}
1794
	return path;
1795
}
1796
Test.AnotherWay._record_node_path_to_string=function( path )
1797
{
1798
	var s="";
1799
	if( path!=null ) {
1800
		for( var i=0; i<path.length; ++i ) {
1801
			s+= i==0 ? "" : ", ";
1802
			var elem=path[i].split( " " );
1803
			if( elem[0].charAt( 0 )=="#" ) {
1804
				s+=elem[1]+" "+elem[0];
1805
			}else {
1806
				s+=elem[1]+" ["+elem[0]+"]";
1807
			}
1808
		}
1809
	}
1810
	return s;
1811
}
1812
Test.AnotherWay._record_node_path_to_node=function( path_str, doc )
1813
{
1814
	if( path_str==null ) {
1815
		return null;
1816
	}
1817
	var path=path_str.split( "," );
1818
	var node=doc.body;
1819
	for( var i=0; i<path.length; ++i ) {
1820
		var node_i=path[i].split( " " )[0];
1821
		if( node_i.charAt( 0 )=="#" ) {
1822
			node=doc.getElementById( node_i.substring( 1 ) );
1823
		}else {
1824
			if( node_i<0 || node_i>=node.childNodes.length ) {
1825
				node=null;
1826
			}else {
1827
				node=node.firstChild;
1828
				while( node!=null ) {
1829
					if( node.nodeType==1 ) {  // count only HTML element nodes
1830
						if( node_i==0 ) {
1831
							break;
1832
						}
1833
						--node_i;
1834
					}
1835
					node=node.nextSibling;
1836
				}
1837
			}
1838
		}
1839
		if( node==null ) {
1840
			return null;
1841
		}
1842
	}
1843
	return node;
1844
}
1845
Test.AnotherWay._record_control_contains_id=function( s )
1846
{
1847
	return s.match( /^#record_[\w_]+/ ) && s.match( Test.AnotherWay._g_record_random_id );
1848
}
1849
Test.AnotherWay._record_checkpoint=function()
1850
{
1851
	var o={ type: "_checkpoint", time: (new Date()).getTime()-Test.AnotherWay._g_record_start_time, which: Test.AnotherWay._g_record_checkpoint_count++,
1852
			target: Test.AnotherWay._record_html_node_path( Test.AnotherWay._g_record_under_cursor ) };
1853
	Test.AnotherWay._g_record_events.push( o );
1854
	return o;
1855
}
1856
Test.AnotherWay._record_event=function( event )
1857
{
1858
	var unneeded=["rangeOffset","eventPhase","timeStamp","isTrusted","popupWindowFeatures","rangeOffset"];
1859
	if( Test.AnotherWay._g_record_started && !Test.AnotherWay._g_record_paused ) {
1860
		var o={};
1861
		for( var n in event ) {
1862
			var needed=!n.match( /^[A-Z0-9_]+$/ );
1863
			if( needed ) {
1864
				for( var ui=0; ui<unneeded.length; ++ui ) {
1865
					if( unneeded[ui]==n ) {
1866
						needed=false;
1867
						break;
1868
					}
1869
				}
1870
				if( needed ) {
1871
					var value=event[n];
1872
					if( typeof( value )!="object" && typeof( value )!="function" ) {
1873
						o[n]=value;
1874
					}else if( n=="target" || n=="relatedTarget" ) {
1875
						o[n]=Test.AnotherWay._record_html_node_path( value );
1876
					}
1877
				}
1878
			}
1879
		}
1880
		o["time"]=(new Date()).getTime()-Test.AnotherWay._g_record_start_time;
1881
		var over_record_control= o["target"]!=null && o["target"][0]!=null && Test.AnotherWay._record_control_contains_id( o["target"][0] );
1882
		if( !over_record_control ) {
1883
			Test.AnotherWay._g_record_events.push( o );
1884
		}
1885
	}
1886
	return true;
1887
}
1888
Test.AnotherWay._record_on_mousemove=function( event )
1889
{
1890
	var path=Test.AnotherWay._record_html_node_path( event.target );
1891
	var new_mouse_over_record_control= path!=null && path[0]!=null && Test.AnotherWay._record_control_contains_id( path[0] );
1892
	if( new_mouse_over_record_control!=Test.AnotherWay._g_record_mouse_over_record_control ) {
1893
		Test.AnotherWay._g_record_mouse_over_record_control=new_mouse_over_record_control;
1894
		Test.AnotherWay._record_control_update_ui();
1895
	}
1896
	if( event.target!=null && event.target!=Test.AnotherWay._g_record_under_cursor ) {
1897
		Test.AnotherWay._g_record_under_cursor=event.target;
1898
		var s="";
1899
		if( path==null || path[0]==null || !Test.AnotherWay._record_control_contains_id( path[0] ) ) {
1900
			s=Test.AnotherWay._record_node_path_to_string( path );
1901
		}
1902
		if( s=="" ) {
1903
			s="&nbsp;";
1904
		}
1905
		var cursor_over_indicator=Test.AnotherWay._record_control_get_element( "record_cursor_over" );
1906
		cursor_over_indicator.innerHTML=s;
1907
	}
1908

    
1909
	var highlight_element=null;
1910
	if( !Test.AnotherWay._g_record_mouse_over_record_control && Test.AnotherWay._g_record_started && !Test.AnotherWay._g_record_paused ) {
1911
		highlight_element=event.target;
1912
	}
1913
	// highlight border disabled on recording - it causes page to scroll, issuing spurious mouseover/mouseout event
1914
	//Test.AnotherWay._record_control_update_highlight( highlight_element, "border" );
1915

    
1916
	if( Test.AnotherWay._g_record_include_mousemove ) {
1917
		Test.AnotherWay._record_event( event );
1918
	}
1919
	return true;
1920
}
1921
Test.AnotherWay._record_display_checkpoint=function( o )
1922
{
1923
	var checkpoints_div=Test.AnotherWay._record_control_get_element( "record_checkpoints" );
1924
	var p=checkpoints_div.appendChild( checkpoints_div.ownerDocument.createElement( "div" ) );
1925
	p.style.marginTop="3px";
1926
	p.style.font="normal normal 8pt sans-serif";
1927
	p.style.color="#000";
1928
	p.style.textAligh="left";
1929
	p.style.position="relative";
1930
	p.style.width="100%";
1931
	var checkpoint_text="";
1932
	checkpoint_text+="#"+(o.which+1);
1933
	checkpoint_text+="  "+Test.AnotherWay._record_format_time( o.time );
1934
	if( o.target!=null ) {
1935
		checkpoint_text+=Test.AnotherWay._record_node_path_to_string( o.target );
1936
	}
1937
	p.appendChild( p.ownerDocument.createTextNode( checkpoint_text ) );
1938
}
1939
Test.AnotherWay._record_save_results=function( doc )
1940
{
1941
	// strange, but DOM-style append does not work here in opera 8.
1942
	var append=function( s ) { doc.write( "<div>"+s+"</div>" ); };
1943
	append( "/* paste this data into your javascript and pass it as an argument to replay_events method */" );
1944
	append( "{ checkpoints: [" );
1945
	var first_checkpoint=true;
1946
	for( var i=0; i<Test.AnotherWay._g_record_events.length; ++i ) {
1947
		var o=Test.AnotherWay._g_record_events[i];
1948
		if( o.type=="_checkpoint" ) {
1949
			var str= first_checkpoint ? "" : "}, ";
1950
			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 );
1951
			append( str );
1952
			first_checkpoint=false;
1953
		}
1954
	}
1955
	if( !first_checkpoint ) {
1956
		append( "}" );
1957
	}
1958
	append( "], events: [ " );
1959
	var prev_time=0;
1960
	for( var i=0; i<Test.AnotherWay._g_record_events.length; ++i ) {
1961
		var o=Test.AnotherWay._g_record_events[i];
1962
		var s="";
1963
		s+= "{";
1964
		var n_first=true;
1965
		for( var n in o ) {
1966
			if( n=="time" ) { // convert to relative time
1967
				var cur_time=o[n]-0;
1968
				o[n]=cur_time-prev_time;
1969
				prev_time=cur_time;
1970
			}
1971
			s+=n_first ? n : ", "+n;
1972
			s+=":";
1973
			if( o[n]==null ) {
1974
				s+="null";
1975
			}else {
1976
				s+="\""+o[n]+"\"";
1977
			}
1978
			n_first=false;
1979
		}
1980
		s+= i==Test.AnotherWay._g_record_events.length-1 ? "}" : "},";
1981
		append( s );
1982
	}
1983
	append( "] }" );
1984
	append( ";" );
1985
}
1986

    
1987
Test.AnotherWay._g_record_border; // border highlighting element under cursor
1988
Test.AnotherWay._g_record_border_flashes=[]; // array of { color: color, timeout: milliseconds }
1989
Test.AnotherWay._g_record_border_flashing=false;
1990
Test.AnotherWay._g_record_border_normal_color="#d4b";
1991
Test.AnotherWay._record_flash_border_timeout=function()
1992
{
1993
	var color=Test.AnotherWay._g_record_border_normal_color;
1994
	var timeout=null;
1995
	if( Test.AnotherWay._g_record_border_flashes.length!=0 ) {
1996
		color=Test.AnotherWay._g_record_border_flashes[0].color;
1997
		timeout=Test.AnotherWay._g_record_border_flashes[0].timeout;
1998
		Test.AnotherWay._g_record_border_flashes.splice( 0, 1 );
1999
	}
2000
	if( Test.AnotherWay._g_record_border!=null ) {
2001
		for( var i=0; i<Test.AnotherWay._g_record_border.length; ++i ) {
2002
			Test.AnotherWay._g_record_border[i].style.backgroundColor=color;
2003
		}
2004
	}
2005
	if( timeout!=null ) {
2006
		setTimeout( Test.AnotherWay._record_flash_border_timeout, timeout );
2007
	}else {
2008
		Test.AnotherWay._g_record_border_flashing=false;
2009
	}
2010
}
2011
Test.AnotherWay._get_page_coords=function( elm )
2012
{
2013
	var point = { x: 0, y: 0 };
2014
	while( elm )  {
2015
		point.x+=elm.offsetLeft;
2016
		point.y+=elm.offsetTop;
2017
		elm=elm.offsetParent;
2018
	 }
2019
	return point;
2020
}
2021
Test.AnotherWay._set_page_coords=function( elm, x, y )
2022
{
2023
	var parent_coords={ x: 0, y: 0 };
2024
	if( elm.offsetParent )  {
2025
		parent_coords=Test.AnotherWay._get_page_coords( elm.offsetParent );
2026
	}
2027
	var new_x=x-parent_coords.x;
2028
	if( new_x<0 ) {
2029
		new_x=0;
2030
	}
2031
	elm.style.left=new_x+'px';
2032
	var new_y=y-parent_coords.y;
2033
	if( new_y<0 ) {
2034
		new_y=0;
2035
	}
2036
	elm.style.top=new_y+'px';
2037
}
2038
Test.AnotherWay._record_setup_highlight_positions=function( element, style, coords, positions )
2039
{
2040
	if( style=="border" ) {
2041
		var width=element.clientWidth;
2042
		var height=element.clientHeight;
2043
		var step=0;
2044
		var thickness=2;
2045
		var fudge_expand=4;
2046
		positions.push( { x: coords.x-step-thickness, y: coords.y-step-thickness, width: width+2*step+2*thickness+fudge_expand, height: thickness } );
2047
		positions.push( { x: coords.x+width+step+fudge_expand, y: coords.y-step-thickness, width: thickness, height: height+2*step+2*thickness+fudge_expand } );
2048
		positions.push( { x:positions[0].x, y:positions[0].y, width:positions[0].width, height:positions[0].height } );
2049
		positions.push( { x:positions[1].x, y:positions[1].y, width:positions[1].width, height:positions[1].height } );
2050
		positions[2].y+=height+thickness+2*step+fudge_expand;
2051
		positions[3].x-=width+thickness+2*step+fudge_expand;
2052
	}else if( style=="ball" ) {
2053
		positions.push( { x: coords.x+2, y: coords.y, width: 2, height: 6 } );
2054
		positions.push( { x: coords.x, y: coords.y+2, width: 6, height: 2 } );
2055
		positions.push( { x: coords.x+1, y: coords.y+1, width: 4, height: 4 } );
2056
	}
2057
}
2058
Test.AnotherWay._record_highlight_border=function( element, style, event ) // null - hide border
2059
{
2060
	if( element!=null ) {
2061
		if( Test.AnotherWay._g_record_border==null || Test.AnotherWay._g_record_border[0].ownerDocument!=element.ownerDocument ) {
2062
			Test.AnotherWay._g_record_border=[];
2063
			var n= style=="border" ? 4 : style=="ball" ? 3 : 0;
2064
			for( var i=0; i<4; ++i ) {
2065
				var b=element.ownerDocument.createElement( "div" );
2066
				b.style.position="absolute";
2067
				b.style.zIndex="1";
2068
				b.style.backgroundColor=Test.AnotherWay._g_record_border_normal_color;
2069
				element.ownerDocument.body.appendChild( b );
2070
				Test.AnotherWay._g_record_border.push( b );
2071
			}
2072
		}
2073
		var coords=null;
2074
		if( style=="border" ) {
2075
			coords=Test.AnotherWay._get_page_coords( element );
2076
		}else if( style=="ball" ) {
2077
			if( event!=null ) {
2078
				if( event.pageX!=null && event.pageY!=null ) {
2079
					coords={ x: event.pageX-0, y: event.pageY-0 };
2080
				}else if( event.clientX!=null && event.clientY!=null ) {
2081
					var doc=element.ownerDocument;
2082
					if( doc!=null ) {
2083
						coords={ x: (event.clientX-0)+doc.body.scrollLeft, y: (event.clientY-0)+doc.body.scrollTop };
2084
					}
2085
				}
2086
			}
2087
		}
2088
		if( coords!=null && element.clientWidth!=null && element.clientHeight!=null ) {
2089
			var positions=[];
2090
			Test.AnotherWay._record_setup_highlight_positions( element, style, coords, positions );
2091
			for( var i=0; i<positions.length; ++i ) {
2092
				var b=Test.AnotherWay._g_record_border[i];
2093
				var p=positions[i];
2094
				Test.AnotherWay._set_page_coords( b, p.x, p.y );
2095
				b.style.width=p.width+"px";
2096
				b.style.height=p.height+"px";
2097
				b.style.display="block";
2098
			}
2099
		}
2100
	}else {
2101
		if( Test.AnotherWay._g_record_border!=null ) {
2102
			for( var i=0; i<Test.AnotherWay._g_record_border.length; ++i ) {
2103
				Test.AnotherWay._g_record_border[i].style.display="none";
2104
			}
2105
		}
2106
	}
2107
}
2108
Test.AnotherWay._record_flash_border=function( color )
2109
{
2110
	if( Test.AnotherWay._g_record_border_flashing ) { //already
2111
		Test.AnotherWay._g_record_border_flashes.push( { color: Test.AnotherWay._g_record_border_normal_color, timeout:300 } );
2112
		Test.AnotherWay._g_record_border_flashes.push( { color: color, timeout:600 } );
2113
	}else {
2114
		Test.AnotherWay._g_record_border_flashing=true;
2115
		Test.AnotherWay._g_record_border_flashes.push( { color: color, timeout:600 } );
2116
		Test.AnotherWay._record_flash_border_timeout();
2117
	}
2118
}
2119
Test.AnotherWay._record_prepare_doc_for_results=function()
2120
{
2121
	document.open();
2122
	document.write( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">" );
2123
	document.write( "<html><head><title> Input recording results</title>" );
2124
	document.write( "<style type=\"text/css\">" );
2125
	document.write( "body { font: normal normal smaller sans-serif; }" );
2126
	document.write( "div { margin-top: 3px; }" );
2127
	document.write( "</style></head><body>" );
2128
	// opera and mozilla disagree over who the opener is.
2129
	if( typeof( window.opener.Test )!="undefined" && typeof( window.opener.Test.AnotherWay )!="undefined" ) {
2130
		window.opener.Test.AnotherWay._record_save_results( document );
2131
		window.opener.Test.AnotherWay._g_record_waiting_for_results=false;
2132
		window.opener.Test.AnotherWay._record_control_update_ui();
2133
	}else if( typeof( window.opener.opener.Test  )!="undefined" && typeof( window.opener.opener.Test.AnotherWay )!="undefined" ) {
2134
		window.opener.opener.Test.AnotherWay._record_save_results( document );
2135
		window.opener.opener.Test.AnotherWay._g_record_waiting_for_results=false;
2136
		window.opener.opener.Test.AnotherWay._record_control_update_ui();
2137
	}
2138
	document.write( "</body>" );
2139
	document.close();
2140
}
2141

    
2142
// global initialization
2143
onload=function()
2144
{
2145
	if( window.opera ) {
2146
		var good_opera=typeof( window.opera.version )=="function";
2147
		good_opera=good_opera && window.opera.version().match( /^\s*(\d+)/ );
2148
		good_opera=good_opera && RegExp.$1>=8;
2149
	}
2150
	var span=document.createElement( "SPAN" );
2151
	span.innerHTML="<!--[if IE]><br /><![endif]-"+"->";
2152
	var is_ie=span.getElementsByTagName( "BR" ).length>0;
2153

    
2154
	Test.AnotherWay._g_test_iframe=window.frames.test_iframe;
2155

    
2156
	var query_str=window.location.search;
2157
	if( query_str.charAt( 0 )=="?" ) {
2158
		query_str=query_str.substring( 1 );
2159
	}
2160
	var testlist_page="list-tests.html";
2161
	var auto_run=false;
2162
	if( query_str!="" ) {
2163
		var params=[query_str];
2164
		if( query_str.indexOf( ";" )!=-1 ) {
2165
			params=query_str.split( ";" );
2166
		}else if( query_str.indexOf( "&" )!=-1 ) {
2167
			params=query_str.split( "&" );
2168
		}
2169
		for( var param_i=0; param_i<params.length; ++param_i ) {
2170
			var param=params[param_i].split( "=" );
2171
			if( param[0]=="recording_results" ) {
2172
				if( window.opener!=null ) {
2173
					// we were told to show recording results - replace everything in the document with the results
2174
					Test.AnotherWay._record_prepare_doc_for_results();
2175
					return;
2176
				}
2177
			}else if( param[0]=="testpage" ) {
2178
				Test.AnotherWay._add_test_page_url( decodeURIComponent( param[1] ), "anotherway" );
2179
			}else if( param[0]=="jsantestpage" ) {
2180
				Test.AnotherWay._add_test_page_url( decodeURIComponent( param[1] ), "jsan" );
2181
			}else if( param[0]=="testlist" ) {
2182
				testlist_page=decodeURIComponent( param[1] );
2183
			}else if( param[0]=="testframe" ) {
2184
				if( window.opera && !good_opera ) {
2185
					Test.AnotherWay._show_error( "testframe parameter does not work in versions of Opera prior to 8.0. Sorry (pathches are welcome)." );
2186
					// Opera 7 barfs on attempt to access frame.frameElement.
2187
					// if someone knows a way to assign onload handler to that iframe in Opera 7
2188
					// without disrupting code that works in other browsers, patches are welcome.
2189
				}else {
2190
					var frame_path=param[1].split( "." );
2191
					var frame=top;
2192
					for( var frame_path_i=0; frame_path_i<frame_path.length; ++frame_path_i ) {
2193
						frame=frame[frame_path[frame_path_i]];
2194
					}
2195
					if( frame==null ) {
2196
						Test.AnotherWay._show_error( "unable to find frame specified for loading test pages: "+param[1] );
2197
					}else {
2198
						if( frame.frameElement!=null ) { // for the following assignement to onload to work, frameElement is required
2199
							frame=frame.frameElement;
2200
						}
2201
						Test.AnotherWay._g_test_iframe=frame;
2202
					}
2203
				}
2204
			}else if( param[0]=="testframe_no_clear" ) {
2205
				Test.AnotherWay._g_test_frame_no_clear=true;
2206
			}else if( param[0]=="run" ) {
2207
				auto_run=true;
2208
				if( param[1]=="all" ) {
2209
					Test.AnotherWay._g_pages_to_run="all";
2210
				}else {
2211
					if( Test.AnotherWay._g_pages_to_run==null || Test.AnotherWay._g_pages_to_run=="all" ) {
2212
						Test.AnotherWay._g_pages_to_run=[];
2213
					}
2214
					var pages=param[1].split( "," );
2215
					for( var i=0; i<pages.length; ++i ) {
2216
						Test.AnotherWay._g_pages_to_run.push( pages[i] );
2217
					}
2218
				}
2219
			}
2220
		}
2221
	}
2222
	if( Test.AnotherWay._g_test_page_urls.length==0 ) {  // if no individual pages were given on the command line, load the list
2223
		var result=Test.AnotherWay._set_iframe_location( window.frames["list_iframe"], testlist_page );
2224
		if( result.msg!=null ) {
2225
			Test.AnotherWay._show_error( result.msg );
2226
		}
2227
		Test.AnotherWay._g_run_on_list_load=auto_run;
2228
	}else {
2229
		Test.AnotherWay._g_run_on_main_load=auto_run;
2230
	}
2231

    
2232
	var f=Test.AnotherWay._g_test_iframe;
2233
	try {
2234
		if( f.attachEvent!=null ) {
2235
			f.attachEvent( "onload", Test.AnotherWay._test_page_onload );
2236
		}else {
2237
			f.onload=Test.AnotherWay._test_page_onload;
2238
		}
2239
		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.
2240
			Test.AnotherWay._g_test_iframe=Test.AnotherWay._g_test_iframe.contentWindow;
2241
		}
2242
	}catch(e) {
2243
		// ignore stupid opera error if the frame has onload handler assigned in the inline html
2244
	}
2245
	var handlers={
2246
		"run_all": { "onclick": Test.AnotherWay._run_all_onclick },
2247
		"run_selected": { "onclick": Test.AnotherWay._run_selected_onclick },
2248
		"unselect_all": { "onclick": Test.AnotherWay._unselect_all_onclick },
2249
		"record_select": { "onfocus": Test.AnotherWay._record_check_onfocus },
2250
		"record_input": { "onfocus": Test.AnotherWay._record_check_onfocus },
2251
		"record_start": { "onclick": Test.AnotherWay._record_start_onclick },
2252
		"clear_btn": { "onclick": Test.AnotherWay._results_clear_onclick },
2253
		"results_tab": { "onclick": Test.AnotherWay._tab_onclick, "onmouseover": Test.AnotherWay._tab_mouseover, "onmouseout": Test.AnotherWay._tab_mouseout },
2254
		"debug_tab": { "onclick": Test.AnotherWay._tab_onclick, "onmouseover": Test.AnotherWay._tab_mouseover, "onmouseout": Test.AnotherWay._tab_mouseout }
2255
	};
2256
	for( var hs in handlers ) {
2257
		var o=document.getElementById( hs );
2258
		if( o!=null ) {
2259
			for( var h in handlers[hs] ) {
2260
				o[h]=handlers[hs][h];
2261
			}
2262
		}else {
2263
			Test.AnotherWay._show_error( "unable to set "+h+" handler: id "+hs+" not found" );
2264
		}
2265
	}
2266

    
2267
	if( window.opera && !good_opera ) {
2268
		Test.AnotherWay._g_no_record_msg="Input events recording and replaying is not available in opera versions prior to 8.0.";
2269
	}
2270
	if( is_ie ) {
2271
		Test.AnotherWay._g_no_record_msg="Input events recording and replaying is not available in internet explorer.";
2272
	}
2273
 	if( Test.AnotherWay._g_no_record_msg!=null ) {
2274
		var no_record_p=document.getElementById( "record_not_supported" );
2275
		no_record_p.style.display="block";
2276
		no_record_p.appendChild( document.createTextNode( Test.AnotherWay._g_no_record_msg ) );
2277
	}
2278

    
2279
	Test.AnotherWay._g_main_loaded=true;
2280
	if( Test.AnotherWay._g_run_on_main_load ) {
2281
		Test.AnotherWay._g_run_on_main_load=false;
2282
		Test.AnotherWay._run_pages_to_run();
2283
	}
2284
}
2285
// -->
2286
</script></head><body>
2287

    
2288
<div id="col1">
2289
<div id="col1_header">Test pages:</div>
2290
<div id="scroller">
2291
<table id="testtable">
2292
</table>
2293
</div>
2294
<div id="run_buttons">
2295
<input type="button" value=" clear " id="clear_btn" />
2296
<input type="button" value=" run all " id="run_all" />
2297
<input type="button" value=" run selected " id="run_selected" />
2298
<input type="button" value=" unselect all " id="unselect_all" />
2299
</div>
2300
<input type="checkbox" id="dont_close_test_windows" /> do not close windows opened by tests
2301
<div id="error"></div>
2302
<div id="record_div">
2303
<p id="record_not_supported" style="display:none"></p>
2304
<p>Record mouse input for the page:</p>
2305
<p><input type="radio" name="record_choose" value="select" checked="checked" /> <select id="record_select"><option selected="selected">-- select a page: --</option></select></p>
2306
<p><input type="radio" name="record_choose" value="input" /> or enter page url: <input type="text" id="record_input" /></p>
2307
<p><input type="button" value=" record " id="record_start" /></p>
2308
</div>
2309
</div>
2310

    
2311
<div id="col2">
2312
<div id="right_header">
2313
<span id="results_count">Results: <span id="total"></span></span>
2314
<span id="results_tab" class="active_tab" style="visibility:hidden">Results</span>
2315
<span id="debug_tab" class="inactive_tab" style="visibility:hidden">Debug</span>
2316
</div>
2317
<div id="right_frame">
2318
<div id="results"></div>
2319
<div id="debug"></div>
2320
</div>
2321
</div>
2322

    
2323
<span style="display:none">
2324
<iframe name="list_iframe" onload="Test.AnotherWay._list_iframe_onload();"></iframe>
2325
<iframe name="test_iframe" onload="Test.AnotherWay._test_page_onload();"></iframe>
2326

    
2327
<!-- record_control div is to be imported into other documents, so all its styles are inline -->
2328
-<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">
2329

    
2330
<p style="margin:0 0 0 0; padding:0">
2331
&nbsp;
2332
<span style="display:none;font-weight:bold;color:#408" id="record_indicator">
2333
recording. <span style="font-weight:normal">time: <span id="record_time"></span></span><span id="record_pause_indicator"> paused</span>
2334
</span>
2335
</p>
2336

    
2337
<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>
2338
<p style="margin:2px 0 0 0; padding:0">
2339
cursor is over
2340
</p>
2341

    
2342
<p style="margin:8px 0 0 0; padding:0;">
2343
 keyboard control: press
2344
 <span id="record_ctrl_key" style="border:1px solid #226;background:#adf;padding:0 0.5em">ctrl</span> -
2345
 <span id="record_shift_key" style="border:1px solid #226;background:#adf;padding:0 0.5em">shift</span> -
2346
</p>
2347

    
2348
<p style="margin:4px 0 0 0; padding:0">
2349
<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>
2350
<span id="record_on">to <b>start</b> recording</span>
2351
<span id="record_off" style="display:none">to <b>stop</b> recording</span>
2352
</p>
2353

    
2354
<p style="margin:4px 0 0 0; padding:0">
2355
<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>
2356
<span>to <b>hide/show</b> this window</span>
2357
</p>
2358

    
2359
<p style="margin:4px 0 0 0; padding:0">
2360
<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>
2361
<span id="record_include_mousemove">to <b> record</b> mousemove</span>
2362
<span id="record_omit_mousemove" style="display:none">to <b>omit</b> mousemove</span>
2363
</p>
2364

    
2365
<p style="margin:4px 0 0 0; padding:0">
2366
<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>
2367
<span id="record_pause_on">to <b> pause</b> recording</span>
2368
<span id="record_pause_off" style="display:none">to <b>continue</b> recording</span>
2369
</p>
2370

    
2371
<p style="margin:4px 0 0 0; padding:0">
2372
<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>
2373
<span>to add checkpoint</span>
2374
</p>
2375

    
2376
<p style="margin:6px 0 0 0; padding:0">
2377
checkpoints:
2378
</p>
2379
<div id="record_checkpoints" style="position:relative;width:100%;height:6em;overflow:auto;font: normal normal 8pt sans-serif; color:#000; text-align: left">
2380
</div>
2381
</div>
2382

    
2383
</span>
2384
</body></html>
(5-5/35)