middleman-wizard-template 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (25) hide show
  1. checksums.yaml +7 -0
  2. data/lib/middleman-wizard-template/template/source/index.html.erb +1 -89
  3. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/Matrix.js +449 -0
  4. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/PxLoader/PxLoader.js +395 -0
  5. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/PxLoader/PxLoaderImage.js +96 -0
  6. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/PxLoader/PxLoaderSwiffy.js +68 -0
  7. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/RouteRecognizer.js +506 -0
  8. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/Slides.js +846 -0
  9. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/Transform.js +312 -0
  10. data/lib/middleman-wizard-template/template/source/javascripts/_lib/{Tween.js → ww/Tween.js} +26 -11
  11. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/base.js +8 -0
  12. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/raf.js +131 -0
  13. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/statemachine.js +1024 -0
  14. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/useragent.js +1244 -0
  15. data/lib/middleman-wizard-template/template/source/javascripts/_lib/{util.js → ww/util.js} +48 -50
  16. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/viewport.js +89 -0
  17. data/lib/middleman-wizard-template/template/source/javascripts/{app.js → site.js} +5 -5
  18. data/lib/middleman-wizard-template/template/source/layouts/layout.erb +85 -0
  19. data/lib/middleman-wizard-template/template/source/stylesheets/default.css +2 -1
  20. data/lib/middleman-wizard-template/template/source/stylesheets/site.css.scss +11 -3
  21. data/lib/middleman-wizard-template/version.rb +1 -1
  22. metadata +23 -23
  23. data/lib/middleman-wizard-template/template/source/javascripts/_lib/Transform.js +0 -401
  24. data/lib/middleman-wizard-template/template/source/javascripts/_lib/raf.js +0 -26
  25. data/lib/middleman-wizard-template/template/source/javascripts/_lib/router.js +0 -679
