├── VERSION ├── test ├── index.html └── js │ ├── StateTest.js │ ├── StateMachineTest.js │ ├── api │ └── puremvc-1.0.1.min.js │ └── FSMInjectorTest.js ├── LICENSE ├── src └── org │ └── puremvc │ └── js │ └── multicore │ └── utilities │ └── statemachine │ ├── State.js │ ├── FSMInjector.js │ └── StateMachine.js ├── README.md └── bin ├── puremvc-statemachine.1.0.min.js └── puremvc-statemachine.1.0.js /VERSION: -------------------------------------------------------------------------------- 1 | PureMVC State Machine Utility for Javascript (Ported) 2 | -------------------------------------------------------------------------- 3 | Release Date: 9/26/14 4 | Platform: JavaScript (Native) 5 | Version: 1 6 | Revision: 0 7 | Minor: 1 8 | Authors: Saad Shams 9 | ------------------------------------------------------------------------- 10 | 1.0 Initial version of Javascript State Machine utility on PureMVC.org. 11 | 12 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Lockable Door Demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | * PureMVC State Machine Utility for Javascript (Ported) - Copyright © 2013-2014 Saad Shams 2 | * PureMVC - Copyright © 2006-2014 Futurescale, Inc. 3 | * All rights reserved. 4 | 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | * Neither the name of Futurescale, Inc., PureMVC.org, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /src/org/puremvc/js/multicore/utilities/statemachine/State.js: -------------------------------------------------------------------------------- 1 | /* 2 | PureMVC JS Utility - StateMachine 3 | Copyright (c) 2014 Saad Shams, Cliff Hall 4 | Your reuse is governed by the Creative Commons Attribution 3.0 License 5 | */ 6 | 7 | /** 8 | * Constructor 9 | * 10 | * Defines a State. 11 | * @method State 12 | * @param {string} name id the id of the state 13 | * @param {string} entering an optional notification name to be sent when entering this state 14 | * @param {string} exiting an optional notification name to be sent when exiting this state 15 | * @param {string} changed an optional notification name to be sent when fully transitioned to this state 16 | * @return 17 | */ 18 | 19 | function State(name, entering, exiting, changed) { 20 | this.name = name; 21 | if(entering) this.entering = entering; 22 | if(exiting) this.exiting = exiting; 23 | if(changed) this.changed = changed; 24 | this.transitions = {}; 25 | } 26 | 27 | /** 28 | * Define a transition. 29 | * @method defineTrans 30 | * @param {string} action the name of the StateMachine.ACTION Notification type. 31 | * @param {string} target the name of the target state to transition to. 32 | * @return 33 | */ 34 | State.prototype.defineTrans = function(action, target) { 35 | if(this.getTarget(action) != null) return; 36 | this.transitions[action] = target; 37 | } 38 | 39 | /** 40 | * Remove a previously defined transition. 41 | * @method removeTrans 42 | * @param {string} action 43 | * @return 44 | */ 45 | State.prototype.removeTrans = function(action) { 46 | delete this.transitions[action]; 47 | } 48 | 49 | /** 50 | * Get the target state name for a given action. 51 | * @method getTarget 52 | * @param {string} action 53 | * @return State 54 | */ 55 | State.prototype.getTarget = function(action) { 56 | return this.transitions[action] ? this.transitions[action] : null; 57 | } 58 | 59 | // The state name 60 | State.prototype.name = null; 61 | 62 | // The notification to dispatch when entering the state 63 | State.prototype.entering = null; 64 | 65 | // The notification to dispatch when exiting the state 66 | State.prototype.exiting = null; 67 | 68 | // The notification to dispatch when the state has actually changed 69 | State.prototype.changed = null; 70 | 71 | /** 72 | * Transition map of actions to target states 73 | */ 74 | State.prototype.transitions = null; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [PureMVC](http://puremvc.github.com/) [JavaScript](https://github.com/PureMVC/puremvc-js-multicore-framework/wiki) State Machine Utility 2 | PureMVC is a lightweight framework for creating applications based upon the classic [Model-View-Controller](http://en.wikipedia.org/wiki/Model-view-controller) design meta-pattern. This is a JavaScript port of the [AS3 reference implementation of the State Machine Utility](https://github.com/PureMVC/puremvc-as3-util-statemachine/wiki). 3 | 4 | Unit Tests are included in this repository. 5 | 6 | * [Discussion](http://forums.puremvc.org/index.php?topic=2110.0) 7 | * [Overview Presentation](http://puremvc.tv/#P003/) 8 | 9 | ## Demos 10 | * [Demo: Lockable Door](https://github.com/PureMVC/puremvc-js-demo-lockabledoor/wiki) 11 | 12 | ## Status 13 | Production - [Version 1.0](https://github.com/PureMVC/puremvc-js-util-statemachine/blob/master/VERSION) 14 | 15 | ## Platforms / Technologies 16 | * [JavaScript](http://en.wikipedia.org/wiki/JavaScript) 17 | 18 | ## License 19 | * PureMVC State Machine Utility for Javascript (Ported) - Copyright © 2013-2014 Saad Shams 20 | * PureMVC - Copyright © 2006-2014 Futurescale, Inc. 21 | * All rights reserved. 22 | 23 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 24 | 25 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 26 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 27 | * Neither the name of Futurescale, Inc., PureMVC.org, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 28 | 29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /test/js/StateTest.js: -------------------------------------------------------------------------------- 1 | QUnit.module("State Test"); 2 | 3 | QUnit.test("Test Constructors", function(assert) { 4 | var state = new puremvc.statemachine.State("state1"); 5 | assert.ok(state, "Expecting $state to be defined"); 6 | assert.ok(state instanceof puremvc.statemachine.State, "state instanceof puremvc.statemachine.State"); 7 | assert.equal(state.name, "state1", "Expecting state.name to be 'state1'"); 8 | assert.equal(state.entering, null, "Expecting state.entering to be null"); 9 | assert.equal(state.exiting, null, "Expecting state.exiting to be null"); 10 | assert.equal(state.changed, null, "Expecting state.changed to be null"); 11 | assert.ok(state.transitions, "Expecting state.transitions to be ok"); 12 | 13 | var state = new puremvc.statemachine.State("state1", "entering", "exiting", "changed"); 14 | assert.ok(state, "Expecting $state to be defined"); 15 | assert.equal(state.name, "state1", "Expecting state.name to be 'state1'"); 16 | assert.equal(state.entering, "entering", "Expecting state.entering to be null"); 17 | assert.equal(state.exiting, "exiting", "Expecting state.exiting to be null"); 18 | assert.equal(state.changed, "changed", "Expecting state.changed to be null"); 19 | assert.ok(state.transitions, "Expecting state.transitions to be ok"); 20 | }); 21 | 22 | QUnit.test("Test Methods", function(assert) { 23 | var state = new puremvc.statemachine.State("state1"); 24 | assert.equal(typeof state.defineTrans, "function", "defineTrans"); 25 | assert.equal(typeof state.removeTrans, "function", "defineTrans"); 26 | assert.equal(typeof state.getTarget, "function", "defineTrans"); 27 | }); 28 | 29 | QUnit.test("Test DefineTrans", function(assert) { 30 | var state = new puremvc.statemachine.State("state1"); 31 | state.defineTrans("action", "target"); 32 | assert.equal(state.transitions["action"], "target", "Expecting state.transitions['action'] to be 'target'"); 33 | 34 | //redefining if it still exists 35 | state.defineTrans("action", "target"); 36 | assert.equal(state.transitions["action"], "target", "Expecting state.transitions['action'] to be 'target'"); 37 | }); 38 | 39 | QUnit.test("Test RemoveTrans", function(assert) { 40 | var state = new puremvc.statemachine.State("state1"); 41 | state.defineTrans("action", "target"); 42 | assert.equal(state.transitions["action"], "target", "Expecting state.transitions['action'] to be 'target'"); 43 | state.removeTrans("action"); 44 | assert.equal(state.transitions["action"], null, "Expecting state.transitions['action'] to be null"); 45 | 46 | //test removal of non existing action does not crash 47 | state.removeTrans("action1"); 48 | assert.ok(true, "Expecting removal not to crash"); 49 | }); 50 | 51 | QUnit.test("Test GetTarget", function(assert) { 52 | var state = new puremvc.statemachine.State("state1"); 53 | state.defineTrans("action", "target"); 54 | var target = state.getTarget("action"); 55 | assert.equal(target, "target", "Expecting target to be 'target'"); 56 | 57 | target = state.getTarget("action1"); 58 | assert.ok(target === null, "Expecting defined target to be null") 59 | }); -------------------------------------------------------------------------------- /bin/puremvc-statemachine.1.0.min.js: -------------------------------------------------------------------------------- 1 | (function(e){function t(e,t,n,r){this.name=e;if(t)this.entering=t;if(n)this.exiting=n;if(r)this.changed=r;this.transitions=new Object}function n(){puremvc.Mediator.call(this,n.NAME,null);this.states={}}function r(e){puremvc.Notifier.call(this);this.fsm=e}if(null==e)e=window;if(e.puremvc.statemachine){return}t.prototype.defineTrans=function(e,t){if(this.getTarget(e)!=null)return;this.transitions[e]=t};t.prototype.removeTrans=function(e){delete this.transitions[e]};t.prototype.getTarget=function(e){return this.transitions[e]?this.transitions[e]:null};t.prototype.name=null;t.prototype.entering=null;t.prototype.exiting=null;t.prototype.changed=null;t.prototype.transitions=null;n.prototype=new puremvc.Mediator;n.prototype.constructor=n;n.prototype.onRegister=function(){if(this.initial)this.transitionTo(this.initial,null)};n.prototype.registerState=function(e,t){if(e==null||this.states[e.name]!=null)return;this.states[e.name]=e;if(t)this.initial=e};n.prototype.removeState=function(e){var t=this.states[e];if(t==null)return;this.states[e]=null};n.prototype.transitionTo=function(e,t){if(e==null)return;this.canceled=false;if(this.getCurrentState()&&this.getCurrentState().exiting)this.sendNotification(this.getCurrentState().exiting,t,e.name);if(this.canceled){this.canceled=false;return}if(e.entering)this.sendNotification(e.entering,t);if(this.canceled){this.canceled=false;return}this.setCurrentState(e);if(e.changed){this.sendNotification(this.getCurrentState().changed,t)}this.sendNotification(n.CHANGED,this.getCurrentState(),this.getCurrentState().name)};n.prototype.listNotificationInterests=function(){return[n.ACTION,n.CANCEL]};n.prototype.handleNotification=function(e){switch(e.getName()){case n.ACTION:var t=e.getType();var r=this.getCurrentState().getTarget(t);var i=this.states[r];if(i)this.transitionTo(i,e.getBody());break;case n.CANCEL:this.canceled=true;break}};n.prototype.getCurrentState=function(){return this.viewComponent};n.prototype.setCurrentState=function(e){this.viewComponent=e};n.prototype.states=null;n.prototype.initial=null;n.prototype.canceled=null;n.NAME="StateMachine";n.ACTION=n.NAME+"/notes/action";n.CHANGED=n.NAME+"/notes/changed";n.CANCEL=n.NAME+"/notes/cancel";r.prototype=new puremvc.Notifier;r.prototype.constructor=r;r.prototype.inject=function(){var e=new puremvc.statemachine.StateMachine(this.multitonKey);var t=this.getStates();for(var n=0;n 11 | * This allows reconfiguration of the StateMachine 12 | * without changing any code, as well as making it 13 | * easier than creating all the State 14 | * instances and registering them with the 15 | * StateMachine at startup time. 16 | * 17 | * @ see State 18 | * @ see StateMachine 19 | */ 20 | 21 | /** 22 | * Constructor 23 | * @method FSMInjector 24 | * @param {Object} fsm JSON Object 25 | * @return 26 | */ 27 | function FSMInjector(fsm) { 28 | puremvc.Notifier.call(this); 29 | this.fsm = fsm; 30 | } 31 | 32 | FSMInjector.prototype = new puremvc.Notifier; 33 | FSMInjector.prototype.constructor = FSMInjector; 34 | 35 | /** 36 | * Inject the StateMachine into the PureMVC apparatus. 37 | *

