Skip to content

Commit d1c208a

Browse files
committed
added a generic onchangestate(from, to) callback that will trigger on ALL state changes (and bump version number to 1.3.0)
1 parent 3ad3b49 commit d1c208a

6 files changed

Lines changed: 73 additions & 40 deletions

File tree

README.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
1-
Javascript Finite State Machine
2-
===============================
1+
Javascript Finite State Machine (v1.3.0)
2+
========================================
33

44
This standalone javascript micro-framework provides a finite state machine for your pleasure.
55

66
* You can find the [code here](https://github.com/jakesgordon/javascript-state-machine)
77
* You can find a [description here](http://codeincomplete.com/posts/2011/6/1/javascript_state_machine/)
88
* You can find a [working demo here](http://codeincomplete.com/posts/2011/6/1/javascript_state_machine/example/)
99

10-
New in version 1.2
11-
==================
12-
13-
* Allows the same event to transition to different states, depending on the current state (see 'Multiple...' sections below)
14-
1510
Download
1611
========
1712

@@ -95,6 +90,12 @@ Hooks can be added after the FSM is created:
9590
fsm.clear()
9691
...
9792

93+
*NEW in v1.3.0* is a generic `onstatechage` hook was added to allow a single function
94+
to be called, with from and to parameters, on all state changes
95+
96+
fsm.onchangestate = function(from, to) { document.body.className = to; };
97+
98+
9899
Multiple 'from' states for a single event
99100
=========================================
100101

@@ -224,6 +225,10 @@ same as the first example in this section where you simply define your own start
224225

225226
So you have a number of choices available to you when initializing your state machine.
226227

228+
Release Notes
229+
=============
230+
231+
See [RELEASE NOTES](https://github.com/jakesgordon/javascript-state-machine/blob/master/RELEASE_NOTES.md) file.
227232

228233
License
229234
=======

RELEASE_NOTES.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
Version 1.3.0 (unreleased)
3+
--------------------------
4+
* added a generic `onchangestate` hook to detect all state changes with a single hook (with from/to parameters).
5+
6+
Version 1.2.0 (June 21st 2011)
7+
------------------------------
8+
* allows the same event to transition to different states, depending on the current state (see 'Multiple...' sections in README.md)
9+
10+
Version 1.0.0 (June 1st 2011)
11+
-----------------------------
12+
* initial version

state-machine.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ StateMachine = {
22

33
//---------------------------------------------------------------------------
44

5-
VERSION: "1.2.0",
5+
VERSION: "1.3.0",
66

77
//---------------------------------------------------------------------------
88

9-
create: function(cfg) {
9+
create: function(cfg, target) {
1010

1111
var initial = (typeof cfg.initial == 'string') ? { state: cfg.initial } : cfg.initial; // allow for a simple string, or an object with { state: 'foo', event: 'setup', defer: true|false }
12-
var fsm = cfg.target || {};
12+
var fsm = target || cfg.target || {};
1313
var events = {};
1414

1515
var add = function(e) {
@@ -70,6 +70,11 @@ StateMachine = {
7070
var enterState = this['onenter' + to] || this['on' + to];
7171
if (enterState)
7272
enterState.apply(this, arguments);
73+
74+
var changeState = this['onchangestate'];
75+
if (changeState)
76+
changeState.call(this, from, to);
77+
7378
}
7479

7580
var afterEvent = this['onafter' + name] || this['on' + name];

test/test_advanced.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ test("hooks are called when appropriate for multiple 'from' and 'to' transitions
7979

8080
var called = [];
8181

82+
// generic state hook
83+
fsm.onchangestate = function(from,to) { called.push('onchange from ' + from + ' to ' + to); };
84+
8285
// state hooks
8386
fsm.onenterhungry = function() { called.push('onenterhungry'); };
8487
fsm.onleavehungry = function() { called.push('onleavehungry'); };
@@ -97,19 +100,19 @@ test("hooks are called when appropriate for multiple 'from' and 'to' transitions
97100

98101
called = [];
99102
fsm.eat();
100-
deepEqual(called, ['onbeforeeat', 'onleavehungry', 'onentersatisfied', 'onaftereat']);
103+
deepEqual(called, ['onbeforeeat', 'onleavehungry', 'onentersatisfied', 'onchange from hungry to satisfied', 'onaftereat']);
101104

102105
called = [];
103106
fsm.eat();
104-
deepEqual(called, ['onbeforeeat', 'onleavesatisfied', 'onenterfull', 'onaftereat']);
107+
deepEqual(called, ['onbeforeeat', 'onleavesatisfied', 'onenterfull', 'onchange from satisfied to full', 'onaftereat']);
105108

106109
called = [];
107110
fsm.eat();
108-
deepEqual(called, ['onbeforeeat', 'onleavefull', 'onentersick', 'onaftereat']);
111+
deepEqual(called, ['onbeforeeat', 'onleavefull', 'onentersick', 'onchange from full to sick', 'onaftereat']);
109112

110113
called = [];
111114
fsm.rest();
112-
deepEqual(called, ['onbeforerest', 'onleavesick', 'onenterhungry', 'onafterrest']);
115+
deepEqual(called, ['onbeforerest', 'onleavesick', 'onenterhungry', 'onchange from sick to hungry', 'onafterrest']);
113116

114117
});
115118

@@ -124,6 +127,9 @@ test("hooks are called when appropriate for prototype based state machine", func
124127

125128
myFSM.prototype = {
126129

130+
// generic state hook
131+
onchangestate: function(from,to) { this.called.push('onchange from ' + from + ' to ' + to); },
132+
127133
// state hooks
128134
onentergreen: function() { this.called.push('onentergreen'); },
129135
onleavegreen: function() { this.called.push('onleavegreen'); },
@@ -159,16 +165,16 @@ test("hooks are called when appropriate for prototype based state machine", func
159165
equal(a.current, 'green', 'start with correct state');
160166
equal(b.current, 'green', 'start with correct state');
161167

162-
deepEqual(a.called, ['onbeforestartup', 'onentergreen', 'onafterstartup']);
163-
deepEqual(b.called, ['onbeforestartup', 'onentergreen', 'onafterstartup']);
168+
deepEqual(a.called, ['onbeforestartup', 'onentergreen', 'onchange from none to green', 'onafterstartup']);
169+
deepEqual(b.called, ['onbeforestartup', 'onentergreen', 'onchange from none to green', 'onafterstartup']);
164170

165171
a.warn();
166172

167173
equal(a.current, 'yellow', 'maintain independent current state');
168174
equal(b.current, 'green', 'maintain independent current state');
169175

170-
deepEqual(a.called, ['onbeforestartup', 'onentergreen', 'onafterstartup', 'onbeforewarn', 'onleavegreen', 'onenteryellow', 'onafterwarn']);
171-
deepEqual(b.called, ['onbeforestartup', 'onentergreen', 'onafterstartup']);
176+
deepEqual(a.called, ['onbeforestartup', 'onentergreen', 'onchange from none to green', 'onafterstartup', 'onbeforewarn', 'onleavegreen', 'onenteryellow', 'onchange from green to yellow', 'onafterwarn']);
177+
deepEqual(b.called, ['onbeforestartup', 'onentergreen', 'onchange from none to green', 'onafterstartup']);
172178

173179
});
174180

test/test_basics.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ test("hooks are called when appropriate", function() {
182182

183183
var called = [];
184184

185+
// generic state hook
186+
fsm.onchangestate = function(from,to) { called.push('onchange from ' + from + ' to ' + to); };
187+
185188
// state hooks
186189
fsm.onentergreen = function() { called.push('onentergreen'); };
187190
fsm.onleavegreen = function() { called.push('onleavegreen'); };
@@ -198,23 +201,24 @@ test("hooks are called when appropriate", function() {
198201
fsm.onbeforecalm = function() { called.push('onbeforecalm'); };
199202
fsm.onaftercalm = function() { called.push('onaftercalm'); };
200203
fsm.onbeforeclear = function() { called.push('onbeforeclear'); };
201-
fsm.onafterclear = function() { called.push('onafterclear'); }
204+
fsm.onafterclear = function() { called.push('onafterclear'); };
205+
202206

203207
called = [];
204208
fsm.warn();
205-
deepEqual(called, ['onbeforewarn', 'onleavegreen', 'onenteryellow', 'onafterwarn']);
209+
deepEqual(called, ['onbeforewarn', 'onleavegreen', 'onenteryellow', 'onchange from green to yellow', 'onafterwarn']);
206210

207211
called = [];
208212
fsm.panic();
209-
deepEqual(called, ['onbeforepanic', 'onleaveyellow', 'onenterred', 'onafterpanic']);
213+
deepEqual(called, ['onbeforepanic', 'onleaveyellow', 'onenterred', 'onchange from yellow to red', 'onafterpanic']);
210214

211215
called = [];
212216
fsm.calm();
213-
deepEqual(called, ['onbeforecalm', 'onleavered', 'onenteryellow', 'onaftercalm']);
217+
deepEqual(called, ['onbeforecalm', 'onleavered', 'onenteryellow', 'onchange from red to yellow', 'onaftercalm']);
214218

215219
called = [];
216220
fsm.clear();
217-
deepEqual(called, ['onbeforeclear', 'onleaveyellow', 'onentergreen', 'onafterclear']);
221+
deepEqual(called, ['onbeforeclear', 'onleaveyellow', 'onentergreen', 'onchange from yellow to green', 'onafterclear']);
218222

219223
});
220224

test/test_initialize.js

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,21 @@ module("special initialization options", {
44

55
setup: function() {
66
this.called = [];
7-
this.onbeforeinit = function() { this.called.push("onbeforeinit"); };
8-
this.onafterinit = function() { this.called.push("onafterinit"); };
9-
this.onbeforestartup = function() { this.called.push("onbeforestartup"); };
10-
this.onafterstartup = function() { this.called.push("onafterstartup"); };
11-
this.onbeforepanic = function() { this.called.push("onbeforepanic"); };
12-
this.onafterpanic = function() { this.called.push("onafterpanic"); };
13-
this.onbeforecalm = function() { this.called.push("onbeforecalm"); };
14-
this.onaftercalm = function() { this.called.push("onaftercalm"); };
15-
this.onenternone = function() { this.called.push("onenternone"); };
16-
this.onentergreen = function() { this.called.push("onentergreen"); };
17-
this.onenterred = function() { this.called.push("onenterred"); };
18-
this.onleavenone = function() { this.called.push("onleavenone"); };
19-
this.onleavegreen = function() { this.called.push("onleavegreen"); };
20-
this.onleavered = function() { this.called.push("onleavered"); };
7+
this.onchangestate = function(from,to) { this.called.push('onchange from ' + from + ' to ' + to); };
8+
this.onbeforeinit = function() { this.called.push("onbeforeinit"); };
9+
this.onafterinit = function() { this.called.push("onafterinit"); };
10+
this.onbeforestartup = function() { this.called.push("onbeforestartup"); };
11+
this.onafterstartup = function() { this.called.push("onafterstartup"); };
12+
this.onbeforepanic = function() { this.called.push("onbeforepanic"); };
13+
this.onafterpanic = function() { this.called.push("onafterpanic"); };
14+
this.onbeforecalm = function() { this.called.push("onbeforecalm"); };
15+
this.onaftercalm = function() { this.called.push("onaftercalm"); };
16+
this.onenternone = function() { this.called.push("onenternone"); };
17+
this.onentergreen = function() { this.called.push("onentergreen"); };
18+
this.onenterred = function() { this.called.push("onenterred"); };
19+
this.onleavenone = function() { this.called.push("onleavenone"); };
20+
this.onleavegreen = function() { this.called.push("onleavegreen"); };
21+
this.onleavered = function() { this.called.push("onleavered"); };
2122
}
2223

2324
});
@@ -46,7 +47,7 @@ test("initial state can be specified", function() {
4647
{ name: 'calm', from: 'red', to: 'green' }
4748
]});
4849
equal(this.current, 'green');
49-
deepEqual(this.called, ["onbeforestartup", "onleavenone", "onentergreen", "onafterstartup"]);
50+
deepEqual(this.called, ["onbeforestartup", "onleavenone", "onentergreen", "onchange from none to green", "onafterstartup"]);
5051
});
5152

5253
//-----------------------------------------------------------------------------
@@ -60,7 +61,7 @@ test("startup event name can be specified", function() {
6061
{ name: 'calm', from: 'red', to: 'green' }
6162
]});
6263
equal(this.current, 'green');
63-
deepEqual(this.called, ["onbeforeinit", "onleavenone", "onentergreen", "onafterinit"]);
64+
deepEqual(this.called, ["onbeforeinit", "onleavenone", "onentergreen", "onchange from none to green", "onafterinit"]);
6465
});
6566

6667
//-----------------------------------------------------------------------------
@@ -79,7 +80,7 @@ test("startup event can be deferred", function() {
7980
this.init();
8081

8182
equal(this.current, 'green');
82-
deepEqual(this.called, ["onbeforeinit", "onleavenone", "onentergreen", "onafterinit"]);
83+
deepEqual(this.called, ["onbeforeinit", "onleavenone", "onentergreen", "onchange from none to green", "onafterinit"]);
8384
});
8485

8586
//-----------------------------------------------------------------------------

0 commit comments

Comments
 (0)