1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 
 28 /**
 29  * Minimum priority level for user scheduling.
 30  * @constant
 31  * @type Number
 32  */
 33 cc.PRIORITY_NON_SYSTEM = cc.PRIORITY_SYSTEM + 1;
 34 
 35 /**
 36  * Verify Array's Type
 37  * @param {Array} arr
 38  * @param {function} type
 39  * @return {Boolean}
 40  * @function
 41  */
 42 cc.arrayVerifyType = function (arr, type) {
 43     if (arr && arr.length > 0) {
 44         for (var i = 0; i < arr.length; i++) {
 45             if (!(arr[i] instanceof  type)) {
 46                 cc.log(cc._LogInfos.arrayVerifyType);
 47                 return false;
 48             }
 49         }
 50     }
 51     return true;
 52 };
 53 
 54 /**
 55  * Searches for the first occurance of object and removes it. If object is not found the function has no effect.
 56  * @function
 57  * @param {Array} arr Source Array
 58  * @param {*} delObj  remove object
 59  */
 60 cc.arrayRemoveObject = function (arr, delObj) {
 61     for (var i = 0, l = arr.length; i < l; i++) {
 62         if (arr[i] == delObj) {
 63             arr.splice(i, 1);
 64             break;
 65         }
 66     }
 67 };
 68 
 69 /**
 70  * Removes from arr all values in minusArr. For each Value in minusArr, the first matching instance in arr will be removed.
 71  * @function
 72  * @param {Array} arr Source Array
 73  * @param {Array} minusArr minus Array
 74  */
 75 cc.arrayRemoveArray = function (arr, minusArr) {
 76     for (var i = 0, l = minusArr.length; i < l; i++) {
 77         cc.arrayRemoveObject(arr, minusArr[i]);
 78     }
 79 };
 80 
 81 /**
 82  * Inserts some objects at index
 83  * @function
 84  * @param {Array} arr
 85  * @param {Array} addObjs
 86  * @param {Number} index
 87  * @return {Array}
 88  */
 89 cc.arrayAppendObjectsToIndex = function(arr, addObjs,index){
 90     arr.splice.apply(arr, [index, 0].concat(addObjs));
 91     return arr;
 92 };
 93 
 94 //data structures
 95 /**
 96  * A list double-linked list used for "updates with priority"
 97  * @Class
 98  * @Construct
 99  * @param {cc.ListEntry} prev
100  * @param {cc.ListEntry} next
101  * @param {cc.Class} target not retained (retained by hashUpdateEntry)
102  * @param {Number} priority
103  * @param {Boolean} paused
104  * @param {Boolean} markedForDeletion selector will no longer be called and entry will be removed at end of the next tick
105  */
106 cc.ListEntry = function (prev, next, target, priority, paused, markedForDeletion) {
107     this.prev = prev;
108     this.next = next;
109     this.target = target;
110     this.priority = priority;
111     this.paused = paused;
112     this.markedForDeletion = markedForDeletion;
113 };
114 
115 /**
116  *  a update entry list
117  * @Class
118  * @Construct
119  * @param {cc.ListEntry} list Which list does it belong to ?
120  * @param {cc.ListEntry} entry entry in the list
121  * @param {cc.Class} target hash key (retained)
122  * @param {Array} hh
123  */
124 cc.HashUpdateEntry = function (list, entry, target, hh) {
125     this.list = list;
126     this.entry = entry;
127     this.target = target;
128     this.hh = hh;
129 };
130 
131 //
132 /**
133  * Hash Element used for "selectors with interval"
134  * @Class
135  * @Construct
136  * @param {Array} timers
137  * @param {cc.Class} target  hash key (retained)
138  * @param {Number} timerIndex
139  * @param {cc.Timer} currentTimer
140  * @param {Boolean} currentTimerSalvaged
141  * @param {Boolean} paused
142  * @param {Array} hh
143  */
144 cc.HashTimerEntry = function (timers, target, timerIndex, currentTimer, currentTimerSalvaged, paused, hh) {
145     var _t = this;
146     _t.timers = timers;
147     _t.target = target;
148     _t.timerIndex = timerIndex;
149     _t.currentTimer = currentTimer;
150     _t.currentTimerSalvaged = currentTimerSalvaged;
151     _t.paused = paused;
152     _t.hh = hh;
153 };
154 
155 /**
156  * Light weight timer
157  * @class
158  * @extends cc.Class
159  */
160 cc.Timer = cc.Class.extend(/** @lends cc.Timer# */{
161     _interval:0.0,
162     _callback:null,//is called _callback before
163 
164     _target:null,//target of _callback
165     _elapsed:0.0,
166 
167     _runForever:false,
168     _useDelay:false,
169     _timesExecuted:0,
170     _repeat:0, //0 = once, 1 is 2 x executed
171     _delay:0,
172 
173     /**
174      * @return {Number} returns interval of timer
175      */
176     getInterval : function(){return this._interval;},
177     /**
178      * @param {Number} interval set interval in seconds
179      */
180     setInterval : function(interval){this._interval = interval;},
181 
182     /**
183      * @return {String|function} returns callback
184      */
185     getCallback : function(){return this._callback},
186 
187 
188     /**
189      * cc.Timer's Constructor
190      * @constructor
191      * @param {cc.Class} target target
192      * @param {String|function} callback Selector
193      * @param {Number} [interval=0] second
194      * @param {Number} [repeat=cc.REPEAT_FOREVER] repeat times
195      * @param {Number} [delay=0] delay
196      */
197     ctor:function (target, callback, interval, repeat, delay) {
198         var self = this;
199         self._target = target;
200         self._callback = callback;
201         self._elapsed = -1;
202         self._interval = interval || 0;
203         self._delay = delay || 0;
204         self._useDelay = self._delay > 0;
205         self._repeat = (repeat == null) ? cc.REPEAT_FOREVER : repeat;
206         self._runForever = (self._repeat == cc.REPEAT_FOREVER);
207     },
208 
209     _doCallback:function(){
210         var self = this;
211         if (typeof(self._callback) == "string")
212             self._target[self._callback](self._elapsed);
213         else // if (typeof(this._callback) == "function") {
214             self._callback.call(self._target, self._elapsed);
215     },
216 
217     /**
218      * triggers the timer
219      * @param {Number} dt delta time
220      */
221     update:function (dt) {
222         var self = this;
223         if (self._elapsed == -1) {
224             self._elapsed = 0;
225             self._timesExecuted = 0;
226         } else {
227             var locTarget = self._target, locCallback = self._callback;
228             self._elapsed += dt;//standard timer usage
229             if (self._runForever && !self._useDelay) {
230                 if (self._elapsed >= self._interval) {
231                     if (locTarget && locCallback)
232                         self._doCallback();
233                     self._elapsed = 0;
234                 }
235             } else {
236                 //advanced usage
237                 if (self._useDelay) {
238                     if (self._elapsed >= self._delay) {
239                         if (locTarget && locCallback)
240                             self._doCallback();
241 
242                         self._elapsed = self._elapsed - self._delay;
243                         self._timesExecuted += 1;
244                         self._useDelay = false;
245                     }
246                 } else {
247                     if (self._elapsed >= self._interval) {
248                         if (locTarget && locCallback)
249                             self._doCallback();
250 
251                         self._elapsed = 0;
252                         self._timesExecuted += 1;
253                     }
254                 }
255 
256                 if (self._timesExecuted > self._repeat)
257                     cc.director.getScheduler().unscheduleCallbackForTarget(locTarget, locCallback);
258             }
259         }
260     }
261 });
262 
263 /**
264  * <p>
265  *    Scheduler is responsible of triggering the scheduled callbacks.<br/>
266  *    You should not use NSTimer. Instead use this class.<br/>
267  *    <br/>
268  *    There are 2 different types of callbacks (selectors):<br/>
269  *       - update callback: the 'update' callback will be called every frame. You can customize the priority.<br/>
270  *       - custom callback: A custom callback will be called every frame, or with a custom interval of time<br/>
271  *       <br/>
272  *    The 'custom selectors' should be avoided when possible. It is faster, and consumes less memory to use the 'update callback'. *
273  * </p>
274  * @class
275  * @extends cc.Class
276  *
277  * @example
278  * //register a schedule to scheduler
279  * cc.director.getScheduler().scheduleSelector(callback, this, interval, !this._isRunning);
280  */
281 cc.Scheduler = cc.Class.extend(/** @lends cc.Scheduler# */{
282     _timeScale:1.0,
283 
284     _updates : null, //_updates[0] list of priority < 0, _updates[1] list of priority == 0, _updates[2] list of priority > 0,
285 
286     _hashForUpdates:null, // hash used to fetch quickly the list entries for pause,delete,etc
287     _arrayForUpdates:null,
288 
289     _hashForTimers:null, //Used for "selectors with interval"
290     _arrayForTimes:null,
291 
292     _currentTarget:null,
293     _currentTargetSalvaged:false,
294     _updateHashLocked:false, //If true unschedule will not remove anything from a hash. Elements will only be marked for deletion.
295 
296     /**
297      * Constructor
298      */
299     ctor:function () {
300         var self = this;
301         self._timeScale = 1.0;
302         self._updates = [[], [], []];
303 
304         self._hashForUpdates = {};
305         self._arrayForUpdates = [];
306 
307         self._hashForTimers = {};
308         self._arrayForTimers = [];
309 
310         self._currentTarget = null;
311         self._currentTargetSalvaged = false;
312         self._updateHashLocked = false;
313     },
314 
315     //-----------------------private method----------------------
316     _removeHashElement:function (element) {
317         delete this._hashForTimers[element.target.__instanceId];
318         cc.arrayRemoveObject(this._arrayForTimers, element);
319         element.Timer = null;
320         element.target = null;
321         element = null;
322     },
323 
324     _removeUpdateFromHash:function (entry) {
325         var self = this, element = self._hashForUpdates[entry.target.__instanceId];
326         if (element) {
327             //list entry
328             cc.arrayRemoveObject(element.list, element.entry);
329 
330             delete self._hashForUpdates[element.target.__instanceId];
331             cc.arrayRemoveObject(self._arrayForUpdates, element);
332             element.entry = null;
333 
334             //hash entry
335             element.target = null;
336         }
337     },
338 
339     _priorityIn:function (ppList, target, priority, paused) {
340         var self = this, listElement = new cc.ListEntry(null, null, target, priority, paused, false);
341 
342         // empey list ?
343         if (!ppList) {
344             ppList = [];
345             ppList.push(listElement);
346         } else {
347             var index2Insert = ppList.length - 1;
348             for(var i = 0; i <= index2Insert; i++){
349                 if (priority < ppList[i].priority) {
350                     index2Insert = i;
351                     break;
352                 }
353             }
354             ppList.splice(i, 0, listElement);
355         }
356 
357         //update hash entry for quick access
358         var hashElement = new cc.HashUpdateEntry(ppList, listElement, target, null);
359         self._arrayForUpdates.push(hashElement);
360         self._hashForUpdates[target.__instanceId] = hashElement;
361 
362         return ppList;
363     },
364 
365     _appendIn:function (ppList, target, paused) {
366         var self = this, listElement = new cc.ListEntry(null, null, target, 0, paused, false);
367         ppList.push(listElement);
368 
369         //update hash entry for quicker access
370         var hashElement = new cc.HashUpdateEntry(ppList, listElement, target, null);
371         self._arrayForUpdates.push(hashElement);
372         self._hashForUpdates[target.__instanceId] = hashElement;
373     },
374 
375     //-----------------------public method-------------------------
376     /**
377      * <p>
378      *    Modifies the time of all scheduled callbacks.<br/>
379      *    You can use this property to create a 'slow motion' or 'fast forward' effect.<br/>
380      *    Default is 1.0. To create a 'slow motion' effect, use values below 1.0.<br/>
381      *    To create a 'fast forward' effect, use values higher than 1.0.<br/>
382      *    @warning It will affect EVERY scheduled selector / action.
383      * </p>
384      * @param {Number} timeScale
385      */
386     setTimeScale:function (timeScale) {
387         this._timeScale = timeScale;
388     },
389 
390     /**
391      * returns time scale of scheduler
392      * @return {Number}
393      */
394     getTimeScale:function () {
395         return this._timeScale;
396     },
397 
398     /**
399      * 'update' the scheduler. (You should NEVER call this method, unless you know what you are doing.)
400      * @param {Number} dt delta time
401      */
402     update:function (dt) {
403         var self = this;
404         var locUpdates = self._updates, locArrayForTimers = self._arrayForTimers;
405         var tmpEntry, elt, i, li;
406         self._updateHashLocked = true;
407 
408         if (this._timeScale != 1.0) {
409             dt *= this._timeScale;
410         }
411 
412         for(i = 0, li = locUpdates.length; i < li && i >= 0; i++){
413             var update = self._updates[i];
414             for(var j = 0, lj = update.length; j < lj; j++){
415                 tmpEntry = update[j];
416                 if ((!tmpEntry.paused) && (!tmpEntry.markedForDeletion)) tmpEntry.target.update(dt);
417             }
418         }
419 
420         //Interate all over the custom callbacks
421         for(i = 0, li = locArrayForTimers.length; i < li; i++){
422             elt = locArrayForTimers[i];
423             if(!elt) break;
424             self._currentTarget = elt;
425             self._currentTargetSalvaged = false;
426 
427             if (!elt.paused) {
428                 // The 'timers' array may change while inside this loop
429                 for (elt.timerIndex = 0; elt.timerIndex < elt.timers.length; elt.timerIndex++) {
430                     elt.currentTimer = elt.timers[elt.timerIndex];
431                     elt.currentTimerSalvaged = false;
432 
433                     elt.currentTimer.update(dt);
434                     elt.currentTimer = null;
435                 }
436             }
437 
438             if ((self._currentTargetSalvaged) && (elt.timers.length == 0)){
439                 self._removeHashElement(elt);
440                 i--;
441             }
442         }
443 
444         for(i = 0, li = locUpdates.length; i < li; i++){
445             var update = self._updates[i];
446             for(var j = 0, lj = update.length; j < lj; ){
447                 tmpEntry = update[j];
448                 if(!tmpEntry) break;
449                 if (tmpEntry.markedForDeletion) self._removeUpdateFromHash(tmpEntry);
450                 else j++;
451             }
452         }
453 
454         self._updateHashLocked = false;
455         self._currentTarget = null;
456     },
457 
458     /**
459      * <p>
460      *   The scheduled method will be called every 'interval' seconds.</br>
461      *   If paused is YES, then it won't be called until it is resumed.<br/>
462      *   If 'interval' is 0, it will be called every frame, but if so, it recommended to use 'scheduleUpdateForTarget:' instead.<br/>
463      *   If the callback function is already scheduled, then only the interval parameter will be updated without re-scheduling it again.<br/>
464      *   repeat let the action be repeated repeat + 1 times, use cc.REPEAT_FOREVER to let the action run continuously<br/>
465      *   delay is the amount of time the action will wait before it'll start<br/>
466      * </p>
467      * @param {cc.Class} target
468      * @param {function} callback_fn
469      * @param {Number} interval
470      * @param {Number} repeat
471      * @param {Number} delay
472      * @param {Boolean} paused
473      * @example
474      * //register a schedule to scheduler
475      * cc.director.getScheduler().scheduleCallbackForTarget(this, function, interval, repeat, delay, !this._isRunning );
476      */
477     scheduleCallbackForTarget:function (target, callback_fn, interval, repeat, delay, paused) {
478 
479         cc.assert(callback_fn, cc._LogInfos.Scheduler_scheduleCallbackForTarget_2);
480 
481         cc.assert(target, cc._LogInfos.Scheduler_scheduleCallbackForTarget_3);
482 
483         // default arguments
484         interval = interval || 0;
485         repeat = (repeat == null) ? cc.REPEAT_FOREVER : repeat;
486         delay = delay || 0;
487         paused = paused || false;
488 
489         var self = this, timer;
490         var element = self._hashForTimers[target.__instanceId];
491 
492         if (!element) {
493             // Is this the 1st element ? Then set the pause level to all the callback_fns of this target
494             element = new cc.HashTimerEntry(null, target, 0, null, null, paused, null);
495             self._arrayForTimers.push(element);
496             self._hashForTimers[target.__instanceId] = element;
497         }
498 
499         if (element.timers == null) {
500             element.timers = [];
501         } else {
502             for (var i = 0; i < element.timers.length; i++) {
503                 timer = element.timers[i];
504                 if (callback_fn == timer._callback) {
505                     cc.log(cc._LogInfos.Scheduler_scheduleCallbackForTarget, timer.getInterval().toFixed(4), interval.toFixed(4));
506                     timer._interval = interval;
507                     return;
508                 }
509             }
510         }
511 
512         timer = new cc.Timer(target, callback_fn, interval, repeat, delay);
513         element.timers.push(timer);
514     },
515 
516     /**
517      * <p>
518      *    Schedules the 'update' callback_fn for a given target with a given priority.<br/>
519      *    The 'update' callback_fn will be called every frame.<br/>
520      *    The lower the priority, the earlier it is called.
521      * </p>
522      * @param {cc.Class} target
523      * @param {Number} priority
524      * @param {Boolean} paused
525      * @example
526      * //register this object to scheduler
527      * cc.director.getScheduler().scheduleUpdateForTarget(this, priority, !this._isRunning );
528      */
529     scheduleUpdateForTarget:function (target, priority, paused) {
530         if(target === null)
531             return;
532         var self = this, locUpdates = self._updates;
533         var hashElement = self._hashForUpdates[target.__instanceId];
534 
535         if (hashElement) {
536             // TODO: check if priority has changed!
537             hashElement.entry.markedForDeletion = false;
538             return;
539         }
540 
541         // most of the updates are going to be 0, that's way there
542         // is an special list for updates with priority 0
543         if (priority == 0) {
544             self._appendIn(locUpdates[1], target, paused);
545         } else if (priority < 0) {
546             locUpdates[0] = self._priorityIn(locUpdates[0], target, priority, paused);
547         } else {
548             // priority > 0
549             locUpdates[2] = self._priorityIn(locUpdates[2], target, priority, paused);
550         }
551     },
552 
553     /**
554      * <p>
555      *   Unschedule a callback function for a given target.<br/>
556      *   If you want to unschedule the "update", use unscheudleUpdateForTarget.
557      * </p>
558      * @param {cc.Class} target
559      * @param {function} callback_fn
560      * @example
561      * //unschedule a callback of target
562      * cc.director.getScheduler().unscheduleCallbackForTarget(function, this);
563      */
564     unscheduleCallbackForTarget:function (target, callback_fn) {
565         // explicity handle nil arguments when removing an object
566         if ((target == null) || (callback_fn == null)) {
567             return;
568         }
569 
570         var self = this, element = self._hashForTimers[target.__instanceId];
571         if (element) {
572             var timers = element.timers;
573             for(var i = 0, li = timers.length; i < li; i++){
574                 var timer = timers[i];
575                 if (callback_fn == timer._callback) {
576                     if ((timer == element.currentTimer) && (!element.currentTimerSalvaged)) {
577                         element.currentTimerSalvaged = true;
578                     }
579                     timers.splice(i, 1)
580                     //update timerIndex in case we are in tick;, looping over the actions
581                     if (element.timerIndex >= i) {
582                         element.timerIndex--;
583                     }
584 
585                     if (timers.length == 0) {
586                         if (self._currentTarget == element) {
587                             self._currentTargetSalvaged = true;
588                         } else {
589                             self._removeHashElement(element);
590                         }
591                     }
592                     return;
593                 }
594             }
595         }
596     },
597 
598     /**
599      * Unschedules the update callback function for a given target
600      * @param {cc.Class} target
601      * @example
602      * //unschedules the "update" method.
603      * cc.director.getScheduler().unscheduleUpdateForTarget(this);
604      */
605     unscheduleUpdateForTarget:function (target) {
606         if (target == null) {
607             return;
608         }
609 
610         var self = this, element = self._hashForUpdates[target.__instanceId];
611         if (element != null) {
612             if (self._updateHashLocked) {
613                 element.entry.markedForDeletion = true;
614             } else {
615                 self._removeUpdateFromHash(element.entry);
616             }
617         }
618     },
619 
620     /**
621      * Unschedules all function callbacks for a given target. This also includes the "update" callback function.
622      * @param {cc.Class} target
623      */
624     unscheduleAllCallbacksForTarget:function (target) {
625         //explicit NULL handling
626         if (target == null) {
627             return;
628         }
629 
630         var self = this, element = self._hashForTimers[target.__instanceId];
631         if (element) {
632             var timers = element.timers;
633             if ((!element.currentTimerSalvaged) && (timers.indexOf(element.currentTimer) >= 0)) {
634                 element.currentTimerSalvaged = true;
635             }
636             timers.length = 0;
637 
638             if (self._currentTarget == element) {
639                 self._currentTargetSalvaged = true;
640             } else {
641                 self._removeHashElement(element);
642             }
643         }
644         // update callback
645         self.unscheduleUpdateForTarget(target);
646     },
647 
648     /**
649      *  <p>
650      *      Unschedules all function callbacks from all targets. <br/>
651      *      You should NEVER call this method, unless you know what you are doing.
652      *  </p>
653      */
654     unscheduleAllCallbacks:function () {
655         this.unscheduleAllCallbacksWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM);
656     },
657 
658     /**
659      * <p>
660      *    Unschedules all function callbacks from all targets with a minimum priority.<br/>
661      *    You should only call this with kCCPriorityNonSystemMin or higher.
662      * </p>
663      * @param {Number} minPriority
664      */
665     unscheduleAllCallbacksWithMinPriority:function (minPriority) {
666         // Custom Selectors
667         var self = this, locArrayForTimers = self._arrayForTimers, locUpdates = self._updates;
668         for(var i = 0, li = locArrayForTimers.length; i < li; i++){
669             // element may be removed in unscheduleAllCallbacksForTarget
670             self.unscheduleAllCallbacksForTarget(locArrayForTimers[i].target);
671         }
672         for(var i = 2; i >= 0; i--){
673             if((i == 1 && minPriority > 0) || (i == 0 && minPriority >= 0)) continue;
674             var updates = locUpdates[i];
675             for(var j = 0, lj = updates.length; j < lj; j++){
676                 self.unscheduleUpdateForTarget(updates[j].target);
677             }
678         }
679     },
680 
681     /**
682      * <p>
683      *  Pause all selectors from all targets.<br/>
684      *  You should NEVER call this method, unless you know what you are doing.
685      * </p>
686      */
687     pauseAllTargets:function () {
688         return this.pauseAllTargetsWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM);
689     },
690 
691     /**
692      * Pause all selectors from all targets with a minimum priority. <br/>
693      * You should only call this with kCCPriorityNonSystemMin or higher.
694      * @param minPriority
695      */
696     pauseAllTargetsWithMinPriority:function (minPriority) {
697         var idsWithSelectors = [];
698 
699         var self = this, element, locArrayForTimers = self._arrayForTimers, locUpdates = self._updates;
700         // Custom Selectors
701         for(var i = 0, li = locArrayForTimers.length; i < li; i++){
702             element = locArrayForTimers[i];
703             if (element) {
704                 element.paused = true;
705                 idsWithSelectors.push(element.target);
706             }
707         }
708         for(var i = 0, li = locUpdates.length; i < li; i++){
709             var updates = locUpdates[i];
710             for(var j = 0, lj = updates.length; j < lj; j++){
711                 element = updates[j];
712                 if (element) {
713                     element.paused = true;
714                     idsWithSelectors.push(element.target);
715                 }
716             }
717         }
718         return idsWithSelectors;
719     },
720 
721     /**
722      * Resume selectors on a set of targets.<br/>
723      * This can be useful for undoing a call to pauseAllCallbacks.
724      * @param targetsToResume
725      */
726     resumeTargets:function (targetsToResume) {
727         if (!targetsToResume)
728             return;
729 
730         for (var i = 0; i < targetsToResume.length; i++) {
731             this.resumeTarget(targetsToResume[i]);
732         }
733     },
734 
735     /**
736      * <p>
737      *    Pauses the target.<br/>
738      *    All scheduled selectors/update for a given target won't be 'ticked' until the target is resumed.<br/>
739      *    If the target is not present, nothing happens.
740      * </p>
741      * @param {cc.Class} target
742      */
743     pauseTarget:function (target) {
744 
745         cc.assert(target, cc._LogInfos.Scheduler_pauseTarget);
746 
747         //customer selectors
748         var self = this, element = self._hashForTimers[target.__instanceId];
749         if (element) {
750             element.paused = true;
751         }
752 
753         //update callback
754         var elementUpdate = self._hashForUpdates[target.__instanceId];
755         if (elementUpdate) {
756             elementUpdate.entry.paused = true;
757         }
758     },
759 
760     /**
761      * Resumes the target.<br/>
762      * The 'target' will be unpaused, so all schedule selectors/update will be 'ticked' again.<br/>
763      * If the target is not present, nothing happens.
764      * @param {cc.Class} target
765      */
766     resumeTarget:function (target) {
767 
768         cc.assert(target, cc._LogInfos.Scheduler_resumeTarget);
769 
770         // custom selectors
771         var self = this, element = self._hashForTimers[target.__instanceId];
772 
773         if (element) {
774             element.paused = false;
775         }
776 
777         //update callback
778         var elementUpdate = self._hashForUpdates[target.__instanceId];
779 
780         if (elementUpdate) {
781             elementUpdate.entry.paused = false;
782         }
783     },
784 
785     /**
786      * Returns whether or not the target is paused
787      * @param {cc.Class} target
788      * @return {Boolean}
789      */
790     isTargetPaused:function (target) {
791 
792         cc.assert(target, cc._LogInfos.Scheduler_isTargetPaused);
793 
794         // Custom selectors
795         var element = this._hashForTimers[target.__instanceId];
796         if (element) {
797             return element.paused;
798         }
799         return false;
800     }
801 });
802 /**
803  * Priority level reserved for system services.
804  * @constant
805  * @type Number
806  */
807 cc.Scheduler.PRIORITY_SYSTEM = (-2147483647 - 1);
808