state
Version:
First-class states
291 lines (266 loc) • 10.4 kB
JavaScript
// Generated by CoffeeScript 1.6.3
(function() {
var O, RootState, State, StateExpression, Transition, TransitionExpression, state,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
__slice = [].slice;
O = require('omicron');
state = require('./state-function');
State = require('./state');
StateExpression = null;
Transition = null;
TransitionExpression = null;
module.exports = RootState = (function(_super) {
var ABSTRACT, CONCLUSIVE, FINAL, VIA_NONE, VIA_PROTO, VIRTUAL, createAccessor, env, evaluateGuard, hasOwn, isArray, isEmpty, rxTransitionArrow, slice, transitionArrowMethods, trim, type;
__extends(RootState, _super);
rxTransitionArrow = state.rxTransitionArrow, transitionArrowMethods = state.transitionArrowMethods;
env = O.env, hasOwn = O.hasOwn, trim = O.trim, type = O.type, isEmpty = O.isEmpty, isArray = O.isArray;
slice = Array.prototype.slice;
VIRTUAL = RootState.VIRTUAL, ABSTRACT = RootState.ABSTRACT, CONCLUSIVE = RootState.CONCLUSIVE, FINAL = RootState.FINAL;
VIA_NONE = RootState.VIA_NONE, VIA_PROTO = RootState.VIA_PROTO;
function RootState(owner, expression, accessorName, initialState) {
var current, _ref, _ref1;
if (owner == null) {
owner = {};
}
this.accessorName = accessorName != null ? accessorName : accessorName = 'state';
owner[accessorName] = createAccessor(owner, accessorName, this);
RootState.__super__.constructor.call(this, owner, '', expression);
current = (_ref = (initialState != null ? this.query(initialState) : this.initialSubstate())) != null ? _ref : this;
if (current.attributes & ABSTRACT) {
current = (_ref1 = current.defaultSubstate()) != null ? _ref1 : current;
}
if (current.root !== this) {
current = current.virtualize(this);
}
this._current = current;
this._transition = null;
}
createAccessor = function(owner, name, root) {
var accessor;
accessor = function() {
var args, current, input, match, method;
input = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
current = root._current || root;
if (this === owner) {
if (input == null) {
return current;
}
if (typeof input === 'function') {
return current.change(input.call(this));
}
if (typeof input === 'string' && (match = input.match(rxTransitionArrow)) && (method = transitionArrowMethods[match[1]])) {
if (args.length) {
return current[method].apply(current, [match[2]].concat(args));
} else {
return current[method](match[2]);
}
}
return current.query.apply(current, arguments);
} else if ((owner.isPrototypeOf(this)) && ((!hasOwn.call(this, name)) || this[name] === owner[name])) {
new RootState(this, null, name, current.path());
return this[name].apply(this, arguments);
}
};
accessor.isAccessor = true;
if (env.debug) {
accessor.toString = function() {
return "[accessor] -> " + (root._current.path());
};
}
return accessor;
};
evaluateGuard = function(context, guard, against) {
var args, key, result, selector, selectors, value, valueIsFn, _i, _len;
if (typeof guard === 'string') {
guard = context.guard(guard);
}
if (!guard) {
return true;
}
args = slice.call(arguments, 1);
for (key in guard) {
if (!__hasProp.call(guard, key)) continue;
value = guard[key];
valueIsFn = typeof value === 'function';
selectors = trim(key).split(/\s*,+\s*/);
for (_i = 0, _len = selectors.length; _i < _len; _i++) {
selector = selectors[_i];
if (!(context.query(selector, against))) {
continue;
}
result = valueIsFn ? value.apply(context, args) : value;
break;
}
if (!result) {
break;
}
}
return !!result;
};
RootState.prototype.getTransitionExpression = (function() {
var search;
search = function(target, origin, subject, ceiling) {
var admit, expr, guards, key, release, _ref;
while (subject && subject !== ceiling) {
_ref = subject.transitions();
for (key in _ref) {
if (!__hasProp.call(_ref, key)) continue;
expr = _ref[key];
if ((!(guards = expr.guards) || (!(admit = guards.admit) || isEmpty(admit) || evaluateGuard.call(origin, admit, target, origin)) && (!(release = guards.release) || isEmpty(release) || evaluateGuard.call(target, release, origin, target))) && (expr.target ? subject.query(expr.target, target) : subject === target) && (!expr.origin || subject.query(expr.origin, origin))) {
return expr;
}
}
if (ceiling == null) {
break;
}
subject = subject.superstate;
}
};
return function(target, origin) {
if (origin == null) {
origin = this._current;
}
return (search(target, origin, target)) || (origin !== target ? search(target, origin, origin) : void 0) || (search(target, origin, target.superstate, this.root)) || (search(target, origin, this.root)) || (!target.isIn(origin) ? search(target, origin, origin.superstate, origin.common(target)) : void 0) || new TransitionExpression;
};
})();
RootState.prototype.change = function(target, options) {
var admitted, args, current, domain, eventArgs, origin, owner, released, root, s, source, targetOwner, transition, _ref;
root = this.root, owner = this.owner;
current = this._current;
transition = this._transition;
origin = (transition != null ? transition.origin : void 0) || current;
if (origin.attributes & FINAL) {
return null;
}
if (!(target instanceof State)) {
target = target ? origin.query(target) : root;
}
if (!target) {
return null;
}
targetOwner = target.owner;
if (owner !== targetOwner && !targetOwner.isPrototypeOf(owner)) {
return null;
}
if (options != null) {
args = (isArray(options)) || (type(options)) === 'arguments' ? options : options.args;
if (args != null) {
args = slice.call(args);
}
}
while (target.attributes & ABSTRACT) {
if (!(target = target.defaultSubstate())) {
return null;
}
}
if (!(options != null ? options.forced : void 0)) {
released = evaluateGuard(origin, 'release', target);
admitted = evaluateGuard(target, 'admit', origin);
if (!(released && admitted)) {
if (options != null) {
if ((_ref = options.failure) != null) {
if (typeof _ref.call === "function") {
_ref.call(this);
}
}
}
return null;
}
}
if ((target != null ? target.root : void 0) !== root) {
target = target.virtualize(this);
}
source = current;
domain = source.common(target);
s = source;
while (s !== domain) {
if (s.attributes & CONCLUSIVE) {
return null;
}
s = s.superstate;
}
if (transition != null) {
transition.abort();
}
this._transition = transition = new Transition(target, source, this.getTransitionExpression(target, origin));
eventArgs = [transition, args];
source.emit('depart', eventArgs, VIA_PROTO);
if (transition.aborted) {
this._transition = transition = null;
}
if (transition) {
this._current = transition;
transition.emit('enter', VIA_NONE);
if (transition.aborted) {
this._transition = transition = null;
}
}
s = source;
while (transition && s !== domain) {
s.emit('exit', eventArgs, VIA_PROTO);
transition.superstate = s = s.superstate;
if (transition.aborted) {
this._transition = transition = null;
}
}
if (transition != null) {
transition.callback = function() {
var pathToState, ss, substate, _ref1;
if (transition.aborted) {
transition = null;
}
if (transition) {
s = target;
pathToState = [];
while (s !== domain) {
pathToState.push(s);
s = s.superstate;
}
}
s = domain;
while (transition && (substate = pathToState.pop())) {
transition.superstate = substate;
substate.emit('enter', eventArgs, VIA_PROTO);
if (transition.aborted) {
transition = null;
}
s = substate;
}
if (transition) {
transition.emit('exit', VIA_NONE);
if (transition.aborted) {
transition = null;
}
}
if (transition) {
this._current = target;
target.emit('arrive', eventArgs, VIA_PROTO);
s = origin;
while (s.attributes & VIRTUAL) {
ss = s.superstate;
s.destroy();
s = ss;
}
transition.destroy();
this._transition = transition = null;
if (options != null) {
if ((_ref1 = options.success) != null) {
if (typeof _ref1.call === "function") {
_ref1.call(this);
}
}
}
return target;
}
return null;
};
}
return (transition != null ? transition.start.apply(transition, args) : void 0) || this._current;
};
return RootState;
})(State);
StateExpression = require('./state-expression');
Transition = require('./transition');
TransitionExpression = require('./transition-expression');
}).call(this);