@@ -6,27 +6,6 @@ want to start fading during an `onleavestate` handler, but not trigger the next
66
77Something like
88
9- var fsm = StateMachine.create({
10- initial: 'green',
11- events: [
12- { name: 'play', from: 'menu', to: 'game', async: true },
13- { name: 'lose', from: 'game', to: 'menu' },
14- ]});
15-
16- fsm.onleavemenu = function() {
17- $('menu').fade(function() {
18- fsm.transition();
19- });
20- }
21-
22- fsm.onentergame = function() {
23- // this doesn't get called until fsm.transition() is called when the menu has finished fading
24- }
25-
26- fsm.play();
27-
28- Also possible to simply return false from onleavestate hook instead of having to declare event as async:
29-
309 var fsm = StateMachine.create({
3110 initial: 'green',
3211 events: [
@@ -49,7 +28,7 @@ Also possible to simply return false from onleavestate hook instead of having to
4928
5029Or.... something else ! Have to wait and see how it pans out (without breaking existing synchronous behavior)
5130
52- Javascript Finite State Machine (v1.3 .0)
31+ Javascript Finite State Machine (v2.0 .0)
5332========================================
5433
5534This standalone javascript micro-framework provides a finite state machine for your pleasure.
@@ -105,24 +84,73 @@ along with the following members:
10584 * fsm.can(e) - return true if event ` e ` can be fired in the current state
10685 * fsm.cannot(e) - return true if event ` e ` cannot be fired in the current state
10786
108- Hooks
109- =====
87+ Multiple 'from' and 'to' states for a single event
88+ ==================================================
89+
90+ If an event is allowed ** from** multiple states, and always transitions ** to** the same
91+ state, then simply provide an array of states in the ` from ` attribute of an event.
92+
93+ If an event is allowed ** from** multiple states, but should transition ** to** a different
94+ state depending on the current state, then provide multiple event entries with
95+ the same name:
96+
97+ var fsm = StateMachine.create({
98+ initial: 'hungry',
99+ events: [
100+ { name: 'eat', from: 'hungry', to: 'satisfied' },
101+ { name: 'eat', from: 'satisfied', to: 'full' },
102+ { name: 'eat', from: 'full', to: 'sick' },
103+ { name: 'rest', from: ['hungry', 'satisfied', 'full', 'sick'], to: 'hungry' },
104+ ]});
105+
106+ This example will create an object with 2 event methods:
107+
108+ * fsm.eat()
109+ * fsm.rest()
110110
111- >> _ NOTE: I'm using the word 'hook' to avoid overloading the word 'event'._
111+ The ` rest ` event will always transition to the ` hungry ` state, while the ` eat ` event
112+ will transition to a state that is dependent on the current state.
112113
113- 4 hooks are available if your object has methods using the following naming conventions:
114+ >> NOTE: The ` rest ` event in the above example can also be specified as multiple events with
115+ the same name if you prefer the verbose approach:
116+
117+ var fsm = StateMachine.create({
118+ initial: 'hungry',
119+ events: [
120+ { name: 'eat', from: 'hungry', to: 'satisfied' },
121+ { name: 'eat', from: 'satisfied', to: 'full' },
122+ { name: 'eat', from: 'full', to: 'sick' },
123+ { name: 'rest', from: 'hungry', to: 'hungry' }, // NOTE: this is a no-op.
124+ { name: 'rest', from: 'satisfied', to: 'hungry' },
125+ { name: 'rest', from: 'full', to: 'hungry' },
126+ { name: 'rest', from: 'sick', to: 'hungry' },
127+ ]});
128+
129+ Callbacks
130+ =========
131+
132+ 4 callbacks are available if your state machine has methods using the following naming conventions:
114133
115134 * onbefore** event** - fired before an event
116135 * onafter** event** - fired after an event
117136 * onenter** state** - fired when entering a state
118137 * onleave** state** - fired when leaving a state
119138
120- For convenience, the 2 most useful hooks can be shortened:
139+ For convenience, the 2 most useful callbacks can be shortened:
121140
122141 * on** event** - convenience shorthand for onafter** event**
123142 * on** state** - convenience shorthand for onenter** state**
124143
125- Hooks can be added after the FSM is created:
144+ In addition, a generic ` onchangestate() ` callback can be used to call a single function for _ all_ state changes:
145+
146+ All callbacks will be passed the same arguments:
147+
148+ * event name
149+ * from state
150+ * to state
151+ * _ (followed by any arguments you passed into the original event method)_
152+
153+ Callbacks can be specified when the state machine is first created:
126154
127155 var fsm = StateMachine.create({
128156 initial: 'green',
@@ -131,77 +159,48 @@ Hooks can be added after the FSM is created:
131159 { name: 'panic', from: 'yellow', to: 'red' },
132160 { name: 'calm', from: 'red', to: 'yellow' },
133161 { name: 'clear', from: 'yellow', to: 'green' }
134- ]});
135-
136- fsm.onpanic = function() { alert('panic!'); };
137- fsm.onclear = function() { alert('all clear!'); };
138- fsm.ongreen = function() { document.body.className = 'green'; };
139- fsm.onyellow = function() { document.body.className = 'yellow'; };
140- fsm.onred = function() { document.body.className = 'red'; };
162+ ],
163+ callbacks: {
164+ onpanic: function(event, from, to) { alert('panic!'); },
165+ onclear: function(event, from, to) { alert('all clear!'); },
166+ ongreen: function(event, from, to) { document.body.className = 'green'; },
167+ onyellow: function(event, from, to) { document.body.className = 'yellow'; },
168+ onred: function(event, from, to) { document.body.className = 'red'; },
169+ }
170+ });
141171
142172 fsm.panic()
143173 fsm.clear()
144174 ...
145175
146- * NEW in v1.3.0* is a generic ` onchangestate(from,to) ` hook was added to allow a single function
147- to be called on all state changes:
148-
149- fsm.onchangestate = function(from, to) { document.body.className = to; };
150-
151-
152- Multiple 'from' states for a single event
153- =========================================
176+ Additionally, they can be added and removed from the state machine at any time:
154177
155- If an event is allowed ** from** multiple states, and always transitions ** to** the same
156- state, then simply provide an array of states in the ` from ` attribute of an event:
178+ fsm.ongreen = null;
179+ fsm.onyellow = null;
180+ fsm.onred = null;
181+ fsm.onchangestate = function(event, from, to) { document.body.className = to; };
157182
158- var fsm = StateMachine.create({
159- initial: 'green',
160- events: [
161- { name: 'warn', from: ['green'], to: 'yellow' },
162- { name: 'panic', from: ['green', 'yellow'], to: 'red' },
163- { name: 'calm', from: ['red'], to: 'yellow' },
164- { name: 'clear', from: ['red', 'yellow'], to: 'green' }
165- ]});
166-
167- Multiple 'to' states for a single event
168- =======================================
169-
170- If an event is allowed ** from** multiple states, but should transition ** to** a different
171- state depending on the current state, then provide multiple event entries with
172- the same name:
173-
174- var fsm = StateMachine.create({
175- initial: 'hungry',
176- events: [
177- { name: 'eat', from: 'hungry', to: 'satisfied' },
178- { name: 'eat', from: 'satisfied', to: 'full' },
179- { name: 'eat', from: 'full', to: 'sick' },
180- { name: 'rest', from: ['hungry', 'satisfied', 'full', 'sick'], to: 'hungry' },
181- ]});
182-
183- This example will create an object with 2 event methods:
184-
185- * fsm.eat()
186- * fsm.rest()
183+ Asynchronous State Transitions
184+ ==============================
187185
188- The ` rest ` event will always transition to the ` hungry ` state, while the ` eat ` event will transition to a state that is dependent on the current state.
186+ * ** TODO **
189187
190188State Machine Classes
191189=====================
192190
193191You can also turn all instances of a _ class_ into an FSM by applying
194- the state machine functionality to the prototype object and providing
195- a ` startup ` event for use when constructing instances:
192+ the state machine functionality to the prototype, including your callbacks
193+ in your prototype, and providing a ` startup ` event for use when constructing
194+ instances:
196195
197196 MyFSM = function() { // my constructor function
198197 this.startup();
199198 };
200199
201200 MyFSM.prototype = {
202201
203- onpanic: function() { alert('panic'); },
204- onclear: function() { alert('all is clear'); },
202+ onpanic: function(event, from, to ) { alert('panic'); },
203+ onclear: function(event, from, to ) { alert('all is clear'); },
205204
206205 // other prototype methods
207206
@@ -250,7 +249,7 @@ implicit `startup` event will be created for you and fired when the state machin
250249 ]});
251250 alert(fsm.current); // "green"
252251
253- If your object already has a ` startup ` method you can change the name of the initial event
252+ If your object already has a ` startup ` method you can use a different name for the initial event
254253
255254 var fsm = StateMachine.create({
256255 initial: { state: 'green', event: 'init' },
0 commit comments