// ========================================================================== // Project: SC
.Statechart - A Statechart Framework for SproutCore
// Copyright: ©2010, 2011 Michael Cohen, and contributors. // Portions @2011 Apple Inc. All rights reserved. // License: Licensed under MIT license (see license.js) // ==========================================================================
/*globals SC
*/
/**
Extends the JS Function object with the handleEvents method that will provide more advanced event handling capabilities when constructing your statechart's states. By default, when you add a method to a state, the state will react to events that matches a method's name, like so: {{{ state = SC.State.extend({ // Will be invoked when a event named "foo" is sent to this state foo: function(event, sender, context) { ... } }) }}} In some situations, it may be advantageous to use one method that can react to multiple events instead of having multiple methods that essentially all do the same thing. In order to set a method to handle more than one event you use the handleEvents method which can be supplied a list of string and/or regular expressions. The following example demonstrates the use of handleEvents: {{{ state = SC.State.extend({ eventHandlerA: function(event, sender, context) { }.handleEvents('foo', 'bar'), eventHandlerB: function(event, sender, context) { }.handleEvents(/num\d/, 'decimal') }) }}} Whenever events 'foo' and 'bar' are sent to the state, the method eventHandlerA will be invoked. When there is an event that matches the regular expression /num\d/ or the event is 'decimal' then eventHandlerB is invoked. In both cases, the name of the event will be supplied to the event handler. It should be noted that the use of regular expressions may impact performance since that statechart will not be able to fully optimize the event handling logic based on its use. Therefore the use of regular expression should be used sparingly. @param {(String|RegExp)...} args
*/ Function.prototype.handleEvents = function() {
this.isEventHandler = YES; this.events = arguments; return this;
};
/**
Extends the JS Function object with the stateObserves method that will create a state observe handler on a given state object. Use a stateObserves() instead of the common observes() method when you want a state to observer changes to some property on the state itself or some other object. Any method on the state that has stateObserves is considered a state observe handler and behaves just like when you use observes() on a method, but with an important difference. When you apply stateObserves to a method on a state, those methods will be active *only* when the state is entered, otherwise those methods will be inactive. This removes the need for you having to explicitly call addObserver and removeObserver. As an example: {{{ state = SC.State.extend({ foo: null, user: null, observeHandlerA: function(target, key) { }.stateObserves('MyApp.someController.status'), observeHandlerB: function(target, key) { }.stateObserves('foo'), observeHandlerC: function(target, key) { }.stateObserves('.user.name', '.user.salary') }) }}} Above, state has three state observe handlers: observeHandlerA, observeHandlerB, and observeHandlerC. When state is entered, the state will automatically add itself as an observer for all of its registered state observe handlers. Therefore when foo changes, observeHandlerB will be invoked, and when MyApp.someController's status changes then observeHandlerA will be invoked. The moment that state is exited then the state will automatically remove itself as an observer for all of its registered state observe handlers. Therefore none of the state observe handlers will be invoked until the next time the state is entered. @param {String...} args
*/ Function.prototype.stateObserves = function() {
this.isStateObserveHandler = YES; // Fast arguments access. // Accessing `arguments.length` is just a Number and doesn't materialize the `arguments` object, which is costly. this.args = new Array(arguments.length); // SC.A(arguments) for (var i = 0, len = this.args.length; i < len; i++) { this.args[i] = arguments[i]; } return this;
};