38 | * Creates the StateMachine instance, registers all the states 39 | * and registers the StateMachine with the IFacade. 40 | * @method inject 41 | * @return 42 | */ 43 | FSMInjector.prototype.inject = function() { 44 | // Create the StateMachine 45 | var stateMachine = new puremvc.statemachine.StateMachine(); 46 | 47 | // Register all the states with the StateMachine 48 | var states = this.getStates(); 49 | for(var i=0; i 60 | * Creates and returns the array of State objects 61 | * from the FSM on first call, subsequently returns 62 | * the existing array.

63 | * 64 | * @method getStates 65 | * @return {Array} Array of States 66 | */ 67 | FSMInjector.prototype.getStates = function() { 68 | if(this.stateList == null) { 69 | this.stateList = []; 70 | 71 | var stateDefs = this.fsm.state ? this.fsm.state : []; 72 | for(var i=0; iState instance from its JSON definition. 83 | * @method createState 84 | * @param {Object} stateDef JSON Object 85 | * @return {State} 86 | */ 87 | FSMInjector.prototype.createState = function(stateDef) { 88 | // Create State object 89 | var name = stateDef['@name']; 90 | var exiting = stateDef['@exiting']; 91 | var entering = stateDef['@entering']; 92 | var changed = stateDef['@changed']; 93 | var state = new puremvc.statemachine.State(name, entering, exiting, changed); 94 | 95 | // Create transitions 96 | var transitions = stateDef.transition ? stateDef.transition : []; 97 | for(var i=0; i 10 | * Handles regisistration and removal of state definitions, 11 | * which include optional entry and exit commands for each 12 | * state.

13 | */ 14 | 15 | /** 16 | * Constructor 17 | * 18 | * @method StateMachine 19 | * @return 20 | */ 21 | function StateMachine() { 22 | puremvc.Mediator.call(this, StateMachine.NAME, null); 23 | this.states = {}; 24 | } 25 | 26 | StateMachine.prototype = new puremvc.Mediator; 27 | StateMachine.prototype.constructor = StateMachine; 28 | 29 | /** 30 | * Transitions to initial state once registered with Facade 31 | * @method onRegister 32 | * @return 33 | */ 34 | StateMachine.prototype.onRegister = function() { 35 | if(this.initial) this.transitionTo(this.initial, null); 36 | } 37 | 38 | /** 39 | * Registers the entry and exit commands for a given state. 40 | * @method registerState 41 | * @param {State} state the state to which to register the above commands 42 | * @param {boolean} initial boolean telling if this is the initial state of the system 43 | * @return 44 | */ 45 | StateMachine.prototype.registerState = function(state, initial) { 46 | if(state == null || this.states[state.name] != null) return; 47 | this.states[state.name] = state; 48 | if(initial) this.initial = state; 49 | } 50 | 51 | /** 52 | * Remove a state mapping. Removes the entry and exit commands for a given state as well as the state mapping itself. 53 | * @method removeState 54 | * @param {string} stateName 55 | * @return 56 | */ 57 | StateMachine.prototype.removeState = function(stateName) { 58 | var state = this.states[stateName]; 59 | if(state == null) return; 60 | this.states[stateName] = null; 61 | } 62 | 63 | /** 64 | * Transitions to the given state from the current state. 65 | *

66 | * Sends the exiting notification for the current state 67 | * followed by the entering notification for the new state. 68 | * Once finally transitioned to the new state, the changed 69 | * notification for the new state is sent.

70 | *

71 | * If a data parameter is provided, it is included as the body of all 72 | * three state-specific transition notes.

73 | *

74 | * Finally, when all the state-specific transition notes have been 75 | * sent, a StateMachine.CHANGED note is sent, with the 76 | * new State object as the body and the name of the 77 | * new state in the type. 78 | * 79 | * @method transitionTo 80 | * @param {State} nextState the next State to transition to. 81 | * @param {Object} data is the optional Object that was sent in the StateMachine.ACTION notification body 82 | * @return 83 | */ 84 | StateMachine.prototype.transitionTo = function(nextState, data) { 85 | // Going nowhere? 86 | if(nextState == null) return; 87 | 88 | // Clear the cancel flag 89 | this.canceled = false; 90 | 91 | // Exit the current State 92 | if(this.getCurrentState() && this.getCurrentState().exiting) 93 | this.sendNotification(this.getCurrentState().exiting, data, nextState.name); 94 | 95 | // Check to see whether the exiting guard has canceled the transition 96 | if(this.canceled) { 97 | this.canceled = false; 98 | return; 99 | } 100 | 101 | // Enter the next State 102 | if(nextState.entering) 103 | this.sendNotification(nextState.entering, data); 104 | 105 | // Check to see whether the entering guard has canceled the transition 106 | if(this.canceled) { 107 | this.canceled = false; 108 | return; 109 | } 110 | 111 | // change the current state only when both guards have been passed 112 | this.setCurrentState(nextState); 113 | 114 | // Send the notification configured to be sent when this specific state becomes current 115 | if(nextState.changed) { 116 | this.sendNotification(this.getCurrentState().changed, data); 117 | } 118 | 119 | // Notify the app generally that the state changed and what the new state is 120 | this.sendNotification(StateMachine.CHANGED, this.getCurrentState(), this.getCurrentState().name); 121 | } 122 | 123 | /** 124 | * Notification interests for the StateMachine. 125 | * @method listNotificationInterests 126 | * @return {Array} Array of Notifications 127 | */ 128 | StateMachine.prototype.listNotificationInterests = function() { 129 | return [ 130 | StateMachine.ACTION, 131 | StateMachine.CANCEL 132 | ]; 133 | } 134 | 135 | /** 136 | * Handle notifications the StateMachine is interested in. 137 | *

138 | * StateMachine.ACTION: Triggers the transition to a new state.
139 | * StateMachine.CANCEL: Cancels the transition if sent in response to the exiting note for the current state.
140 | * 141 | * @method handleNotification 142 | * @param {Notification} notification 143 | * @return 144 | */ 145 | StateMachine.prototype.handleNotification = function(notification) { 146 | switch(notification.getName()) { 147 | case StateMachine.ACTION: 148 | var action = notification.getType(); 149 | var target = this.getCurrentState().getTarget(action); 150 | var newState = this.states[target]; 151 | if(newState) this.transitionTo(newState, notification.getBody()); 152 | break; 153 | 154 | case StateMachine.CANCEL: 155 | this.canceled = true; 156 | break; 157 | } 158 | } 159 | 160 | /** 161 | * Get the current state. 162 | * @method getCurrentState 163 | * @return a State defining the machine's current state 164 | */ 165 | StateMachine.prototype.getCurrentState = function() { 166 | return this.viewComponent; 167 | } 168 | 169 | /** 170 | * Set the current state. 171 | * @method setCurrentState 172 | * @param {State} state 173 | * @return 174 | */ 175 | StateMachine.prototype.setCurrentState = function(state) { 176 | this.viewComponent = state; 177 | } 178 | 179 | /** 180 | * Map of States objects by name. 181 | */ 182 | StateMachine.prototype.states = null; 183 | 184 | /** 185 | * The initial state of the FSM. 186 | */ 187 | StateMachine.prototype.initial = null; 188 | 189 | /** 190 | * The transition has been canceled. 191 | */ 192 | StateMachine.prototype.canceled = null; 193 | 194 | StateMachine.NAME = "StateMachine"; 195 | 196 | /** 197 | * Action Notification name. 198 | */ 199 | StateMachine.ACTION = StateMachine.NAME + "/notes/action"; 200 | 201 | /** 202 | * Changed Notification name 203 | */ 204 | StateMachine.CHANGED = StateMachine.NAME + "/notes/changed"; 205 | 206 | /** 207 | * Cancel Notification name 208 | */ 209 | StateMachine.CANCEL = StateMachine.NAME + "/notes/cancel"; 210 | -------------------------------------------------------------------------------- /test/js/api/puremvc-1.0.1.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileOverview 3 | * PureMVC JS Native Port by David Foley, Frédéric Saunier, & Alain Duchesneau 4 | * Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved. 5 | * Reuse governed by Creative Commons Attribution 3.0 6 | * http://creativecommons.org/licenses/by/3.0/us/ 7 | * @author david.foley@puremvc.org 8 | * returns registered Proxy and Mediator on onRegister 9 | * added queryString (@object) to Facade 10 | */ 11 | 12 | (function(n){function i(a,d){this.setNotifyMethod(a);this.setNotifyContext(d)}function j(a,d,b){this.name=a;this.body=d;this.type=b}function k(){}function m(){}function l(){this.subCommands=[];this.initializeMacroCommand()}function g(a,d){this.mediatorName=a||this.constructor.NAME;this.viewComponent=d}function h(a,d){this.proxyName=a||this.constructor.NAME;null!=d&&this.setData(d)}function b(a){if(null!=b.instanceMap[a])throw Error(b.MULTITON_MSG);this.initializeNotifier(a);b.instanceMap[a]=this; 13 | this.initializeFacade(); 14 | this.url=null;this.queryString={};var query=window.location.search.substring(1);var vars=query.split("&");for(var i=0;i 96 | * Handles regisistration and removal of state definitions, 97 | * which include optional entry and exit commands for each 98 | * state.

99 | */ 100 | 101 | /** 102 | * Constructor 103 | * 104 | * @method StateMachine 105 | * @return 106 | */ 107 | function StateMachine() { 108 | puremvc.Mediator.call(this, StateMachine.NAME, null); 109 | this.states = {}; 110 | } 111 | 112 | StateMachine.prototype = new puremvc.Mediator; 113 | StateMachine.prototype.constructor = StateMachine; 114 | 115 | /** 116 | * Transitions to initial state once registered with Facade 117 | * @method onRegister 118 | * @return 119 | */ 120 | StateMachine.prototype.onRegister = function() { 121 | if(this.initial) this.transitionTo(this.initial, null); 122 | } 123 | 124 | /** 125 | * Registers the entry and exit commands for a given state. 126 | * @method registerState 127 | * @param {State} state the state to which to register the above commands 128 | * @param {boolean} initial boolean telling if this is the initial state of the system 129 | * @return 130 | */ 131 | StateMachine.prototype.registerState = function(state, initial) { 132 | if(state == null || this.states[state.name] != null) return; 133 | this.states[state.name] = state; 134 | if(initial) this.initial = state; 135 | } 136 | 137 | /** 138 | * Remove a state mapping. Removes the entry and exit commands for a given state as well as the state mapping itself. 139 | * @method removeState 140 | * @param {string} stateName 141 | * @return 142 | */ 143 | StateMachine.prototype.removeState = function(stateName) { 144 | var state = this.states[stateName]; 145 | if(state == null) return; 146 | this.states[stateName] = null; 147 | } 148 | 149 | /** 150 | * Transitions to the given state from the current state. 151 | *

152 | * Sends the exiting notification for the current state 153 | * followed by the entering notification for the new state. 154 | * Once finally transitioned to the new state, the changed 155 | * notification for the new state is sent.

156 | *

157 | * If a data parameter is provided, it is included as the body of all 158 | * three state-specific transition notes.

159 | *

160 | * Finally, when all the state-specific transition notes have been 161 | * sent, a StateMachine.CHANGED note is sent, with the 162 | * new State object as the body and the name of the 163 | * new state in the type. 164 | * 165 | * @method transitionTo 166 | * @param {State} nextState the next State to transition to. 167 | * @param {Object} data is the optional Object that was sent in the StateMachine.ACTION notification body 168 | * @return 169 | */ 170 | StateMachine.prototype.transitionTo = function(nextState, data) { 171 | // Going nowhere? 172 | if(nextState == null) return; 173 | 174 | // Clear the cancel flag 175 | this.canceled = false; 176 | 177 | // Exit the current State 178 | if(this.getCurrentState() && this.getCurrentState().exiting) 179 | this.sendNotification(this.getCurrentState().exiting, data, nextState.name); 180 | 181 | // Check to see whether the exiting guard has canceled the transition 182 | if(this.canceled) { 183 | this.canceled = false; 184 | return; 185 | } 186 | 187 | // Enter the next State 188 | if(nextState.entering) 189 | this.sendNotification(nextState.entering, data); 190 | 191 | // Check to see whether the entering guard has canceled the transition 192 | if(this.canceled) { 193 | this.canceled = false; 194 | return; 195 | } 196 | 197 | // change the current state only when both guards have been passed 198 | this.setCurrentState(nextState); 199 | 200 | // Send the notification configured to be sent when this specific state becomes current 201 | if(nextState.changed) { 202 | this.sendNotification(this.getCurrentState().changed, data); 203 | } 204 | 205 | // Notify the app generally that the state changed and what the new state is 206 | this.sendNotification(StateMachine.CHANGED, this.getCurrentState(), this.getCurrentState().name); 207 | } 208 | 209 | /** 210 | * Notification interests for the StateMachine. 211 | * @method listNotificationInterests 212 | * @return {Array} Array of Notifications 213 | */ 214 | 215 | StateMachine.prototype.listNotificationInterests = function() { 216 | return [ 217 | StateMachine.ACTION, 218 | StateMachine.CANCEL 219 | ]; 220 | } 221 | 222 | /** 223 | * Handle notifications the StateMachine is interested in. 224 | *

225 | * StateMachine.ACTION: Triggers the transition to a new state.
226 | * StateMachine.CANCEL: Cancels the transition if sent in response to the exiting note for the current state.
227 | * 228 | * @method handleNotification 229 | * @param {Notification} notification 230 | * @return 231 | */ 232 | StateMachine.prototype.handleNotification = function(notification) { 233 | switch(notification.getName()) { 234 | case StateMachine.ACTION: 235 | var action = notification.getType(); 236 | var target = this.getCurrentState().getTarget(action); 237 | var newState = this.states[target]; 238 | if(newState) this.transitionTo(newState, notification.getBody()); 239 | break; 240 | 241 | case StateMachine.CANCEL: 242 | this.canceled = true; 243 | break; 244 | } 245 | } 246 | 247 | /** 248 | * Get the current state. 249 | * @method getCurrentState 250 | * @return a State defining the machine's current state 251 | */ 252 | StateMachine.prototype.getCurrentState = function() { 253 | return this.viewComponent; 254 | } 255 | 256 | /** 257 | * Set the current state. 258 | * @method setCurrentState 259 | * @param {State} state 260 | * @return 261 | */ 262 | StateMachine.prototype.setCurrentState = function(state) { 263 | this.viewComponent = state; 264 | } 265 | 266 | /** 267 | * Map of States objects by name. 268 | */ 269 | StateMachine.prototype.states = null; 270 | 271 | /** 272 | * The initial state of the FSM. 273 | */ 274 | StateMachine.prototype.initial = null; 275 | 276 | /** 277 | * The transition has been canceled. 278 | */ 279 | StateMachine.prototype.canceled = null; 280 | 281 | StateMachine.NAME = "StateMachine"; 282 | 283 | /** 284 | * Action Notification name. 285 | */ 286 | StateMachine.ACTION = StateMachine.NAME + "/notes/action"; 287 | 288 | /** 289 | * Changed Notification name 290 | */ 291 | StateMachine.CHANGED = StateMachine.NAME + "/notes/changed"; 292 | 293 | /** 294 | * Cancel Notification name 295 | */ 296 | StateMachine.CANCEL = StateMachine.NAME + "/notes/cancel"; 297 | 298 | 299 | /** 300 | * Creates and registers a StateMachine described in JSON. 301 | * 302 | *

303 | * This allows reconfiguration of the StateMachine 304 | * without changing any code, as well as making it 305 | * easier than creating all the State 306 | * instances and registering them with the 307 | * StateMachine at startup time. 308 | * 309 | * @ see State 310 | * @ see StateMachine 311 | */ 312 | 313 | /** 314 | * Constructor 315 | * @method FSMInjector 316 | * @param {Object} fsm JSON Object 317 | * @return 318 | */ 319 | function FSMInjector(fsm) { 320 | puremvc.Notifier.call(this); 321 | this.fsm = fsm; 322 | } 323 | 324 | FSMInjector.prototype = new puremvc.Notifier; 325 | FSMInjector.prototype.constructor = FSMInjector; 326 | 327 | /** 328 | * Inject the StateMachine into the PureMVC apparatus. 329 | *

330 | * Creates the StateMachine instance, registers all the states 331 | * and registers the StateMachine with the IFacade. 332 | * @method inject 333 | * @return 334 | */ 335 | FSMInjector.prototype.inject = function() { 336 | // Create the StateMachine 337 | var stateMachine = new puremvc.statemachine.StateMachine(); 338 | 339 | // Register all the states with the StateMachine 340 | var states = this.getStates(); 341 | for(var i=0; i 352 | * Creates and returns the array of State objects 353 | * from the FSM on first call, subsequently returns 354 | * the existing array.

355 | * 356 | * @method getStates 357 | * @return {Array} Array of States 358 | */ 359 | FSMInjector.prototype.getStates = function() { 360 | if(this.stateList == null) { 361 | this.stateList = []; 362 | 363 | var stateDefs = this.fsm.state ? this.fsm.state : []; 364 | for(var i=0; iState instance from its JSON definition. 375 | * @method createState 376 | * @param {Object} stateDef JSON Object 377 | * @return {State} 378 | */ 379 | /** 380 | 381 | */ 382 | FSMInjector.prototype.createState = function(stateDef) { 383 | // Create State object 384 | var name = stateDef['@name']; 385 | var exiting = stateDef['@exiting']; 386 | var entering = stateDef['@entering']; 387 | var changed = stateDef['@changed']; 388 | var state = new puremvc.statemachine.State(name, entering, exiting, changed); 389 | 390 | // Create transitions 391 | var transitions = stateDef.transition ? stateDef.transition : []; 392 | for(var i=0; i