1
/****************************************************************************
2
**
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
** Contact: Qt Software Information (qt-info@nokia.com)
5
**
6
** This file is part of the SCXML module of the Qt Labs.
7
**
8
** GNU General Public License Usage
9
** Alternatively, this file may be used under the terms of the GNU
10
** General Public License version 3.0 as published by the Free Software
11
** Foundation and appearing in the file LICENSE.GPL included in the
12
** packaging of this file.  Please review the following information to
13
** ensure the GNU General Public License version 3.0 requirements will be
14
** met: http://www.gnu.org/copyleft/gpl.html.
15
**
16
** If you are unsure which license is appropriate for your use, please
17
** contact the sales department at qt-sales@nokia.com.
18
** $QT_END_LICENSE$
19
**
20
****************************************************************************/
21
function el_hasClass(ele,cls) {
22
	return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
23
}
24
function el_addClass(ele,cls) {
25
	if (!el_hasClass(ele,cls)) ele.className += " "+cls;
26
}
27
function el_removeClass(ele,cls) {
28
	if (el_hasClass(ele,cls)) {
29
		var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
30
		ele.className=ele.className.replace(reg,' ');
31
	}
32
}
33
var Set = Array;
34
Set.prototype.add = function Set_add(o)
35
{
36
	for (var i=0; i < this.length; ++i) {
37
			if (this[i] == o)
38
				return;
39
	}
40
	this.push(o);
41
};
42
	function removeFromSet (s,o)
43
	{
44
		var index = s.indexOf(o);
45
		var a = [];
46
		for (var i=0; i < s.length; ++i)
47
			if (s[i] != o)
48
				a.push(s[i]);
49
		return a;
50
	};
51
Array.prototype.clone = function() {
52
	var a = new Array();
53
	for (var i =0; i < this.length; ++i)
54
		a[i] = this[i];
55
	return a;
56
};
57
Object.prototype.clone = function() {
58
	var o = {};
59
	o.prototype = this.prototype;
60
	for (var i=0; i < this.length; ++i)
61
		o[i] = this[i];
62
	return o;
63
};
64
function Signal()
65
{
66
	this.prototype = new Array();
67
	this.connect = this.push;
68
	this.emit = function() {
69
		var a = arguments.clone();
70
		for (var i = 0; i < this.length; ++i) {
71
			this[i](a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9]);
72
		}
73
	};
74
	
