1 // ==========================================================================
  2 // Project:   SproutCore - JavaScript Application Framework
  3 // Copyright: ©2006-2011 Strobe Inc. and contributors.
  4 //            Portions ©2008-2011 Apple Inc. All rights reserved.
  5 // License:   Licensed under MIT license (see license.js)
  6 // ==========================================================================
  7 
  8 /**
  9   @namespace
 10 
 11   Support methods for the Delegate design pattern.
 12 
 13   The Delegate design pattern makes it easy to delegate a portion of your
 14   application logic to another object.  This is most often used in views to
 15   delegate various application-logic decisions to controllers in order to
 16   avoid having to bake application-logic directly into the view itself.
 17 
 18   The methods provided by this mixin make it easier to implement this pattern
 19   but they are not required to support delegates.
 20 
 21   ## The Pattern
 22 
 23   The delegate design pattern typically means that you provide a property,
 24   usually ending in "delegate", that can be set to another object in the
 25   system.
 26 
 27   When events occur or logic decisions need to be made that you would prefer
 28   to delegate, you can call methods on the delegate if it is set.  If the
 29   delegate is not set, you should provide some default functionality instead.
 30 
 31   Note that typically delegates are not observable, hence it is not necessary
 32   to use get() to retrieve the value of the delegate.
 33 
 34   @since SproutCore 1.0
 35 
 36 */
 37 SC.DelegateSupport = {
 38 
 39   /**
 40     Selects the delegate that implements the specified method name.  Pass one
 41     or more delegates.  The receiver is automatically included as a default.
 42 
 43     This can be more efficient than using invokeDelegateMethod() which has
 44     to marshall arguments into a delegate call.
 45 
 46     @param {String} methodName
 47     @param {Object...} delegate one or more delegate arguments
 48     @returns {Object} delegate or null
 49   */
 50   delegateFor: function(methodName) {
 51     var idx = 1,
 52         len = arguments.length,
 53         ret ;
 54 
 55     while(idx<len) {
 56       ret = arguments[idx];
 57       if (ret && ret[methodName] !== undefined) return ret ;
 58       idx++;
 59     }
 60 
 61     return (this[methodName] !== undefined) ? this : null;
 62   },
 63 
 64   /**
 65     Invokes the named method on the delegate that you pass.  If no delegate
 66     is defined or if the delegate does not implement the method, then a
 67     method of the same name on the receiver will be called instead.
 68 
 69     You can pass any arguments you want to pass onto the delegate after the
 70     delegate and methodName.
 71 
 72     @param {Object} delegate a delegate object.  May be null.
 73     @param {String} methodName a method name
 74     @param {Object...} [args...] any additional arguments
 75 
 76     @returns {Object} value returned by delegate
 77   */
 78   invokeDelegateMethod: function(delegate, methodName) {
 79     // Fast arguments access.
 80     // Accessing `arguments.length` is just a Number and doesn't materialize the `arguments` object, which is costly.
 81     var args = new Array(arguments.length - 2); //  SC.A(arguments).slice(2)
 82     for (var i = 0, len = args.length; i < len; i++) { args[i] = arguments[i + 2]; }
 83 
 84     if (!delegate || !delegate[methodName]) delegate = this ;
 85 
 86     var method = delegate[methodName];
 87     return method ? method.apply(delegate, args) : null;
 88   },
 89 
 90   /**
 91     Search the named delegates for the passed property.  If one is found,
 92     gets the property value and returns it.  If none of the passed delegates
 93     implement the property, search the receiver for the property as well.
 94 
 95     @param {String} key the property to get.
 96     @param {Object} delegate one or more delegate
 97     @returns {Object} property value or undefined
 98   */
 99   getDelegateProperty: function(key, delegate) {
100     var idx = 1,
101         len = arguments.length,
102         ret ;
103 
104     while(idx<len) {
105       ret = arguments[idx++];
106       if (ret && ret[key] != undefined) {
107         return ret.get ? ret.get(key) : ret[key] ;
108       }
109     }
110 
111     return (this[key] != undefined) ? this.get(key) : undefined ;
112   }
113 
114 };
115