PageRenderTime 22ms CodeModel.GetById 13ms app.highlight 4ms RepoModel.GetById 1ms app.codeStats 0ms

/Foundation/CPTimer.j

http://github.com/cacaodev/cappuccino
Unknown | 309 lines | 254 code | 55 blank | 0 comment | 0 complexity | 12a574361a930e9e1af78176cf2e83d0 MD5 | raw file
  1/*
  2 * CPTimer.j
  3 * Foundation
  4 *
  5 * Created by Nick Takayama.
  6 * Copyright 2008.
  7 *
  8 * This library is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU Lesser General Public
 10 * License as published by the Free Software Foundation; either
 11 * version 2.1 of the License, or (at your option) any later version.
 12 *
 13 * This library is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 16 * Lesser General Public License for more details.
 17 *
 18 * You should have received a copy of the GNU Lesser General Public
 19 * License along with this library; if not, write to the Free Software
 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 21 */
 22
 23@import "CPDate.j"
 24@import "CPInvocation.j"
 25@import "CPObject.j"
 26@import "CPRunLoop.j"
 27
 28#define CPTimerDefaultTimeInterval 0.1
 29
 30/*!
 31    @class CPTimer
 32    @ingroup foundation
 33
 34    @brief A timer object that can send a message after the given time interval.
 35*/
 36@implementation CPTimer : CPObject
 37{
 38    CPTimeInterval      _timeInterval;
 39    CPInvocation        _invocation;
 40    Function            _callback;
 41
 42    BOOL                _repeats;
 43    BOOL                _isValid;
 44    CPDate              _fireDate;
 45    id                  _userInfo;
 46}
 47
 48/*!
 49    Returns a new CPTimer object and adds it to the current CPRunLoop object in the default mode.
 50*/
 51+ (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat
 52{
 53    var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds invocation:anInvocation repeats:shouldRepeat];
 54
 55    [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode];
 56
 57    return timer;
 58}
 59
 60/*!
 61    Returns a new CPTimer object and adds it to the current CPRunLoop object in the default mode.
 62*/
 63+ (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
 64{
 65    var timer =  [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds target:aTarget selector:aSelector userInfo:userInfo repeats:shouldRepeat];
 66
 67    [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode];
 68
 69    return timer;
 70}
 71
 72/*!
 73    Returns a new CPTimer object and adds it to the current CPRunLoop object in the default mode.
 74*/
 75+ (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat
 76{
 77    var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds callback:aFunction repeats:shouldRepeat];
 78
 79    [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode];
 80
 81    return timer;
 82}
 83
 84/*!
 85    Returns a new CPTimer that, when added to a run loop, will fire after seconds.
 86*/
 87+ (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat
 88{
 89    return [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds invocation:anInvocation repeats:shouldRepeat];
 90}
 91
 92/*!
 93    Returns a new CPTimer that, when added to a run loop, will fire after seconds.
 94*/
 95+ (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
 96{
 97    return [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds target:aTarget selector:aSelector userInfo:userInfo repeats:shouldRepeat];
 98}
 99
100/*!
101    Returns a new CPTimer that, when added to a run loop, will fire after seconds.
102*/
103+ (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat
104{
105    return [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds callback:aFunction repeats:shouldRepeat];
106}
107
108/*!
109    Initializes a new CPTimer that, when added to a run loop, will fire at date and then, if repeats is YES, every seconds after that.
110*/
111- (id)initWithFireDate:(CPDate)aDate interval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat
112{
113    self = [super init];
114
115    if (self)
116    {
117        _timeInterval = (seconds <= 0) ? CPTimerDefaultTimeInterval : seconds;
118        _invocation = anInvocation;
119        _repeats = shouldRepeat;
120        _isValid = YES;
121        _fireDate = aDate;
122    }
123
124    return self;
125}
126
127/*!
128    Initializes a new CPTimer that, when added to a run loop, will fire at date and then, if repeats is YES, every seconds after that.
129*/
130- (id)initWithFireDate:(CPDate)aDate interval:(CPTimeInterval)seconds target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
131{
132    var invocation = [CPInvocation invocationWithMethodSignature:1];
133
134    [invocation setTarget:aTarget];
135    [invocation setSelector:aSelector];
136    [invocation setArgument:self atIndex:2];
137
138    self = [self initWithFireDate:aDate interval:seconds invocation:invocation repeats:shouldRepeat];
139
140    if (self)
141        _userInfo = userInfo;
142
143    return self;
144}
145
146/*!
147    Initializes a new CPTimer that, when added to a run loop, will fire at date and then, if repeats is YES, every seconds after that.
148*/
149- (id)initWithFireDate:(CPDate)aDate interval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat
150{
151    self = [super init];
152
153    if (self)
154    {
155        _timeInterval = (seconds <= 0) ? CPTimerDefaultTimeInterval : seconds;
156        _callback = aFunction;
157        _repeats = shouldRepeat;
158        _isValid = YES;
159        _fireDate = aDate;
160    }
161
162    return self;
163}
164
165/*!
166    Returns the receiver’s time interval.
167*/
168- (CPTimeInterval)timeInterval
169{
170   return _timeInterval;
171}
172
173/*!
174    Returns the date at which the receiver will fire.
175*/
176- (CPDate)fireDate
177{
178   return _fireDate;
179}
180
181/*!
182    Resets the receiver to fire next at a given date.
183*/
184- (void)setFireDate:(CPDate)aDate
185{
186    _fireDate = aDate;
187}
188
189/*!
190    Causes the receiver’s message to be sent to its target.
191*/
192- (void)fire
193{
194    if (!_isValid)
195        return;
196
197    if (_callback)
198        _callback();
199    else
200        [_invocation invoke];
201
202    if (!_isValid)
203        return;
204
205    if (_repeats)
206        _fireDate = [CPDate dateWithTimeIntervalSinceNow:_timeInterval];
207
208    else
209        [self invalidate];
210}
211
212/*!
213    Returns a Boolean value that indicates whether the receiver is currently valid.
214*/
215- (BOOL)isValid
216{
217   return _isValid;
218}
219
220/*!
221    Stops the receiver from ever firing again and requests its removal from its CPRunLoop object.
222*/
223- (void)invalidate
224{
225   _isValid = NO;
226   _userInfo = nil;
227   _invocation = nil;
228   _callback = nil;
229}
230
231/*!
232    Returns the receiver's userInfo object.
233*/
234- (id)userInfo
235{
236   return _userInfo;
237}
238
239@end
240
241var CPTimersTimeoutID       = 1000,
242    CPTimersForTimeoutIDs   = {};
243
244var _CPTimerBridgeTimer = function(codeOrFunction, aDelay, shouldRepeat, functionArgs)
245{
246    var timeoutID = CPTimersTimeoutID++,
247        theFunction = nil;
248
249    if (typeof codeOrFunction === "string")
250    {
251        theFunction = function()
252        {
253            new Function(codeOrFunction)();
254
255            if (!shouldRepeat)
256                CPTimersForTimeoutIDs[timeoutID] = nil;
257        }
258    }
259    else
260    {
261        if (!functionArgs)
262            functionArgs = [];
263
264        theFunction = function()
265        {
266            codeOrFunction.apply(window, functionArgs);
267
268            if (!shouldRepeat)
269                CPTimersForTimeoutIDs[timeoutID] = nil;
270        }
271    }
272
273    // A call such as setTimeout(f) is technically invalid but browsers seem to treat it as setTimeout(f, 0), so so will we.
274    aDelay = aDelay | 0.0;
275
276    CPTimersForTimeoutIDs[timeoutID] = [CPTimer scheduledTimerWithTimeInterval:aDelay / 1000 callback:theFunction repeats:shouldRepeat];
277
278    return timeoutID;
279};
280
281// Avoid "TypeError: Result of expression 'window' [undefined] is not an object" when running unit tests.
282// We can't use a regular PLATFORM(DOM) check because that platform constant is not defined in Foundation.
283if (typeof(window) !== 'undefined')
284{
285    window.setTimeout = function(codeOrFunction, aDelay)
286    {
287        return _CPTimerBridgeTimer(codeOrFunction, aDelay, NO, Array.prototype.slice.apply(arguments, [2]));
288    };
289
290    window.clearTimeout = function(aTimeoutID)
291    {
292        var timer = CPTimersForTimeoutIDs[aTimeoutID];
293
294        if (timer)
295            [timer invalidate];
296
297        CPTimersForTimeoutIDs[aTimeoutID] = nil;
298    };
299
300    window.setInterval = function(codeOrFunction, aDelay, functionArgs)
301    {
302        return _CPTimerBridgeTimer(codeOrFunction, aDelay, YES, Array.prototype.slice.apply(arguments, [2]));
303    };
304
305    window.clearInterval = function(aTimeoutID)
306    {
307        window.clearTimeout(aTimeoutID);
308    };
309}