@@ -0,0 +1,1024 @@
1
+ goog.provide('ww.Statechart');
2
+ goog.provide('ww.State');
3
+ goog.require('goog.array');
4
+
5
+ // ed9c899ccd0b42c4e9da3dbcb70dbbc7e4918f75
6
+
7
+ // // Helper function for creating prototypical objects...
8
+ // var creator = function(){
9
+ // function F() {}
10
+ // F.prototype = this;
11
+ // return new F();
12
+ // };
13
+
14
+ // helper function for merging in properties
15
+ var merge = function(obj, configs){
16
+ var k;
17
+ obj = obj || {};
18
+ configs = configs || [];
19
+ configs.forEach( function(x){
20
+ if (typeof x === 'object'){
21
+ for (k in x){
22
+ if(x.hasOwnProperty(k)) obj[k] = x[k];
23
+ }
24
+ }
25
+ });
26
+
27
+ return obj;
28
+ };
29
+
30
+ /**
31
+ * StateMachine namespace.
32
+ */
33
+ ww.Statechart = {
34
+ DEFAULT_TREE: 'default',
35
+ SUBSTATE_DELIM: 'SUBSTATE:',
36
+ version: '0.9.3'
37
+ };
38
+
39
+ if (goog.DEBUG) {
40
+ ww.Statechart.DebugMessagingObject = {
41
+
42
+ level: 0,
43
+
44
+ _buildOutput: function(type, state, details, tree){
45
+ tree = tree || ww.Statechart.DEFAULT_TREE;
46
+ var msg = "Global::["+tree+"] ";
47
+ msg = msg + "=> State::["+state+"]: ";
48
+ msg = msg + '{'+type+'} > '+details;
49
+ return msg;
50
+ },
51
+
52
+ sendLog: function(type, state, details, tree){
53
+ if (this.level > 0) return;
54
+ var msg = this._buildOutput(type, state, details, tree);
55
+ console.log(msg);
56
+ return msg;
57
+ },
58
+
59
+ sendInfo: function(type, state, details, tree){
60
+ if (this.level > 1) return;
61
+ var msg = this._buildOutput(type, state, details, tree);
62
+ console.info(msg);
63
+ return msg;
64
+ },
65
+
66
+ sendWarn: function(type, state, details, tree){
67
+ if (this.level > 2) return;
68
+ var msg = this._buildOutput(type, state, details, tree);
69
+ console.error(msg);
70
+ return msg;
71
+ },
72
+
73
+ sendError: function(type, state, details, tree){
74
+ if (this.level > 3) return;
75
+ var msg = this._buildOutput(type, state, details, tree);
76
+ console.error(msg);
77
+ return msg;
78
+ }
79
+ };
80
+ }
81
+
82
+ /**
83
+ * A State.
84
+ * @constructor
85
+ * @param {Object} configs Params.
86
+ */
87
+ ww.State = function State(config) {
88
+ this._data = {};
89
+ merge(this, [config]);
90
+ };
91
+
92
+ ww.State.prototype = {
93
+ // walk like a duck
94
+ isState: true,
95
+
96
+ _data: null,
97
+
98
+ _isNone: function(value) {
99
+ return (value === undefined || value === null);
100
+ },
101
+
102
+ goToState: function(name, data) {
103
+ var sc = this.statechart;
104
+ if (sc) {
105
+ sc.goToState(
106
+ name,
107
+ this.globalConcurrentState,
108
+ this.localConcurrentState,
109
+ data
110
+ );
111
+ } else { // weird format for UglifyJS preprocessing
112
+ if (goog.DEBUG) {
113
+ throw 'Cannot goToState cause state doesnt have a statechart';
114
+ }
115
+ }
116
+ },
117
+
118
+ goToHistoryState: function(name, isRecursive) {
119
+ var sc = this.statechart;
120
+ if (sc) {
121
+ sc.goToHistoryState(
122
+ name,
123
+ this.globalConcurrentState,
124
+ this.localConcurrentState,
125
+ isRecursive
126
+ );
127
+ } else { // weird format for UglifyJS preprocessing
128
+ if (goog.DEBUG) {
129
+ throw 'Cannot goToState cause state doesnt have a statechart';
130
+ }
131
+ }
132
+ },
133
+
134
+ sendEvent: function(evt) {
135
+ var sc = this.statechart;
136
+ if (sc) { sc.sendEvent.apply(sc, arguments); }
137
+ else { // weird format for UglifyJS preprocessing
138
+ if (goog.DEBUG) {
139
+ throw 'Cannot sendEvent cause state doesnt have a statechart';
140
+ }
141
+ }
142
+ },
143
+
144
+ sendAction: function(evt){
145
+ return this.sendEvent.apply(this, arguments);
146
+ },
147
+
148
+ getData: function(key) {
149
+ if (this._isNone(key)) return key;
150
+ var sc = this.statechart, ret = this._data[key];
151
+ if (this._isNone(ret)) {
152
+ ret = sc.getData(key, this.parentState, this.globalConcurrentState);
153
+ }
154
+ return ret;
155
+ },
156
+
157
+ setData: function(key, value) {
158
+ if (this._isNone(key)) return value;
159
+ this._data[key] = value;
160
+ },
161
+
162
+ removeData: function(key){
163
+ if (this._isNone(key)) return key;
164
+ var sc = this.statechart, ret = this._data[key];
165
+ if (this._isNone(ret)) {
166
+ sc.removeData(key, this.parentState, this.globalConcurrentState);
167
+ } else delete this._data[key];
168
+ },
169
+
170
+ setHistoryState: function(state) {
171
+ this.history = this.history || {};
172
+ if (this.substatesAreConcurrent) {
173
+ this.history[this.localConcurrentState] = state.name;
174
+ if (goog.DEBUG) {
175
+ ww.Statechart.DebugMessagingObject.sendLog('HISTORY STATE SET', this.name, ' substree = '+this.localConcurrentState+' => history state set to: '+state.name, this.globalConcurrentState);
176
+ }
177
+ }
178
+ else {
179
+ this.history = state.name;
180
+ if (goog.DEBUG) {
181
+ ww.Statechart.DebugMessagingObject.sendLog('HISTORY STATE SET', this.name, ' history state set to: '+state.name, this.globalConcurrentState);
182
+ }
183
+ }
184
+ }
185
+ };
186
+
187
+ /**
188
+ * A state chart.
189
+ * @constructor
190
+ * @param {Object} config Options.
191
+ */
192
+ ww.Statechart = function Statechart(config) {
193
+ // config all the internal information
194
+ this._all_states = {};
195
+ this._all_states[ww.Statechart.DEFAULT_TREE] = {};
196
+ this._states_with_concurrent_substates = {};
197
+ this._current_subtrees = {};
198
+ this._current_state = {};
199
+ this._current_state[ww.Statechart.DEFAULT_TREE] = null;
200
+ this._goToStateLocked = false;
201
+ this._sendEventLocked = false;
202
+ this._pendingStateTransitions = [];
203
+ this._pendingEvents = [];
204
+ this._active_subtrees = {};
205
+
206
+ if (goog.DEBUG) {
207
+ this.inState = function(name, tree) {
208
+ var ret = false, cStates = this.currentState(tree);
209
+ if (!cStates) {
210
+ throw [
211
+ "Doesn't appear that you are in any states,",
212
+ "perhaps you forgot to 'initStates'?"
213
+ ].join(' ');
214
+ }
215
+ goog.array.forEach(cStates, function(x) {
216
+ if (x.name === name) ret = true;
217
+ });
218
+ return ret;
219
+ };
220
+ this.getActiveStates = this.currentState;
221
+ }
222
+ };
223
+
224
+ ww.Statechart.prototype = {
225
+ isStatechart: true,
226
+
227
+ addState: function(name) {
228
+ var tree, obj, hasConcurrentSubstates, pState, states,
229
+ cTree, nState, config, configs = [], len, i, that = this;
230
+
231
+ for (i = 1, len = arguments.length; i < len; i++) {
232
+ configs[i - 1] = config = arguments[i];
233
+ }
234
+ config = len === 1 ? {} : merge(null, configs);
235
+ // primary config is always the last config
236
+ config.name = name;
237
+ config.statechart = this;
238
+ config.history = null;
239
+
240
+ tree = config.globalConcurrentState || ww.Statechart.DEFAULT_TREE;
241
+ config.globalConcurrentState = tree;
242
+
243
+ // Concurrent Substate checks:
244
+ // Do i have substates?
245
+ hasConcurrentSubstates = config.substatesAreConcurrent;
246
+ pState = config.parentState;
247
+ cTree = this._states_with_concurrent_substates[tree];
248
+ if (hasConcurrentSubstates) {
249
+ obj = this._states_with_concurrent_substates[tree] || {};
250
+ obj[name] = true;
251
+ this._states_with_concurrent_substates[tree] = obj;
252
+ }
253
+ // Am I a Concurrent State of any parent State?
254
+ if (pState && cTree && cTree[pState]) {
255
+ pState = this._all_states[tree][pState];
256
+ if (pState) {
257
+ pState.substates = pState.substates || [];
258
+ pState.substates.push(name);
259
+ }
260
+ }
261
+
262
+ nState = new ww.State(config);
263
+ nState.sendAction = nState.sendEvent;
264
+
265
+ // Actually add the state to our statechart
266
+ obj = this._all_states[tree] || {};
267
+ if (goog.DEBUG) {
268
+ if (obj[name]) {
269
+ throw [
270
+ 'Trying to add state',
271
+ name,
272
+ 'to state tree',
273
+ tree,
274
+ 'and it already exists'
275
+ ].join(' ');
276
+ }
277
+ }
278
+
279
+ obj[name] = nState;
280
+ this._all_states[tree] = obj;
281
+ nState._beenAdded = true;
282
+
283
+ // Code to get the substates and add them.
284
+ states = nState.states || [];
285
+ if (goog.DEBUG) {
286
+ // weird format for UglifyJS preprocessing
287
+ if (states.length === 1 && nState.substatesAreConcurrent) {
288
+ throw [
289
+ 'Trying to add substates in property \'states\' to ',
290
+ nState.name,
291
+ ', but must have more than ONE substate'
292
+ ].join(' ');
293
+ }
294
+ }
295
+
296
+ goog.array.forEach(states, function(x, idx) {
297
+ var args = [], good = false, last;
298
+ if (typeof x === 'object' && x.length > 0) {
299
+ if (goog.DEBUG) {
300
+ if (typeof x[0] !== 'string') {
301
+ var msg = '#addState: invalid substate array...Must have the name ';
302
+ msg += 'at index=0';
303
+ throw msg;
304
+ }
305
+ }
306
+ args = args.concat(x);
307
+ good = true;
308
+ }
309
+ else if (typeof x === 'string') {
310
+ args.push(x);
311
+ good = true;
312
+ }
313
+ else if (typeof x === 'object') {
314
+ if (typeof x.name !== 'string') {
315
+ if (goog.DEBUG) {
316
+ var msg2 = '#addState: invalid substate hash...Must have a ';
317
+ msg2 += '\'name\' property';
318
+ throw msg2;
319
+ }
320
+ }
321
+ args.push(x.name);
322
+ args.push(x);
323
+ good = true;
324
+ }
325
+ if (good) {
326
+ // add missing config parts to the last element.
327
+ last = args.length - 1;
328
+ args[last].parentState = name;
329
+ args[last].globalConcurrentState = tree;
330
+ that.addState.apply(that, args);
331
+ } else {
332
+ if (goog.DEBUG) throw '#addState: invalid substate at index=' + idx;
333
+ }
334
+ });
335
+
336
+ return this;
337
+ },
338
+
339
+ initStates: function(init) {
340
+ var x, state;
341
+ this._inInitialSetup = true;
342
+ if (typeof init === 'string') {
343
+ this.goToState(init, ww.Statechart.DEFAULT_TREE);
344
+ }
345
+ else if (typeof init === 'object') {
346
+ for (x in init) {
347
+ if (init.hasOwnProperty(x)) {
348
+ state = init[x];
349
+ this.goToState(state, x);
350
+ }
351
+ }
352
+ }
353
+ this._inInitialSetup = false;
354
+ this._flushPendingEvents();
355
+
356
+ return this;
357
+ },
358
+
359
+ goToState: function(requestedStateName, tree, concurrentTree, data) {
360
+ var cState, allStates = this._all_states[tree], idx, len,
361
+ enterStates = [], exitStates = [], haveExited,
362
+ enterMatchIndex, exitMatchIndex, that,
363
+ reqState, pState, i, substateTree,
364
+ enterStateHandled, exitStateHandled, substates;
365
+
366
+ if (goog.DEBUG) {
367
+ if (!tree) throw '#goToState: invalid global parallel state';
368
+ }
369
+
370
+ // First, find the current tree off of the concurrentTree, then the
371
+ // main tree
372
+ if (concurrentTree) {
373
+ cState = this._current_state[concurrentTree];
374
+ } else {
375
+ cState = this._current_state[tree];
376
+ }
377
+
378
+ reqState = allStates[requestedStateName];
379
+
380
+ if (goog.DEBUG) {
381
+ if (!reqState) {
382
+ var msg = '#goToState: Could not find requested state: ';
383
+ msg += requestedStateName;
384
+ throw msg;
385
+ }
386
+ }
387
+
388
+ // if the current state is the same as the requested state do nothing
389
+ if (this._checkAllCurrentStates(reqState, concurrentTree || tree)) return;
390
+
391
+ if (typeof data !== 'undefined' && data !== null) {
392
+ ww.Statechart.DebugMessagingObject.sendLog('SETTING DATA FOR TRANSITION FOR => '+requestedStateName);
393
+ if (typeof data === 'string') reqState.setData(data, data);
394
+ if (typeof data === 'object') {
395
+ for (var key in data) {
396
+ if (data.hasOwnProperty(key)) reqState.setData(key, data[key]);
397
+ }
398
+ }
399
+ }
400
+
401
+ if (this._goToStateLocked) {
402
+ // There is a state transition currently happening. Add this requested
403
+ // state transition to the queue of pending state transitions. The req
404
+ // will be invoked after the current state transition is finished
405
+ this._pendingStateTransitions.push({
406
+ requestedState: requestedStateName,
407
+ tree: tree
408
+ });
409
+
410
+ return;
411
+ }
412
+
413
+ // Lock for the current state transition, so that it all gets sorted out
414
+ // in the right order
415
+ this._goToStateLocked = true;
416
+
417
+ // Get the parent states for the current state and the registered state.
418
+ // we will use them to find the commen parent state
419
+ enterStates = this._parentStatesWithRoot(reqState);
420
+ exitStates = cState ? this._parentStatesWithRoot(cState) : [];
421
+
422
+ // continue by finding the common parent state for the current and
423
+ // requested states:
424
+ //
425
+ // At most, this takes O(m^2) time, where m is the maximum depth from the
426
+ // root of the tree to either the requested state or the current state.
427
+ // Will always be less than or equal to O(n^2), where n is the number
428
+ // of states in the tree
429
+ enterMatchIndex = -1;
430
+ for (idx = 0, len = exitStates.length; idx < len; idx++) {
431
+ exitMatchIndex = idx;
432
+ enterMatchIndex = goog.array.indexOf(enterStates, exitStates[idx]);
433
+ if (enterMatchIndex >= 0) break;
434
+ }
435
+
436
+ // In the case where we don't find a common parent state, we
437
+ // must enter from the root state
438
+ if (enterMatchIndex < 0) enterMatchIndex = enterStates.length - 1;
439
+
440
+ // Setup for the enter state sequence
441
+ this._enterStates = enterStates;
442
+ this._enterStateMatchIndex = enterMatchIndex;
443
+ this._enterStateConcurrentTree = concurrentTree;
444
+ this._enterStateTree = tree;
445
+
446
+ // Now, we will exit all the underlying states till we reach the common
447
+ // parent state. We do not exit the parent state because we transition
448
+ // within it.
449
+ this._exitStateStack = [];
450
+ if (cState && cState.substatesAreConcurrent) {
451
+ this._fullExitFromSubstates(tree, cState);
452
+ }
453
+ for (i = 0; i < exitMatchIndex; i += 1) {
454
+ cState = exitStates[i];
455
+ this._exitStateStack.push(cState);
456
+ }
457
+
458
+ // Now, that we have the full stack of states to exit
459
+ // We can exit them in an orderly fashion.
460
+ this._unwindExitStateStack();
461
+ },
462
+
463
+ goToHistoryState: function goToHistoryState(requestedState,
464
+ tree,
465
+ concurrentTree,
466
+ isRecursive) {
467
+ var allStateForTree = this._all_states[tree],
468
+ pState, realHistoryState;
469
+
470
+ if (goog.DEBUG) {
471
+ if (!tree || !allStateForTree) {
472
+ var msg = '#goToHistoryState: State requesting does not have a';
473
+ msg += 'valid global parallel tree';
474
+ throw msg;
475
+ }
476
+ }
477
+
478
+ pState = allStateForTree[requestedState];
479
+ if (pState) realHistoryState = pState.history || pState.initialSubstate;
480
+
481
+ if (!realHistoryState) {
482
+ realHistoryState = requestedState;
483
+ }
484
+ else if (isRecursive) {
485
+ this.goToHistoryState(realHistoryState, tree, isRecursive);
486
+ return;
487
+ }
488
+ this.goToState(realHistoryState, tree);
489
+ },
490
+
491
+ currentState: function(tree) {
492
+ var ret, tmp, sTree, aTrees, bTree, cStates = this._current_state,
493
+ cState, i, len, state, ps, aStates;
494
+ tree = tree || 'default';
495
+ cState = cStates[tree];
496
+ aStates = this._all_states[tree];
497
+
498
+ // now add all the parents of the current state...
499
+ if (cState && cState.isState) {
500
+ ret = this._parentStates(cState);
501
+ }
502
+
503
+ // Now see if it has substates...
504
+ if (cState && cState.substatesAreConcurrent) {
505
+ aTrees = this._active_subtrees[tree] || [];
506
+ for (i = 0, len = aTrees.length; i < len; i++) {
507
+ sTree = aTrees[i];
508
+ state = cStates[sTree];
509
+ if (state) ps = aStates[state.parentState];
510
+ if (ps && goog.array.indexOf(ret, ps) < 0) ret.unshift(ps);
511
+ if (state && goog.array.indexOf(ret, state) < 0) ret.unshift(state);
512
+ }
513
+ }
514
+ return ret;
515
+ },
516
+
517
+ sendEvent: function(evt) {
518
+ var args = [], len = arguments.length, i;
519
+
520
+ if (len < 1) return;
521
+ for (i = 1; i < len; i++) {
522
+ args[i - 1] = arguments[i];
523
+ }
524
+
525
+ try {
526
+ if (this._inInitialSetup || this._sendEventLocked ||
527
+ this._goToStateLocked) {
528
+ // We want to prevent any events from occurring until
529
+ // we have completed the state transitions and events
530
+ this._pendingEvents.push({
531
+ evt: evt,
532
+ args: args
533
+ });
534
+
535
+ return;
536
+ }
537
+
538
+ this._sendEventLocked = true;
539
+
540
+ // function that processes the event, diff for testing v. production
541
+ this._processEvent(evt, args);
542
+ } catch(err) {
543
+ this._restartEvents();
544
+ throw err;
545
+ }
546
+
547
+ this._restartEvents();
548
+ },
549
+
550
+ _processEvent: function(evt, args){
551
+ this._structureCrawl('_cascadeEvents', evt, args);
552
+ },
553
+
554
+ getData: function(key, stateName, tree) {
555
+ var allStates = this._all_states[tree], state;
556
+ if (!allStates) return null;
557
+ state = allStates[stateName];
558
+ if (state && state.isState) return state.getData(key);
559
+ },
560
+
561
+ removeData: function(key, statename, tree){
562
+ var allStates = this._all_states[tree], state;
563
+ if (!allStates) return null;
564
+ state = allStates[statename];
565
+ if (state && state.isState) return state.removeData(key);
566
+ },
567
+
568
+ getState: function(name, tree) {
569
+ var allStates, ret;
570
+ tree = tree || ww.Statechart.DEFAULT_TREE;
571
+ allStates = this._all_states[tree];
572
+ if (!allStates) return null;
573
+ ret = allStates[name];
574
+ return ret;
575
+ },
576
+
577
+ _restartEvents: function(){
578
+ // Now, that the states have a chance to process the first action
579
+ // we can go ahead and flush the queued events
580
+ this._sendEventLocked = false;
581
+ if (!this._inInitialSetup) this._flushPendingEvents();
582
+ },
583
+
584
+ _structureCrawl: function(func, evt, args) {
585
+ var tree, currentStates = this._current_state, i, len, sResponder, tmp,
586
+ allStates, responder, aTrees, sTree, handled, found,
587
+ ss = ww.Statechart.SUBSTATE_DELIM;
588
+ for (tree in currentStates) {
589
+ if (!currentStates.hasOwnProperty(tree)) continue;
590
+
591
+ handled = false;
592
+ sTree = null;
593
+ responder = currentStates[tree];
594
+ if (!responder || tree.slice(0, ss.length) === ss) continue;
595
+ // if we don't have an all state tree then we know that this is a
596
+ // substate tree
597
+ allStates = this._all_states[tree];
598
+ if (!allStates) continue;
599
+ aTrees = this._active_subtrees[tree] || [];
600
+ for (i = 0, len = aTrees.length; i < len; i++) {
601
+ sTree = aTrees[i];
602
+ sResponder = currentStates[sTree];
603
+
604
+ if (handled) {
605
+ tmp = [true, true];
606
+ } else {
607
+ tmp = this[func](evt, args, sResponder, allStates, sTree);
608
+ }
609
+
610
+ handled = tmp[0];
611
+ if (goog.DEBUG) found = tmp[1];
612
+ }
613
+ if (!handled) {
614
+ tmp = this[func](evt, args, responder, allStates, null);
615
+ handled = tmp[0];
616
+ if (goog.DEBUG) {
617
+ if (!found) found = tmp[1];
618
+ }
619
+ }
620
+ if (goog.DEBUG) {
621
+ if (!found) {
622
+ ww.Statechart.DebugMessagingObject.sendLog('EVENT', this.name, 'Fired {'+evt+'} with '+(args.length || 0)+' argument(s) found NO state to handle this', this.globalConcurrentState);
623
+ }
624
+ }
625
+ }
626
+ },
627
+
628
+ _checkAllCurrentStates: function(reqState, tree) {
629
+ var currentStates = this.currentState(tree) || [];
630
+ if (currentStates === reqState) {
631
+ return true;
632
+ } else if (typeof currentStates === 'string' &&
633
+ reqState === this._all_states[tree][currentStates]) {
634
+ return true;
635
+ } else if (goog.isArray(currentStates) &&
636
+ (goog.array.indexOf(currentStates, reqState) > -1)) {
637
+ return true;
638
+ } else {
639
+ return false;
640
+ }
641
+ },
642
+
643
+ _flushPendingEvents: function() {
644
+ var args, pa = this._pendingEvents.shift();
645
+ if (!pa) return;
646
+ args = pa.args;
647
+ args.unshift(pa.evt);
648
+ this.sendEvent.apply(this, args);
649
+ },
650
+
651
+ _flushPendingStateTransitions: function() {
652
+ var pending = this._pendingStateTransitions.shift(), msg;
653
+ if (!pending) return false;
654
+ this.goToState(pending.requestedState, pending.tree);
655
+ return true;
656
+ },
657
+
658
+ _parentStateObject: function(name, tree) {
659
+ if (name &&
660
+ tree &&
661
+ this._all_states[tree] &&
662
+ this._all_states[tree][name]) {
663
+ return this._all_states[tree][name];
664
+ }
665
+ },
666
+
667
+ _fullEnter: function(state) {
668
+ var pState, enterStateHandled = false;
669
+ if (!state) return;
670
+
671
+ try {
672
+ if (state.enterState) state.enterState();
673
+ if (state.didEnterState) state.didEnterState();
674
+ } catch(e){
675
+ if (DEBUG_MODE) {
676
+ Stativus.DebugMessagingObject.sendError('ENTER STATE', state.name, 'EXECEPTION ['+e+']', state.globalConcurrentState);
677
+ }
678
+ }
679
+
680
+ if (state.parentState) {
681
+ pState = state.statechart.getState(
682
+ state.parentState,
683
+ state.globalConcurrentState
684
+ );
685
+ pState.setHistoryState(state);
686
+ }
687
+ this._unwindEnterStateStack();
688
+ },
689
+
690
+ _fullExit: function(state) {
691
+ var pState;
692
+ if (!state) return;
693
+ var exitStateHandled = false;
694
+
695
+ try {
696
+ if (state.exitState) state.exitState();
697
+ if (state.didExitState) state.didExitState();
698
+ } catch (e){
699
+ if (DEBUG_MODE) {
700
+ Stativus.DebugMessagingObject.sendError('EXIT STATE', state.name, 'EXECEPTION ['+e+']', state.globalConcurrentState);
701
+ }
702
+ }
703
+
704
+ if (goog.DEBUG) {
705
+ ww.Statechart.DebugMessagingObject.sendInfo('EXIT STATE', state.name, 'Completed', state.globalConcurrentState);
706
+ }
707
+ this._unwindExitStateStack();
708
+ },
709
+
710
+ _initiateEnterStateSequence: function() {
711
+ var enterStates, enterMatchIndex, concurrentTree, tree,
712
+ allStates, i, cState;
713
+
714
+ enterStates = this._enterStates;
715
+ enterMatchIndex = this._enterStateMatchIndex;
716
+ concurrentTree = this._enterStateConcurrentTree;
717
+ tree = this._enterStateTree;
718
+ allStates = this._all_states[tree];
719
+
720
+ // Initialize the Enter State Stack
721
+ this._enterStateStack = this._enterStateStack || [];
722
+
723
+ // Finally, from the common parent state, but not including the parent
724
+ // state, enter the sub states down to the requested state. If the
725
+ // requested state has an initial sub state, then we must enter it too
726
+ i = enterMatchIndex - 1;
727
+ cState = enterStates[i];
728
+ if (cState) {
729
+ this._cascadeEnterSubstates(
730
+ cState,
731
+ enterStates,
732
+ (i - 1),
733
+ concurrentTree || tree,
734
+ allStates
735
+ );
736
+ }
737
+
738
+ // once, we have fully hydrated the Enter State Stack, we must
739
+ // actually async unwind it
740
+ this._unwindEnterStateStack();
741
+
742
+ // Cleanup
743
+ enterStates = null;
744
+ enterMatchIndex = null;
745
+ concurrentTree = null;
746
+ tree = null;
747
+
748
+ delete this._enterStates;
749
+ delete this._enterStateMatchIndex;
750
+ delete this._enterStateConcurrentTree;
751
+ delete this._enterStateTree;
752
+ },
753
+
754
+ _cascadeEnterSubstates: function(start,
755
+ requiredStates,
756
+ index,
757
+ tree,
758
+ allStates) {
759
+ var cState, len = requiredStates.length, pState, subStates,
760
+ that = this, nTree, bTree, name, currStates, aTrees;
761
+
762
+ if (!start) return;
763
+
764
+ name = start.name;
765
+ this._enterStateStack.push(start);
766
+ this._current_state[tree] = start;
767
+ start.localConcurrentState = tree;
768
+ if (start.substatesAreConcurrent) {
769
+ tree = start.globalConcurrentState || ww.Statechart.DEFAULT_TREE;
770
+ nTreeBase = [ww.Statechart.SUBSTATE_DELIM, tree, name].join('=>');
771
+ start.history = start.history || {};
772
+ subStates = start.substates || [];
773
+ goog.array.forEach(subStates, function(x) {
774
+ nTree = nTreeBase + '=>' + x;
775
+ cState = allStates[x];
776
+
777
+ // Now, we have to push the item onto the active subtrees for
778
+ // the base tree for later use of the events.
779
+ bTree = cState.globalConcurrentState || ww.Statechart.DEFAULT_TREE;
780
+ aTrees = that._active_subtrees[bTree] || [];
781
+ aTrees.unshift(nTree);
782
+ that._active_subtrees[bTree] = aTrees;
783
+
784
+ if (index > -1 && requiredStates[index] === cState) index -= 1;
785
+ that._cascadeEnterSubstates(
786
+ cState,
787
+ equiredStates,
788
+ index,
789
+ nTree,
790
+ allStates
791
+ );
792
+ });
793
+ return;
794
+ }
795
+ else {
796
+ // now we can trigger the lower levels of the state
797
+ cState = requiredStates[index];
798
+ if (cState) {
799
+ if (index > -1 && requiredStates[index] === cState) index -= 1;
800
+ this._cascadeEnterSubstates(
801
+ cState,
802
+ requiredStates,
803
+ index,
804
+ tree,
805
+ allStates
806
+ );
807
+ }
808
+ // now we will go into the initial substates of this state
809
+ else {
810
+ cState = allStates[start.initialSubstate];
811
+ this._cascadeEnterSubstates(
812
+ cState,
813
+ requiredStates,
814
+ index,
815
+ tree,
816
+ allStates
817
+ );
818
+ }
819
+ }
820
+ },
821
+
822
+ _fullExitFromSubstates: function(tree, stopState) {
823
+ var cStates, allStates, func, that = this;
824
+ if (!tree || !stopState || !tree || !stopState.substates) return;
825
+
826
+ allStates = this._all_states[tree];
827
+ cStates = this._current_state;
828
+ this._exitStateStack = this._exitStateStack || [];
829
+
830
+ goog.array.forEach(stopState.substates, function(state) {
831
+ var substateTree, currState, curr, exitStateHandled, aTrees;
832
+ substateTree = [
833
+ ww.Statechart.SUBSTATE_DELIM,
834
+ tree,
835
+ stopState.name,
836
+ state
837
+ ].join('=>');
838
+ currState = cStates[substateTree];
839
+ while (currState && currState !== stopState) {
840
+ exitStateHandled = false;
841
+ if (!currState) continue;
842
+
843
+ that._exitStateStack.unshift(currState);
844
+
845
+ // check to see if it has substates
846
+ if (currState.substatesAreConcurrent) {
847
+ that._fullExitFromSubstates(tree, currState);
848
+ }
849
+
850
+ curr = currState.parentState;
851
+ currState = allStates[curr];
852
+ }
853
+
854
+ // Now, remove this from the active substate tree
855
+ that._active_subtrees[tree] = that._removeFromActiveTree(
856
+ tree,
857
+ substateTree
858
+ );
859
+ });
860
+ },
861
+
862
+ // this function unwinds the next item on the exitStateStack...
863
+ _unwindExitStateStack: function() {
864
+ var stateToExit, delayForAsync = false, stateRestart, sc = this;
865
+ this._exitStateStack = this._exitStateStack || [];
866
+ stateToExit = this._exitStateStack.shift();
867
+ if (stateToExit) {
868
+ if (stateToExit.willExitState) {
869
+ // Now for some amazing encapsulation magic with closures
870
+ // We are going to create a temporary object that gets passed
871
+ // into the willExitState call that will restart the state
872
+ // exit for this path as needed
873
+ stateRestart = function(){
874
+ var sc = this._statechart;
875
+ if (DEBUG_MODE) {
876
+ Stativus.DebugMessagingObject.sendLog('ASYNC', stateToExit.name, 'willExitState() completed!', stateToExit.globalConcurrentState);
877
+ }
878
+ if (sc) sc._fullExit(stateToExit);
879
+ };
880
+ delayForAsync = stateToExit.willExitState(stateRestart);
881
+ if (goog.DEBUG) {
882
+ if (delayForAsync) {
883
+ ww.Statechart.DebugMessagingObject.sendLog('ASYNC', stateToExit.name, 'exitState() delayed', stateToExit.globalConcurrentState);
884
+ } else {
885
+ ww.Statechart.DebugMessagingObject.sendWarn('ASYNC', stateToExit.name, 'Didn\'t return \'true\' willExitState() which is needed if you want async', stateToExit.globalConcurrentState);
886
+ }
887
+ }
888
+ }
889
+ if (!delayForAsync) this._fullExit(stateToExit);
890
+ }
891
+ else {
892
+ delete this._exitStateStack;
893
+ this._initiateEnterStateSequence();
894
+ }
895
+ },
896
+
897
+ // this function unwinds the next item on the enterStateStack...
898
+ _unwindEnterStateStack: function() {
899
+ var stateToEnter, delayForAsync = false, stateRestart, more, that = this;
900
+ this._exitStateStack = this._exitStateStack || [];
901
+ stateToEnter = this._enterStateStack.shift();
902
+ if (stateToEnter) {
903
+ if (stateToEnter.willEnterState) {
904
+ // Now for some amazing encapsulation magic with closures
905
+ // We are going to create a temporary object that gets passed
906
+ // into the willExitState call that will restart the state
907
+ // exit for this path as needed
908
+ stateRestart = function() {
909
+ if (goog.DEBUG) {
910
+ ww.Statechart.DebugMessagingObject.sendLog('ASYNC', stateToEnter.name, 'willEnterState() completed!', stateToEnter.globalConcurrentState);
911
+ }
912
+ if (that) that._fullEnter(stateToEnter);
913
+ };
914
+ delayForAsync = stateToEnter.willEnterState(stateRestart);
915
+ if (goog.DEBUG) {
916
+ if (delayForAsync) {
917
+ ww.Statechart.DebugMessagingObject.sendLog('ASYNC', stateToEnter.name, 'enterState() delayed', stateToEnter.globalConcurrentState);
918
+ } else {
919
+ ww.Statechart.DebugMessagingObject.sendWarn('ASYNC', stateToEnter.name, 'Didn\'t return \'true\' willEnterState() which is needed if you want async', stateToEnter.globalConcurrentState);
920
+ }
921
+ }
922
+ }
923
+ if (!delayForAsync) this._fullEnter(stateToEnter);
924
+ }
925
+ else {
926
+ delete this._enterStateStack;
927
+
928
+ // Ok, we're done with the current state transition. Make sure to unlock
929
+ // the goToState and let other pending state transitions
930
+ this._goToStateLocked = false;
931
+ more = this._flushPendingStateTransitions();
932
+ if (!more && !this._inInitialSetup) {
933
+ // Once pending state transitions are flushed then go ahead and
934
+ // start flush pending actions
935
+ this._flushPendingEvents();
936
+ }
937
+ }
938
+ },
939
+
940
+ // TODO: make this more efficient
941
+ _removeFromActiveTree: function(baseTree, tree) {
942
+ var nArray = [], aTrees = this._active_subtrees[baseTree];
943
+ if (!aTrees) return [];
944
+ if (!tree) return aTrees;
945
+
946
+ goog.array.forEach(aTrees, function(x) {
947
+ if (x !== tree) nArray.push(x);
948
+ });
949
+
950
+ return nArray;
951
+ },
952
+
953
+ _parentStates: function(state) {
954
+ var ret = [], curr = state;
955
+ // always add first state
956
+ ret.push(curr);
957
+ curr = this._parentStateObject(
958
+ curr.parentState,
959
+ curr.globalConcurrentState
960
+ );
961
+
962
+ while (curr) {
963
+ ret.push(curr);
964
+ curr = this._parentStateObject(
965
+ curr.parentState,
966
+ curr.globalConcurrentState
967
+ );
968
+ }
969
+ return ret;
970
+ },
971
+
972
+ _parentStatesWithRoot: function(state) {
973
+ var ret = this._parentStates(state);
974
+ ret.push('root');
975
+ return ret;
976
+ }
977
+
978
+ };
979
+
980
+ /**
981
+ * Cascade events.
982
+ * @param {Event} evt The original event.
983
+ * @param {Array} args Event args.
984
+ * @param {ww.State} responder Responder state.
985
+ * @param {Array} allStates All the states.
986
+ * @param {String} tree The state tree.
987
+ * @return {Array} Who handled the event.
988
+ */
989
+ ww.Statechart.prototype['_cascadeEvents'] =
990
+ function(evt, args, responder, allStates, tree) {
991
+ var handled, trees, len, ssName, found = false;
992
+
993
+ // substate prep work...
994
+ if (tree) {
995
+ trees = tree.split('=>');
996
+ len = trees.length || 0;
997
+ ssName = trees[len - 1];
998
+ }
999
+
1000
+ while (!handled && responder) {
1001
+ if (responder[evt]) {
1002
+ if (goog.DEBUG) {
1003
+ ww.Statechart.DebugMessagingObject.sendInfo('EVENT', responder.name, 'Fired \''+evt+'\' with '+(args.length || 0)+' argument(s)', responder.globalConcurrentState);
1004
+ }
1005
+ try {
1006
+ handled = responder[evt].apply(responder, args);
1007
+ } catch(e){
1008
+ if (DEBUG_MODE) {
1009
+ Stativus.DebugMessagingObject.sendError('EVENT', responder.name, 'Fired \''+evt+'\': Exception: '+e, responder.globalConcurrentState);
1010
+ }
1011
+ }
1012
+ found = true;
1013
+ }
1014
+ // check to see if we have reached the end of this tree
1015
+ if (tree && ssName === responder.name) return [handled, found];
1016
+ if (!handled && responder.parentState) {
1017
+ responder = allStates[responder.parentState];
1018
+ } else {
1019
+ responder = null;
1020
+ }
1021
+ }
1022
+
1023
+ return [handled, found];
1024
+ };