1 // ========================================================================== 2 // Project: SC.Statechart - A Statechart Framework for SproutCore 3 // Copyright: ©2010, 2011 Michael Cohen, and contributors. 4 // Portions @2011 Apple Inc. All rights reserved. 5 // License: Licensed under MIT license (see license.js) 6 // ========================================================================== 7 8 /*globals SC */ 9 10 /** 11 Extends the JS Function object with the handleEvents method that 12 will provide more advanced event handling capabilities when constructing 13 your statechart's states. 14 15 By default, when you add a method to a state, the state will react to 16 events that matches a method's name, like so: 17 18 {{{ 19 20 state = SC.State.extend({ 21 22 // Will be invoked when a event named "foo" is sent to this state 23 foo: function(event, sender, context) { ... } 24 25 }) 26 27 }}} 28 29 In some situations, it may be advantageous to use one method that can react to 30 multiple events instead of having multiple methods that essentially all do the 31 same thing. In order to set a method to handle more than one event you use 32 the handleEvents method which can be supplied a list of string and/or regular 33 expressions. The following example demonstrates the use of handleEvents: 34 35 {{{ 36 37 state = SC.State.extend({ 38 39 eventHandlerA: function(event, sender, context) { 40 41 }.handleEvents('foo', 'bar'), 42 43 eventHandlerB: function(event, sender, context) { 44 45 }.handleEvents(/num\d/, 'decimal') 46 47 }) 48 49 }}} 50 51 Whenever events 'foo' and 'bar' are sent to the state, the method eventHandlerA 52 will be invoked. When there is an event that matches the regular expression 53 /num\d/ or the event is 'decimal' then eventHandlerB is invoked. In both 54 cases, the name of the event will be supplied to the event handler. 55 56 It should be noted that the use of regular expressions may impact performance 57 since that statechart will not be able to fully optimize the event handling logic based 58 on its use. Therefore the use of regular expression should be used sparingly. 59 60 @param {(String|RegExp)...} args 61 */ 62 Function.prototype.handleEvents = function() { 63 this.isEventHandler = YES; 64 this.events = arguments; 65 return this; 66 }; 67 68 /** 69 Extends the JS Function object with the stateObserves method that will 70 create a state observe handler on a given state object. 71 72 Use a stateObserves() instead of the common observes() method when you want a 73 state to observer changes to some property on the state itself or some other 74 object. 75 76 Any method on the state that has stateObserves is considered a state observe 77 handler and behaves just like when you use observes() on a method, but with an 78 important difference. When you apply stateObserves to a method on a state, those 79 methods will be active *only* when the state is entered, otherwise those methods 80 will be inactive. This removes the need for you having to explicitly call 81 addObserver and removeObserver. As an example: 82 83 {{{ 84 85 state = SC.State.extend({ 86 87 foo: null, 88 89 user: null, 90 91 observeHandlerA: function(target, key) { 92 93 }.stateObserves('MyApp.someController.status'), 94 95 observeHandlerB: function(target, key) { 96 97 }.stateObserves('foo'), 98 99 observeHandlerC: function(target, key) { 100 101 }.stateObserves('.user.name', '.user.salary') 102 103 }) 104 105 }}} 106 107 Above, state has three state observe handlers: observeHandlerA, observeHandlerB, and 108 observeHandlerC. When state is entered, the state will automatically add itself as 109 an observer for all of its registered state observe handlers. Therefore when 110 foo changes, observeHandlerB will be invoked, and when MyApp.someController's status 111 changes then observeHandlerA will be invoked. The moment that state is exited then 112 the state will automatically remove itself as an observer for all of its registered 113 state observe handlers. Therefore none of the state observe handlers will be 114 invoked until the next time the state is entered. 115 116 @param {String...} args 117 */ 118 Function.prototype.stateObserves = function() { 119 this.isStateObserveHandler = YES; 120 121 // Fast arguments access. 122 // Accessing `arguments.length` is just a Number and doesn't materialize the `arguments` object, which is costly. 123 this.args = new Array(arguments.length); // SC.A(arguments) 124 for (var i = 0, len = this.args.length; i < len; i++) { this.args[i] = arguments[i]; } 125 126 return this; 127 }; 128