forked from flamejs/flame.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstatechart.js
103 lines (93 loc) · 3.55 KB
/
statechart.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*jshint loopfunc: true */
Flame.State = Ember.Object.extend({
gotoState: function(stateName) {
this.get('owner').gotoState(stateName);
},
$: function(args) {
args = Array.prototype.slice.call(arguments);
var owner = this.get('owner');
return owner.$.apply(owner, args);
}
});
Flame.State.reopenClass({
gotoHandler: function(stateName, returnValue) {
return function() {
this.gotoState(stateName);
return returnValue === undefined ? true : returnValue;
};
}
});
Flame.Statechart = {
initialState: null,
currentState: undefined,
_currentStateName: undefined,
init: function() {
this._super();
// Look for defined states and initialize them
var key;
for (key in this) {
var state = this[key];
if (Flame.State.detect(state)) {
this.set(key, state.create({owner: this}));
this._setupProxyMethods(this[key]);
}
}
ember_assert("No initial state defined for statechart!", !Ember.none(this.get('initialState')));
this.gotoState(this.get('initialState'));
},
/**
Sets up proxy methods so that methods called on the owner of the statechart
will be invoked on the current state if they are not present on the owner of
the statechart.
*/
_setupProxyMethods: function(state) {
for (var property in state) {
if (state.constructor.prototype.hasOwnProperty(property) && Ember.typeOf(state[property]) === "function" &&
!this[property] && property !== "enterState" && property !== "exitState") {
this[property] = function(methodName) {
return function(args) {
args = Array.prototype.slice.call(arguments);
args.unshift(methodName);
return this.invokeStateMethod.apply(this, args);
};
}(property);
}
}
},
gotoState: function(stateName) {
ember_assert("Cannot go to an undefined or null state!", !Ember.none(stateName));
var currentState = this.get('currentState');
var newState = this.get(stateName);
//do nothing if we are already in the state to go to
if (currentState === newState) {
return;
}
if (!Ember.none(newState) && newState instanceof Flame.State) {
if (!Ember.none(currentState)) {
if (currentState.exitState) currentState.exitState();
}
this._currentStateName = stateName;
this.set('currentState', newState);
if (newState.enterState) newState.enterState();
} else {
throw new Error("%@ is not a state!".fmt(stateName));
}
},
/**
* Is this state chart currently in a state with the given name?
* @param stateName
* @returns {Boolean} is this statechart currently in a state with the given name?
*/
isCurrentlyIn: function(stateName) {
return this._currentStateName === stateName;
},
invokeStateMethod: function(methodName, args) {
args = Array.prototype.slice.call(arguments); args.shift();
var state = this.get('currentState');
ember_assert("Cannot invoke state method without having a current state!", !Ember.none(state) && state instanceof Flame.State);
var method = state[methodName];
if (Ember.typeOf(method) === "function") {
return method.apply(state, args);
}
}
};