123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669 |
- (function webpackUniversalModuleDefinition(root, factory) {
- if(typeof exports === 'object' && typeof module === 'object')
- module.exports = factory();
- else if(typeof define === 'function' && define.amd)
- define("StateMachine", [], factory);
- else if(typeof exports === 'object')
- exports["StateMachine"] = factory();
- else
- root["StateMachine"] = factory();
- })(this, function() {
- return /******/ (function(modules) { // webpackBootstrap
- /******/ // The module cache
- /******/ var installedModules = {};
- /******/
- /******/ // The require function
- /******/ function __webpack_require__(moduleId) {
- /******/
- /******/ // Check if module is in cache
- /******/ if(installedModules[moduleId]) {
- /******/ return installedModules[moduleId].exports;
- /******/ }
- /******/ // Create a new module (and put it into the cache)
- /******/ var module = installedModules[moduleId] = {
- /******/ i: moduleId,
- /******/ l: false,
- /******/ exports: {}
- /******/ };
- /******/
- /******/ // Execute the module function
- /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
- /******/
- /******/ // Flag the module as loaded
- /******/ module.l = true;
- /******/
- /******/ // Return the exports of the module
- /******/ return module.exports;
- /******/ }
- /******/
- /******/
- /******/ // expose the modules object (__webpack_modules__)
- /******/ __webpack_require__.m = modules;
- /******/
- /******/ // expose the module cache
- /******/ __webpack_require__.c = installedModules;
- /******/
- /******/ // identity function for calling harmony imports with the correct context
- /******/ __webpack_require__.i = function(value) { return value; };
- /******/
- /******/ // define getter function for harmony exports
- /******/ __webpack_require__.d = function(exports, name, getter) {
- /******/ if(!__webpack_require__.o(exports, name)) {
- /******/ Object.defineProperty(exports, name, {
- /******/ configurable: false,
- /******/ enumerable: true,
- /******/ get: getter
- /******/ });
- /******/ }
- /******/ };
- /******/
- /******/ // getDefaultExport function for compatibility with non-harmony modules
- /******/ __webpack_require__.n = function(module) {
- /******/ var getter = module && module.__esModule ?
- /******/ function getDefault() { return module['default']; } :
- /******/ function getModuleExports() { return module; };
- /******/ __webpack_require__.d(getter, 'a', getter);
- /******/ return getter;
- /******/ };
- /******/
- /******/ // Object.prototype.hasOwnProperty.call
- /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
- /******/
- /******/ // __webpack_public_path__
- /******/ __webpack_require__.p = "";
- /******/
- /******/ // Load entry module and return exports
- /******/ return __webpack_require__(__webpack_require__.s = 5);
- /******/ })
- /************************************************************************/
- /******/ ([
- /* 0 */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- module.exports = function(target, sources) {
- var n, source, key;
- for(n = 1 ; n < arguments.length ; n++) {
- source = arguments[n];
- for(key in source) {
- if (source.hasOwnProperty(key))
- target[key] = source[key];
- }
- }
- return target;
- }
- /***/ }),
- /* 1 */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- //-------------------------------------------------------------------------------------------------
- var mixin = __webpack_require__(0);
- //-------------------------------------------------------------------------------------------------
- module.exports = {
- build: function(target, config) {
- var n, max, plugin, plugins = config.plugins;
- for(n = 0, max = plugins.length ; n < max ; n++) {
- plugin = plugins[n];
- if (plugin.methods)
- mixin(target, plugin.methods);
- if (plugin.properties)
- Object.defineProperties(target, plugin.properties);
- }
- },
- hook: function(fsm, name, additional) {
- var n, max, method, plugin,
- plugins = fsm.config.plugins,
- args = [fsm.context];
- if (additional)
- args = args.concat(additional)
- for(n = 0, max = plugins.length ; n < max ; n++) {
- plugin = plugins[n]
- method = plugins[n][name]
- if (method)
- method.apply(plugin, args);
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- /***/ }),
- /* 2 */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- //-------------------------------------------------------------------------------------------------
- function camelize(label) {
- if (label.length === 0)
- return label;
- var n, result, word, words = label.split(/[_-]/);
- // single word with first character already lowercase, return untouched
- if ((words.length === 1) && (words[0][0].toLowerCase() === words[0][0]))
- return label;
- result = words[0].toLowerCase();
- for(n = 1 ; n < words.length ; n++) {
- result = result + words[n].charAt(0).toUpperCase() + words[n].substring(1).toLowerCase();
- }
- return result;
- }
- //-------------------------------------------------------------------------------------------------
- camelize.prepended = function(prepend, label) {
- label = camelize(label);
- return prepend + label[0].toUpperCase() + label.substring(1);
- }
- //-------------------------------------------------------------------------------------------------
- module.exports = camelize;
- /***/ }),
- /* 3 */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- //-------------------------------------------------------------------------------------------------
- var mixin = __webpack_require__(0),
- camelize = __webpack_require__(2);
- //-------------------------------------------------------------------------------------------------
- function Config(options, StateMachine) {
- options = options || {};
- this.options = options; // preserving original options can be useful (e.g visualize plugin)
- this.defaults = StateMachine.defaults;
- this.states = [];
- this.transitions = [];
- this.map = {};
- this.lifecycle = this.configureLifecycle();
- this.init = this.configureInitTransition(options.init);
- this.data = this.configureData(options.data);
- this.methods = this.configureMethods(options.methods);
- this.map[this.defaults.wildcard] = {};
- this.configureTransitions(options.transitions || []);
- this.plugins = this.configurePlugins(options.plugins, StateMachine.plugin);
- }
- //-------------------------------------------------------------------------------------------------
- mixin(Config.prototype, {
- addState: function(name) {
- if (!this.map[name]) {
- this.states.push(name);
- this.addStateLifecycleNames(name);
- this.map[name] = {};
- }
- },
- addStateLifecycleNames: function(name) {
- this.lifecycle.onEnter[name] = camelize.prepended('onEnter', name);
- this.lifecycle.onLeave[name] = camelize.prepended('onLeave', name);
- this.lifecycle.on[name] = camelize.prepended('on', name);
- },
- addTransition: function(name) {
- if (this.transitions.indexOf(name) < 0) {
- this.transitions.push(name);
- this.addTransitionLifecycleNames(name);
- }
- },
- addTransitionLifecycleNames: function(name) {
- this.lifecycle.onBefore[name] = camelize.prepended('onBefore', name);
- this.lifecycle.onAfter[name] = camelize.prepended('onAfter', name);
- this.lifecycle.on[name] = camelize.prepended('on', name);
- },
- mapTransition: function(transition) {
- var name = transition.name,
- from = transition.from,
- to = transition.to;
- this.addState(from);
- if (typeof to !== 'function')
- this.addState(to);
- this.addTransition(name);
- this.map[from][name] = transition;
- return transition;
- },
- configureLifecycle: function() {
- return {
- onBefore: { transition: 'onBeforeTransition' },
- onAfter: { transition: 'onAfterTransition' },
- onEnter: { state: 'onEnterState' },
- onLeave: { state: 'onLeaveState' },
- on: { transition: 'onTransition' }
- };
- },
- configureInitTransition: function(init) {
- if (typeof init === 'string') {
- return this.mapTransition(mixin({}, this.defaults.init, { to: init, active: true }));
- }
- else if (typeof init === 'object') {
- return this.mapTransition(mixin({}, this.defaults.init, init, { active: true }));
- }
- else {
- this.addState(this.defaults.init.from);
- return this.defaults.init;
- }
- },
- configureData: function(data) {
- if (typeof data === 'function')
- return data;
- else if (typeof data === 'object')
- return function() { return data; }
- else
- return function() { return {}; }
- },
- configureMethods: function(methods) {
- return methods || {};
- },
- configurePlugins: function(plugins, builtin) {
- plugins = plugins || [];
- var n, max, plugin;
- for(n = 0, max = plugins.length ; n < max ; n++) {
- plugin = plugins[n];
- if (typeof plugin === 'function')
- plugins[n] = plugin = plugin()
- if (plugin.configure)
- plugin.configure(this);
- }
- return plugins
- },
- configureTransitions: function(transitions) {
- var i, n, transition, from, to, wildcard = this.defaults.wildcard;
- for(n = 0 ; n < transitions.length ; n++) {
- transition = transitions[n];
- from = Array.isArray(transition.from) ? transition.from : [transition.from || wildcard]
- to = transition.to || wildcard;
- for(i = 0 ; i < from.length ; i++) {
- this.mapTransition({ name: transition.name, from: from[i], to: to });
- }
- }
- },
- transitionFor: function(state, transition) {
- var wildcard = this.defaults.wildcard;
- return this.map[state][transition] ||
- this.map[wildcard][transition];
- },
- transitionsFor: function(state) {
- var wildcard = this.defaults.wildcard;
- return Object.keys(this.map[state]).concat(Object.keys(this.map[wildcard]));
- },
- allStates: function() {
- return this.states;
- },
- allTransitions: function() {
- return this.transitions;
- }
- });
- //-------------------------------------------------------------------------------------------------
- module.exports = Config;
- //-------------------------------------------------------------------------------------------------
- /***/ }),
- /* 4 */
- /***/ (function(module, exports, __webpack_require__) {
- var mixin = __webpack_require__(0),
- Exception = __webpack_require__(6),
- plugin = __webpack_require__(1),
- UNOBSERVED = [ null, [] ];
- //-------------------------------------------------------------------------------------------------
- function JSM(context, config) {
- this.context = context;
- this.config = config;
- this.state = config.init.from;
- this.observers = [context];
- }
- //-------------------------------------------------------------------------------------------------
- mixin(JSM.prototype, {
- init: function(args) {
- mixin(this.context, this.config.data.apply(this.context, args));
- plugin.hook(this, 'init');
- if (this.config.init.active)
- return this.fire(this.config.init.name, []);
- },
- is: function(state) {
- return Array.isArray(state) ? (state.indexOf(this.state) >= 0) : (this.state === state);
- },
- isPending: function() {
- return this.pending;
- },
- can: function(transition) {
- return !this.isPending() && !!this.seek(transition);
- },
- cannot: function(transition) {
- return !this.can(transition);
- },
- allStates: function() {
- return this.config.allStates();
- },
- allTransitions: function() {
- return this.config.allTransitions();
- },
- transitions: function() {
- return this.config.transitionsFor(this.state);
- },
- seek: function(transition, args) {
- var wildcard = this.config.defaults.wildcard,
- entry = this.config.transitionFor(this.state, transition),
- to = entry && entry.to;
- if (typeof to === 'function')
- return to.apply(this.context, args);
- else if (to === wildcard)
- return this.state
- else
- return to
- },
- fire: function(transition, args) {
- return this.transit(transition, this.state, this.seek(transition, args), args);
- },
- transit: function(transition, from, to, args) {
- var lifecycle = this.config.lifecycle,
- changed = this.config.options.observeUnchangedState || (from !== to);
- if (!to)
- return this.context.onInvalidTransition(transition, from, to);
- if (this.isPending())
- return this.context.onPendingTransition(transition, from, to);
- this.config.addState(to); // might need to add this state if it's unknown (e.g. conditional transition or goto)
- this.beginTransit();
- args.unshift({ // this context will be passed to each lifecycle event observer
- transition: transition,
- from: from,
- to: to,
- fsm: this.context
- });
- return this.observeEvents([
- this.observersForEvent(lifecycle.onBefore.transition),
- this.observersForEvent(lifecycle.onBefore[transition]),
- changed ? this.observersForEvent(lifecycle.onLeave.state) : UNOBSERVED,
- changed ? this.observersForEvent(lifecycle.onLeave[from]) : UNOBSERVED,
- this.observersForEvent(lifecycle.on.transition),
- changed ? [ 'doTransit', [ this ] ] : UNOBSERVED,
- changed ? this.observersForEvent(lifecycle.onEnter.state) : UNOBSERVED,
- changed ? this.observersForEvent(lifecycle.onEnter[to]) : UNOBSERVED,
- changed ? this.observersForEvent(lifecycle.on[to]) : UNOBSERVED,
- this.observersForEvent(lifecycle.onAfter.transition),
- this.observersForEvent(lifecycle.onAfter[transition]),
- this.observersForEvent(lifecycle.on[transition])
- ], args);
- },
- beginTransit: function() { this.pending = true; },
- endTransit: function(result) { this.pending = false; return result; },
- failTransit: function(result) { this.pending = false; throw result; },
- doTransit: function(lifecycle) { this.state = lifecycle.to; },
- observe: function(args) {
- if (args.length === 2) {
- var observer = {};
- observer[args[0]] = args[1];
- this.observers.push(observer);
- }
- else {
- this.observers.push(args[0]);
- }
- },
- observersForEvent: function(event) { // TODO: this could be cached
- var n = 0, max = this.observers.length, observer, result = [];
- for( ; n < max ; n++) {
- observer = this.observers[n];
- if (observer[event])
- result.push(observer);
- }
- return [ event, result, true ]
- },
- observeEvents: function(events, args, previousEvent, previousResult) {
- if (events.length === 0) {
- return this.endTransit(previousResult === undefined ? true : previousResult);
- }
- var event = events[0][0],
- observers = events[0][1],
- pluggable = events[0][2];
- args[0].event = event;
- if (event && pluggable && event !== previousEvent)
- plugin.hook(this, 'lifecycle', args);
- if (observers.length === 0) {
- events.shift();
- return this.observeEvents(events, args, event, previousResult);
- }
- else {
- var observer = observers.shift(),
- result = observer[event].apply(observer, args);
- if (result && typeof result.then === 'function') {
- return result.then(this.observeEvents.bind(this, events, args, event))
- .catch(this.failTransit.bind(this))
- }
- else if (result === false) {
- return this.endTransit(false);
- }
- else {
- return this.observeEvents(events, args, event, result);
- }
- }
- },
- onInvalidTransition: function(transition, from, to) {
- throw new Exception("transition is invalid in current state", transition, from, to, this.state);
- },
- onPendingTransition: function(transition, from, to) {
- throw new Exception("transition is invalid while previous transition is still in progress", transition, from, to, this.state);
- }
- });
- //-------------------------------------------------------------------------------------------------
- module.exports = JSM;
- //-------------------------------------------------------------------------------------------------
- /***/ }),
- /* 5 */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- //-----------------------------------------------------------------------------------------------
- var mixin = __webpack_require__(0),
- camelize = __webpack_require__(2),
- plugin = __webpack_require__(1),
- Config = __webpack_require__(3),
- JSM = __webpack_require__(4);
- //-----------------------------------------------------------------------------------------------
- var PublicMethods = {
- is: function(state) { return this._fsm.is(state) },
- can: function(transition) { return this._fsm.can(transition) },
- cannot: function(transition) { return this._fsm.cannot(transition) },
- observe: function() { return this._fsm.observe(arguments) },
- transitions: function() { return this._fsm.transitions() },
- allTransitions: function() { return this._fsm.allTransitions() },
- allStates: function() { return this._fsm.allStates() },
- onInvalidTransition: function(t, from, to) { return this._fsm.onInvalidTransition(t, from, to) },
- onPendingTransition: function(t, from, to) { return this._fsm.onPendingTransition(t, from, to) },
- }
- var PublicProperties = {
- state: {
- configurable: false,
- enumerable: true,
- get: function() {
- return this._fsm.state;
- },
- set: function(state) {
- throw Error('use transitions to change state')
- }
- }
- }
- //-----------------------------------------------------------------------------------------------
- function StateMachine(options) {
- return apply(this || {}, options);
- }
- function factory() {
- var cstor, options;
- if (typeof arguments[0] === 'function') {
- cstor = arguments[0];
- options = arguments[1] || {};
- }
- else {
- cstor = function() { this._fsm.apply(this, arguments) };
- options = arguments[0] || {};
- }
- var config = new Config(options, StateMachine);
- build(cstor.prototype, config);
- cstor.prototype._fsm.config = config; // convenience access to shared config without needing an instance
- return cstor;
- }
- //-------------------------------------------------------------------------------------------------
- function apply(instance, options) {
- var config = new Config(options, StateMachine);
- build(instance, config);
- instance._fsm();
- return instance;
- }
- function build(target, config) {
- if ((typeof target !== 'object') || Array.isArray(target))
- throw Error('StateMachine can only be applied to objects');
- plugin.build(target, config);
- Object.defineProperties(target, PublicProperties);
- mixin(target, PublicMethods);
- mixin(target, config.methods);
- config.allTransitions().forEach(function(transition) {
- target[camelize(transition)] = function() {
- return this._fsm.fire(transition, [].slice.call(arguments))
- }
- });
- target._fsm = function() {
- this._fsm = new JSM(this, config);
- this._fsm.init(arguments);
- }
- }
- //-----------------------------------------------------------------------------------------------
- StateMachine.version = '3.0.1';
- StateMachine.factory = factory;
- StateMachine.apply = apply;
- StateMachine.defaults = {
- wildcard: '*',
- init: {
- name: 'init',
- from: 'none'
- }
- }
- //===============================================================================================
- module.exports = StateMachine;
- /***/ }),
- /* 6 */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- module.exports = function(message, transition, from, to, current) {
- this.message = message;
- this.transition = transition;
- this.from = from;
- this.to = to;
- this.current = current;
- }
- /***/ })
- /******/ ]);
- });
|