75
};
76
77
Statechartz = 
78
{
79
		buildFromArgs: function(args,defaultFunc) {
80
			var obj = {};
81
			for (var i = 0; i < args.length; ++i) {
82
				var a = args[i];
83
				if (a != null) {
84
				if (typeof(a) == "string") {
85
					obj.id = a;
86
				}
87
				else 
88
					if (typeof(a) == "function") {
89
						obj[defaultFunc] = a;
90
					}
91
					else 
92
						if (typeof(a) == "object") {
93
							if (a.cls != undefined) {
94
								if (obj[a.cls] == undefined) 
95
									obj[a.cls] = [a.obj];
96
								else 
97
									obj[a.cls].push(a.obj);
98
							}
99
							else {
100
								for (var n in a) {
101
									obj[n] = a[n];
102
								}
103
							}
104
						}
105
          }
106
			}
107
			return obj;
108
		},
109
		buildState: function(type,args) {
110
			var obj = this.buildFromArgs(args);
111
			obj.type = type;
112
			obj.historyStates = [];
113
			obj.toString = function()
114
			{
115
				return ("state (id="+this.id+")");
116
			};
117
			if (obj.states != undefined) {
118
				for (var i=0; i < obj.states.length; ++i) {
119
					var s = obj.states[i];
120
					s.parent = obj;
121
					if (s.initial == true)
122
						obj.initialState = s;					
123
					if (s.type == "H") {
124
						obj.historyStates.push(s);
125
					}
126
				}
127
			} else 
128
				obj.states = [];
129
			if (obj.transitions != undefined) {
130
				for (var i=0; i < obj.transitions.length; ++i) {
131
					obj.transitions[i].source = obj;
132
          obj.transitions[i].regexp = 
133
            new RegExp("^"+obj.transitions[i].event+"($|(\\.[A-Za-z0-9_]+)+$)");
134
				}
135
			} else
136
				obj.transitions = [];
137
			obj.atomic =  (obj.type != "H" && obj.states.length == 0);				
138
			return {cls:"states",obj:obj};
139
		},
140
		fixStateIDs: function(state,stateByID,idx) {
141
			state.sort_index = idx++;
142
			stateByID[state.id] = state;
143
			if (state.states != undefined)
144
				for (var i = 0; i < state.states.length; ++i)
145
				{
146
					idx = this.fixStateIDs(state.states[i],stateByID,idx);
147
				}
148
			return idx;
149
		},
150
		fixTransitionTargets: function(state,stateByID) {
151
			if (state.transitions != undefined) {
152
				for (var i = 0; i < state.transitions.length; ++i)
153
				{
154
					var t = state.transitions[i];
155
					if (t.targets != undefined)
156
						for (var j=0; j < t.targets.length; ++j)
157
							t.targets[j] = stateByID[t.targets[j]];
158
					else
159
						t.targets = [];
160
				}
161
			}
162
			if (state.states != undefined) {
163
				for (var i = 0; i < state.states.length; ++i)
164
				{
165
					this.fixTransitionTargets(state.states[i],stateByID);
166
				}
167
			}
168
		},
169
		fixTransitions: function(state)
170
		{
171
			var stateByID = {};
172
			this.fixStateIDs(state,stateByID,0);
173
			this.fixTransitionTargets(state,stateByID);
174
			return state;
175
		},
176
		
177
		resolveFunction: function(f) {
178
			if (typeof(f) == "function")
179
				return f;
180
			else if (typeof(f) == "string")
181
				return function() { return eval(f); };
182
		},
183
		resolveEvent: function(e) {
184
			if (typeof (e) == "string") {
185
				return e;
186
			} else if (typeof(e) == "function"){
187
				var uid = "";
188
				if (e.connect != undefined ) {
189
					e.connect(function(){
190
						this.raise(uid);
191
					});
192
					return uid;
193
				}
194
			} else if (typeof(e) == "object") {
195
				var uid = "";
196
				e += function() { this.raise(); };
197
			}
198
		},
199
		Entry: function(f) {
200
			return {onentry: this.resolveFunction(f)};
201
		},
202
		Exit: function(f) {
203
			return {onexit: Statechartz.resolveFunction(f)};
204
		},
205
		Done: function(f) {
206
			return {ondone: Statechartz.resolveFunction(f)};
207
		},
208
		Trigger: function(f) {
209
			return {ontrigger: Statechartz.resolveFunction(f)};
210
		},
211
		Targets: function() {
212
			var a = new Array();
213
			for (var i =0; i < arguments.length; ++i)
214
				a[i] = arguments[i];
215
			return {targets: a};
216
		},
217
		Event: function(e) {
218
			return {event:this.resolveEvent(e)};
219
		},
220
		Condition: function(f) {
221
			return {condition: Statechartz.resolveFunction(f)};
222
		},
223
		Target: function(s) {return this.Targets(s);},
224
		Initial: {initial:true},
225
		Deep: {deep:true},
226
		Shallow: {deep:false},
227
		Final: function() {
228
			return Statechartz.buildState("F",arguments);
229
		},
230
		State: function() {
231
			return Statechartz.buildState("S",arguments);
232
		},
233
		Parallel: function() {
234
			return Statechartz.buildState("P",arguments);
235
		},
236
		History: function() {
237
			return Statechartz.buildState("H",arguments);
238
		},
239
		Attribute: function(element,attr,value) {
240
			return {cls:"attributes", obj:{type:'A',element:element,attr:attr,value:value}};
241
		},
242
		Css: function(element,attr,value) {
243
			return {cls:"attributes", obj:{type:'S',element:element,attr:attr,value:value}};
244
		},
245
		Transition: function() {
246
			var t = {cls: "transitions", obj:this.buildFromArgs(arguments,"ontrigger")};
247
			if (t.targets == undefined)
248
				t.targets = [];
249
			return t;
250
		},
251
		build: function(rootState) {
252
			
253
			return {
254
				rootState: Statechartz.fixTransitions(rootState.obj,{}),
255
				event: {name:"",data:{}},
256
                                historyValues: {},
257
				
258
				processing: false,
259
				doContinue: false,
260
				raise: function raise(event,external,payload)
261
				{
262
         if (this.externalQueue == undefined) {
263
            start();
264
          }
265
					if (!this.processing)
266
						external = true;
267
					(external?this.externalQueue:this.internalQueue).push(
268
							{name:event,data:payload}
269
						);
270
					if (!this.processing)
271
						this.process();
272
				},
273
				start: function()
274
				{
275
					this.doContinue = true;
276
					this.rootState.parent = undefined;
277
					
278
					this.configuration = new Set();
279
					this.externalQueue = [];
280
					this.internalQueue = [];
281
					this.processing = true;
282
					this.enterStates([{source:this.rootState,targets:[this.rootState.initialState]}]);
283
					this.process();
284
				},
285
				stop: function stop()
286
				{
287
					this.doContinue = false;
288
					this.configuration = new Set();
289
					this.externalQueue = this.internalQueue = [];
290
				},
291
				pause: function pause()
292
				{
293
					this.doContinue = false;
294
					this.running = false;
295
				},
296
				configuration: new Set(),
297
                                eventMatch: function eventMatch(trre,transitionEvent,actualEvent)
298
				{
299
					
300
					if (transitionEvent == undefined && actualEvent == undefined)
301
						return true;
302
					else if (transitionEvent != undefined && actualEvent != undefined) {						
303
304
                                                return (
305
                                                           transitionEvent == "*"
306
							|| transitionEvent == actualEvent 
307
                                                        || actualEvent.match(trre));
308
309
//                                                        actualEvent.indexOf(transitionEvent+'.')==0)
310
					} else
311
						return false;
312
				},
313
				startEventLoop: function startEventLoop() {
314
					var initialStepComplete = false;
315
					this.processing = true;
316
					while (true) {
317
						var enabledTransitions = this.selectTransitions();
318
						if (enabledTransitions.length == 0) {
319
							var internalEvent = this.internalQueue.shift();
320
							if (internalEvent != undefined ) {
321
								this.event = internalEvent;
322
								enabledTransitions = this.selectTransitions(internalEvent);
323
							}
324
						}
325
						if (enabledTransitions.length != 0) {
326
							microstep(this.enabledTransitions);
327
						} else
328
							break;							
329
					}
330
					this.process();
331
				},
332
				process: function process() {
333
					this.processing = true;
334
					while (this.externalQueue.length > 0) 
335
					{
336
						var externalEvent = this.externalQueue.shift();
337
						this.event = externalEvent;
338
						status = externalEvent.name;
339
						var enabledTransitions = this.selectTransitions(externalEvent);
340
						if (enabledTransitions.length) {
341
							this.microstep(enabledTransitions);
342
							var macrostepComplete = false;
343
							while (!macrostepComplete) {
344
								enabledTransitions = this.selectTransitions();
345
								if (enabledTransitions.length == 0) {
346
									var internalEvent = this.internalQueue.shift();
347
									if (internalEvent != undefined) {
348
										this.event = internalEvent;
349
										enabledTransitions = this.selectTransitions(internalEvent);
350
									}
351
								}
352
								if (enabledTransitions.length == 0) {
353
									macrostepComplete = true;
354
								} else {
355
									this.microstep(enabledTransitions);
356
								}
357
							}
358
							
359
						}
360
					}
361
					this.processing = false;
362
				},
363
				exitOrder: function(state_a,state_b)
364
				{
365
					return state_b.sort_index - state_a.sort_index;
366
				},
367
				entryOrder: function(state_a,state_b)
368
				{
369
					return state_a.sort_index - state_b.sort_index;
370
				},
371
				exitInterpreter: function() {
372
					   var inFinalState = false;
373
					   var statesToExit = this.configuration.sort(this.exitOrder);
374
					   for (var s=0; s < statesToExit.length; ++s) {
375
						   s.onexit();
376
					   }
377
				},
378
				selectTransitions: function selectTransitions(e) {
379
					var enabledTransitions = new Set();
380
					for (var i=0; i < this.configuration.length; ++i) {
381
						var state = this.configuration[i];
382
						if (state.atomic)
383
						{
384
							if (!this.isPreempted(state,enabledTransitions)) {
385
								var ancs = [state].concat(this.getProperAncestors(state));
386
								var breakLoop = false;
387
								for (var j =0; j < ancs.length && !breakLoop; ++j) {
388
									var tt = ancs[j].transitions;
389
									if (tt != undefined) {
390
										for (var ti =0; ti < tt.length; ++ti) {
391
											var t = tt[ti];
392
											if (t!=undefined)
393
                      if ((this.eventMatch(t.regexp,t.event,e==undefined?undefined:e.name)) && this.func(t.condition,e)) {
394
													enabledTransitions.add(t);
395
													breakLoop = true;
396
													break;
397
											}
398
										}
399
									}
400
								}
401
							}
402
						}
403
					}
404
					return enabledTransitions;
405
				},
406
				microstep: function microstep(enabledTransitions) {
407
					this.exitStates(enabledTransitions);
408
					for (var t=0; t < enabledTransitions.length; ++t)
409
						this.func(enabledTransitions[t].ontrigger,this.event);
410
					this.enterStates(enabledTransitions);
411
//					alert("config is now "+this.configuration);
412
				},
413
				exitStates: function exitStates(enabledTransitions) {
414
					var statesToExit = new Set();
415
					for (x=0; x < enabledTransitions.length; ++x) {
416
						var t = enabledTransitions[x];
417
						if (t.targets!= undefined && t.targets.length) {
418
							var LCA = this.findLCA([t.source].concat(t.targets));
419
							for (var i=0; i <this.configuration.length; ++i) {
420
								var s = this.configuration[i];
421
								if (this.isDescendant(s,LCA)) {
422
									statesToExit.add(s);
423
								}
424
							}
425
						}
426
					}
427
					statesToExit = statesToExit.sort(this.exitOrder);
428
					for (var i=0; i< statesToExit.length;++i) {
429
						var s = statesToExit[i];
430
						if (s.historyStates != undefined)
431
						for (var j=0;j< s.historyStates.length;++j) {
432
							var h = s.historyStates[j];
433
							var hconf = [];
434
							for (var k = 0; k < this.configuration.length; k++) {
435
								var conf = this.configuration[k];
436
								if ((h.deep && this.isDescendant(conf,s)) || (!h.deep && conf.parent == s)) {
437
									hconf.push(conf);
438
								}
439
							}
440
							this.historyValues[h.id] = hconf;
441
						}
442
					}
443
					
444
					for (var i =0; i< statesToExit.length;++i) {
445
						var s = statesToExit[i];
446
						this.func(s.onexit);
447
						this.configuration =  removeFromSet(this.configuration,s);
448
						if (s.id != undefined && s.id != "") {
449
							this.removeCssClass("state_"+s.id);
450
							/*
451
							var sel = document.getElementById("screen_"+s.id);
452
							if (sel != null)
453
								sel.style.visibility = "hidden";
454
						  */
455
						}
456
					}
457
				},
458
				enterStates: function enterStates(enabledTransitions) {
459
					var statesToEnter = new Set();
460
					var statesForDefaultEntry = new Set();
461
					for (var i =0; i < enabledTransitions.length; ++i) {
462
						var t = enabledTransitions[i];
463
						if (t.targets!= undefined && t.targets.length) {
464
							var LCA = this.findLCA([t.source].concat(t.targets));
465
							for (var j =0; j < t.targets.length; ++j) {
466
								this.addStatesToEnter(t.targets[j],LCA,statesToEnter,statesForDefaultEntry);
467
							}
468
						}
469
					}
470
					statesToEnter = statesToEnter.sort(this.entryOrder);
471
					for (var i =0; i < statesToEnter.length; ++i) {
472
						var s =statesToEnter[i];
473
						this.configuration.push(s);
474
						if (s.id != undefined && s.id != "") {
475
							this.addCssClass("state_"+s.id);
476
							var sel = document.getElementById("screen_"+s.id);
477
							if (sel != null)
478
								sel.style.visibility = "visible";
479
						}
480
						this.func(s.onentry,this.event);
481
						if (s.type == "F") {
482
							var parent = s.parent;
483
							var gparent = parent.parent;
484
							this.raise("done."+parent.id);
485
							if (gparent != undefined ){
486
								if (gparent.type == "P" && this.isInFinalState("P")) {
487
									this.raise("done."+gparent.oid);
488
								}
489
							}
490
							if (this.isInFinalState(this.rootState)) {
491
								this.doContinue = false;
492
								this.finished();
493
							}
494
						}
495
					}						      
496
				},
497
				addStatesToEnter: function addStatesToEnter(s,root,statesToEnter)
498
				{
499
          if (s == undefined)
500
                  return;
501
          if (s.type == 'H') {
502
					   var h =this.historyValues[s.id];
503
					   if (h != undefined) {
504
						   for (var i=0; i < h.length; ++i) {
505
							   this.addStatesToEnter(h[i],root,statesToEnter);
506
						   }
507
						 } else if (s.states.length) {
508
			        	 this.addStatesToEnter(s.initialState,s,statesToEnter);              
509
						 }
510
          } else {
511
            statesToEnter.add(s);
512
            if (s.type=='P') {
513
               for (var i=0; i <  s.states.length; ++i) {
514
                 this.addStatesToEnter(s.states[i],s,statesToEnter);
515
               }
516
            } else if (s.type =='S' && s.states.length) {
517
			        	 this.addStatesToEnter(s.initialState,s,statesToEnter);
518
            }
519
				   var pa = this.getProperAncestors(s,root);
520
				   if (root!=undefined && root.type=='P') {
521
            for (var i=0; i < root.states.length; ++i)
522
              pa.add(root.states[i]);
523
           }
524
				   for (var i=0; i < pa.length; ++i) {
525
					   var anc = pa[i];
526
					   statesToEnter.add(anc);
527
					   if (anc.type == "P") {
528
						   for (var j=0; j < anc.states.length; ++j) {
529
                 var pChild = anc.states[j];
530
                 var doAdd = true;
531
						     for (var k=0; k < statesToEnter.length; ++k) {
532
                  var s2 = statesToEnter[k];
533
                  if (this.isDescendant(s2,pChild)) {
534
                    doAdd = false;
535
                    break;
536
                  }
537
						     }
538
						     if (doAdd)
539
                  this.addStatesToEnter(pChild,anc,statesToEnter);
540
						   }
541
					   }
542
				   }
543
            
544
          }
545
				 },
546
				isInFinalState: function isInFinalState(state)
547
				{
548
					if (state.type == 'F')
549
						return true;
550
					else if (state.type == 'S') {
551
						for (var i=0; i < this.configuration.length; ++i) {
552
							var s = this.configuration[i];
553
							if (s.parent == state && s.type == 'F')
554
								return true;
555
						}
556
					} else if (state.type == 'P') {
557
						var all_done = true;
558
						for (var j=0; j<state.children.length; ++j) {
559
							if (state.children[j].type != 'F') {
560
								all_done = false;
561
								break;
562
							}
563
						}
564
						if (all_done) {
565
							return true;
566
						}						
567
					} else
568
						return false;
569
				},
570
				isDescendant: function isDescendant(child,parent) {
571
					for (var s = child.parent; s != parent; s = s.parent) {
572
						
573
						if (typeof(s) == "undefined")
574
							return false;
575
					}
576
					return typeof(s) != "undefined";
577
				},
578
				getProperAncestors: function getProperAncestors(state,root) {
579
					var ancs = [];
580
					var i = 0;
581
                                        if (state!=undefined) {
582
                                            for (var s = state.parent; s !=root && s !=undefined; s = s.parent) {
583
                                                    ancs[i++] = s;
584
                                            }
585
                                        }
586
					return ancs;
587
				},
588
				findLCA: function findLCA(states) {
589
					var ancs = this.getProperAncestors(states[0]);
590
					for (var i=0; i < ancs.length; ++i) {
591
						var anc = ancs[i];
592
						var all_are_descendants = true;
593
						for (var j =1; j < states.length; ++j) {
594
							var s = states[j];
595
							if (!this.isDescendant(s,anc)) {
596
								all_are_descendants = false;
597
								break;
598
							}
599
						}
600
						if (all_are_descendants)
601
							return anc;
602
						else
603
							return this.rootState;
604
					}
605
				},
606
				isPreempted: function isPreempted(state,transitionList) {
607
				   for (var i = 0; i<transitionList.length; ++i) {
608
					   t = transitionList[i];
609
					   if (t.targets.length > 0) {
610
						   if (this.isDescendant(state,this.findLCA([t.source].concat(t.targets)))) {
611
							   return true;
612
						   }
613
					   }
614
				   }
615
				   return false;
616
				},
617
				func: function func(f,e) {
618
					if (typeof(f) == "function")
619
						return f.call(this,e);
620
					else 
621
						return true;
622
				},
623
				addCssClass: function addCssClass(cls)
624
				{
625
					var ctx = [document.body];
626
					if (typeof(this.cssContext) != "undefined")
627
						ctx = document.querySelectorAll(this.cssContext);
628
					for (var i=0; i < ctx.length; ++i)
629
						el_addClass(ctx[i],cls);
630
				},
631
				removeCssClass: function removeCssClass(cls)
632
				{
633
					var ctx = [document.body];
634
					if (typeof(this.cssContext) != "undefined")
635
						ctx = document.querySelectorAll(this.cssContext);
636
          if (typeof(ctx) != 'undefined')
637
					for (var i=0; i < ctx.length; ++i)
638
						el_removeClass(ctx[i],cls);
639
				},
640
			};
641
		}, 
642
		loadScxml: function(doc) {
643
        var scxmlElement = doc.documentElement;
644
        function createFunctionFromExecutionContext(args) {
645
          if (args.length==0)
646
            return {};
647
          var f = "(function(_event){with(this){"+(args.join(';'))+";}})";
648
//          alert(f);
649
          return eval(f);
650
        }
651
        function resolveElement(el) {
652
          var args = [];
653
          for (var e=el.firstElementChild; e!=null; e=e.nextElementSibling) {
654
            args.push(resolveElement(e));
655
          }
656
657
          var tagName = el.localName.toLowerCase();
658
          if (tagName=='initial' || ((tagName=='state' || tagName=='parallel' || tagName=='history') && 
659
              el.parentNode.getAttribute("initial") == el.getAttribute('id')))
660
              args.push(Statechartz.Initial);
661
          if (tagName == "scxml") {
662
            for (var e=el.firstElementChild; e!=null; e=e.nextElementSibling) {
663
              if (e.localName.toLowerCase()=='script') {
664
                eval(e.textContent);
665
              }
666
            }
667
            var sc =Statechartz.build(Statechartz.buildState("S",args));
668
              sc._data = {};
669
              var datas = el.getElementsByTagName("data");
670
              for (var i=0; i < datas.length; ++i) {
671
                var data = datas[i];
672
                sc._data[data.getAttribute("id")] = eval(data.getAttribute("expr"));
673
              }
674
              return sc;
675
          } else if (tagName == "state" || tagName == "initial") {
676
            args.push(el.getAttribute("id"));
677
            return Statechartz.buildState("S",args);
678
          } else if (tagName == "parallel") {
679
            args.push(el.getAttribute("id"));
680
            return Statechartz.buildState("P",args);
681
          } else if (tagName == "final") {
682
            args.push(el.getAttribute("id"));
683
            return Statechartz.buildState("F",args);
684
          } else if (tagName == "history") {
685
            if (el.getAttribute("type") == "shallow")
686
              args.push(el.getAttribute("type") == "shallow"?Statechartz.Shallow:Statechartz.Deep);
687
            args.push(el.getAttribute("id"));
688
            return Statechartz.buildState("H",args);
689
          } else if (tagName == "onentry") {
690
              return Statechartz.Entry(createFunctionFromExecutionContext(args));
691
          } else if (tagName == "onexit") {
692
              return Statechartz.Exit(createFunctionFromExecutionContext(args));
693
694
          } else if (tagName == "transition") {
695
              var func = createFunctionFromExecutionContext(args);
696
              args = [];
697
              var cond = el.getAttribute("cond");
698
              var ev= el.getAttribute("event");
699
              var target = el.getAttribute("target");
700
              if (func != undefined)
701
                args.push(func);
702
              if (cond != null) {
703
                var cond_func = eval("(function(_event){with (this) { return "+cond+";}})");
704
                args.push({condition:cond_func});
705
              }
706
              if (ev != null) {
707
                args.push(Statechartz.Event(ev));
708
              }
709
              if (target != null) {
710
                args.push(Statechartz.Targets(target.split(' ')));
711
              }
712
              var t = {cls: "transitions", obj:Statechartz.buildFromArgs(args,"ontrigger")};
713
              if (t.targets == undefined)
714
                t.targets = [];
715
              return t;
716
          } else if (tagName == "if") {
717
            return "with(this) {if ("+el.getAttribute("cond")+") {"
718
            +args.join(';')
719
            +"}}";
720
          } else if (tagName == "elseif") {
721
            return "} else if ("+el.getAttribute("cond")+") {";
722
          } else if (tagName == "else") {
723
            return "} else {";
724
          } else if (tagName == "log") {
725
            return "";
726
          } else if (tagName == "raise") {
727
            return 'raise("'+el.getAttribute("event")+'",false,{'+args.join(',')+'})';
728
          } else if (tagName == "send") {
729
            var delay_attr = el.getAttribute("delay");
730
            if (delay_attr == null)
731
              delay_attr = "0";
732
            return 'setTimeout(function(){raise("'+el.getAttribute("event")+'",'+(el.getAttribute("target")!="_internal"?'true':'false')+',{'+args.join(',')+'}),'+
733
              delay_attr
734
            +'});'; 
735
          } else if (tagName == "assign") {
736
            var loc = el.getAttribute("location");
737
            if (loc==null)
738
              loc = "_data."+el.getAttribute("dataid");
739
            return loc+"="+el.getAttribute("expr");
740
          } else if (tagName == "script") {
741
            return el.textContent;
742
          } else if (tagName == "param") {
743
            return el.getAttribute("name")+":"+el.getAttribute("expr");
744
          }
745
        }
746
        return resolveElement(scxmlElement);
747
    },
748
    loadFromDocument: function() {
749
        var links = document.getElementsByTagName("link");
750
        for (var i=0; i < links.length;++i) {
751
          var link = links[i];
752
          var rel = link.getAttribute("rel");
753
          if (rel == "statechart") {
754
            var href = link.getAttribute("href");
755
            var xhttp=new XMLHttpRequest();
756
            xhttp.open("GET",href,false);
757
            xhttp.setRequestHeader("Content-Type","application/xml;charset=UTF8");            
758
            xhttp.send("");
759
            if (xhttp.readyState == 4) {
760
              var xmlDoc=xhttp.responseXML;
761
              if (xmlDoc == null) {
762
                var parser = new DOMParser();
763
                xmlDoc = parser.parseFromString(xhttp.responseText,"text/xml");
764
              }
765
              if (xmlDoc != null) {
766
                document.statechart = Statechartz.loadScxml(xmlDoc);
767
                document.statechart.start();
768
              }
769
            }
770
          }
771
        }
772
    }
773
		
774
		
775
};
776
777
window.onload = Statechartz.loadFromDocument;