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 // Extensions to the core SC.Object class 9 SC.mixin(SC.Object.prototype, /** @scope SC.Object.prototype */ { 10 11 /** 12 Invokes the named method after the specified period of time. This 13 uses SC.Timer, which works properly with the Run Loop. 14 15 Any additional arguments given to invokeOnce will be passed to the 16 method. 17 18 For example, 19 20 var obj = SC.Object.create({ 21 myMethod: function(a, b, c) { 22 alert('a: %@, b: %@, c: %@'.fmt(a, b, c)); 23 } 24 }); 25 26 obj.invokeLater('myMethod', 200, 'x', 'y', 'z'); 27 28 // After 200 ms, alerts "a: x, b: y, c: z" 29 30 @param method {String} method name to perform. 31 @param interval {Number} period from current time to schedule. 32 @returns {SC.Timer} scheduled timer. 33 */ 34 invokeLater: function(method, interval) { 35 var f, args; 36 37 // Normalize the method and interval. 38 if (SC.typeOf(method) === SC.T_STRING) { method = this[method]; } 39 if (interval === undefined) { interval = 1 ; } 40 41 // If extra arguments were passed - build a function binding. 42 if (arguments.length > 2) { 43 args = SC.$A(arguments).slice(2); 44 f = function() { return method.apply(this, args); } ; 45 } else { 46 f = method; 47 } 48 49 // schedule the timer 50 return SC.Timer.schedule({ target: this, action: f, interval: interval }); 51 }, 52 53 /** 54 A convenience method which makes it easy to coalesce invocations to ensure 55 that the method is only called once after the given period of time. This is 56 useful if you need to schedule a call from multiple places, but only want 57 it to run at most once. 58 59 Any additional arguments given to invokeOnceLater will be passed to the 60 method. 61 62 For example, 63 64 var obj = SC.Object.create({ 65 myMethod: function(a, b, c) { 66 alert('a: %@, b: %@, c: %@'.fmt(a, b, c)); 67 } 68 }); 69 70 obj.invokeOnceLater('myMethod', 200, 'x', 'y', 'z'); 71 72 // After 200 ms, alerts "a: x, b: y, c: z" 73 74 @param {Function|String} method reference or method name 75 @param {Number} interval 76 */ 77 invokeOnceLater: function(method, interval) { 78 var args, f, 79 methodGuid, 80 timers = this._sc_invokeOnceLaterTimers, 81 existingTimer, newTimer; 82 83 // Normalize the method, interval and timers cache. 84 if (SC.typeOf(method) === SC.T_STRING) { method = this[method]; } 85 if (interval === undefined) { interval = 1 ; } 86 if (!timers) { timers = this._sc_invokeOnceLaterTimers = {}; } 87 88 // If there's a timer outstanding for this method, invalidate it in favor of 89 // the new timer. 90 methodGuid = SC.guidFor(method); 91 existingTimer = timers[methodGuid]; 92 if (existingTimer) existingTimer.invalidate(); 93 94 // If extra arguments were passed - apply them to the method. 95 if (arguments.length > 2) { 96 args = SC.$A(arguments).slice(2); 97 } else { 98 args = arguments; 99 } 100 101 // Create a function binding every time, so that the timers cache is properly cleaned out. 102 f = function() { 103 // GC assistance for IE 104 delete timers[methodGuid]; 105 return method.apply(this, args); 106 }; 107 108 // Schedule the new timer and track it. 109 newTimer = SC.Timer.schedule({ target: this, action: f, interval: interval }); 110 timers[methodGuid] = newTimer; 111 112 return newTimer; 113 }, 114 115 /** 116 Lookup the named property path and then invoke the passed function, 117 passing the resulting value to the function. 118 119 This method is a useful way to handle deferred loading of properties. 120 If you want to defer loading a property, you can override this method. 121 When the method is called, passing a deferred property, you can load the 122 property before invoking the callback method. 123 124 You can even swap out the receiver object. 125 126 The callback method should have the signature: 127 128 function callback(objectAtPath, sourceObject) { ... } 129 130 You may pass either a function itself or a target/method pair. 131 132 @param {String} pathName 133 @param {Object} target target or method 134 @param {Function|String} method 135 @returns {SC.Object} receiver 136 */ 137 invokeWith: function(pathName, target, method) { 138 // normalize target/method 139 if (method === undefined) { 140 method = target; target = this; 141 } 142 if (!target) { target = this ; } 143 if (SC.typeOf(method) === SC.T_STRING) { method = target[method]; } 144 145 // get value 146 var v = this.getPath(pathName); 147 148 // invoke method 149 method.call(target, v, this); 150 return this ; 151 } 152 153 }); 154