middleman-wizard-template 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ };