~launchpad-pqm/lazr-js/toolchain

« back to all changes in this revision

Viewing changes to src-js/lazrjs/yui/async-queue/async-queue-debug.js

  • Committer: Sidnei da Silva
  • Date: 2009-11-16 00:51:29 UTC
  • mto: This revision was merged to the branch mainline in revision 154.
  • Revision ID: sidnei.da.silva@canonical.com-20091116005129-8ibwjlboa38glaw5
- Improved generation of skin modules and revamped combo service to make it more twisty.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3
 
Code licensed under the BSD License:
4
 
http://developer.yahoo.com/yui/license.html
5
 
version: 3.2.0
6
 
build: 2676
7
 
*/
8
 
YUI.add('async-queue', function(Y) {
9
 
 
10
 
/**
11
 
 * <p>AsyncQueue allows you create a chain of function callbacks executed
12
 
 * via setTimeout (or synchronously) that are guaranteed to run in order.
13
 
 * Items in the queue can be promoted or removed.  Start or resume the
14
 
 * execution chain with run().  pause() to temporarily delay execution, or
15
 
 * stop() to halt and clear the queue.</p>
16
 
 *
17
 
 * @module async-queue
18
 
 */
19
 
 
20
 
/**
21
 
 * <p>A specialized queue class that supports scheduling callbacks to execute
22
 
 * sequentially, iteratively, even asynchronously.</p>
23
 
 *
24
 
 * <p>Callbacks can be function refs or objects with the following keys.  Only
25
 
 * the <code>fn</code> key is required.</p>
26
 
 *
27
 
 * <ul>
28
 
 * <li><code>fn</code> -- The callback function</li>
29
 
 * <li><code>context</code> -- The execution context for the callbackFn.</li>
30
 
 * <li><code>args</code> -- Arguments to pass to callbackFn.</li>
31
 
 * <li><code>timeout</code> -- Millisecond delay before executing callbackFn.
32
 
 *                     (Applies to each iterative execution of callback)</li>
33
 
 * <li><code>iterations</code> -- Number of times to repeat the callback.
34
 
 * <li><code>until</code> -- Repeat the callback until this function returns
35
 
 *                         true.  This setting trumps iterations.</li>
36
 
 * <li><code>autoContinue</code> -- Set to false to prevent the AsyncQueue from
37
 
 *                        executing the next callback in the Queue after
38
 
 *                        the callback completes.</li>
39
 
 * <li><code>id</code> -- Name that can be used to get, promote, get the
40
 
 *                        indexOf, or delete this callback.</li>
41
 
 * </ul>
42
 
 *
43
 
 * @class AsyncQueue
44
 
 * @extends EventTarget
45
 
 * @constructor
46
 
 * @param callback* {Function|Object} 0..n callbacks to seed the queue
47
 
 */
48
 
Y.AsyncQueue = function() {
49
 
    this._init();
50
 
    this.add.apply(this, arguments);
51
 
};
52
 
 
53
 
var Queue   = Y.AsyncQueue,
54
 
    EXECUTE = 'execute',
55
 
    SHIFT   = 'shift',
56
 
    PROMOTE = 'promote',
57
 
    REMOVE  = 'remove',
58
 
 
59
 
    isObject   = Y.Lang.isObject,
60
 
    isFunction = Y.Lang.isFunction;
61
 
 
62
 
/**
63
 
 * <p>Static default values used to populate callback configuration properties.
64
 
 * Preconfigured defaults include:</p>
65
 
 *
66
 
 * <ul>
67
 
 *  <li><code>autoContinue</code>: <code>true</code></li>
68
 
 *  <li><code>iterations</code>: 1</li>
69
 
 *  <li><code>timeout</code>: 10 (10ms between callbacks)</li>
70
 
 *  <li><code>until</code>: (function to run until iterations &lt;= 0)</li>
71
 
 * </ul>
72
 
 *
73
 
 * @property AsyncQueue.defaults
74
 
 * @type {Object}
75
 
 * @static
76
 
 */
77
 
Queue.defaults = Y.mix({
78
 
    autoContinue : true,
79
 
    iterations   : 1,
80
 
    timeout      : 10,
81
 
    until        : function () {
82
 
        this.iterations |= 0;
83
 
        return this.iterations <= 0;
84
 
    }
85
 
}, Y.config.queueDefaults || {});
86
 
 
87
 
Y.extend(Queue, Y.EventTarget, {
88
 
    /**
89
 
     * Used to indicate the queue is currently executing a callback.
90
 
     *
91
 
     * @property _running
92
 
     * @type {Boolean|Object} true for synchronous callback execution, the
93
 
     *                        return handle from Y.later for async callbacks.
94
 
     *                        Otherwise false.
95
 
     * @protected
96
 
     */
97
 
    _running : false,
98
 
 
99
 
    /**
100
 
     * Initializes the AsyncQueue instance properties and events.
101
 
     *
102
 
     * @method _init
103
 
     * @protected
104
 
     */
105
 
    _init : function () {
106
 
        Y.EventTarget.call(this, { emitFacade: true });
107
 
 
108
 
        this._q = [];
109
 
 
110
 
        /** 
111
 
         * Callback defaults for this instance.  Static defaults that are not
112
 
         * overridden are also included.
113
 
         *
114
 
         * @property defaults
115
 
         * @type {Object}
116
 
         */
117
 
        this.defaults = {};
118
 
 
119
 
        this._initEvents();
120
 
    },
121
 
 
122
 
    /**
123
 
     * Initializes the instance events.
124
 
     *
125
 
     * @method _initEvents
126
 
     * @protected
127
 
     */
128
 
    _initEvents : function () {
129
 
        this.publish({
130
 
            'execute' : { defaultFn : this._defExecFn,    emitFacade: true },
131
 
            'shift'   : { defaultFn : this._defShiftFn,   emitFacade: true },
132
 
            'add'     : { defaultFn : this._defAddFn,     emitFacade: true },
133
 
            'promote' : { defaultFn : this._defPromoteFn, emitFacade: true },
134
 
            'remove'  : { defaultFn : this._defRemoveFn,  emitFacade: true }
135
 
        });
136
 
    },
137
 
 
138
 
    /**
139
 
     * Returns the next callback needing execution.  If a callback is
140
 
     * configured to repeat via iterations or until, it will be returned until
141
 
     * the completion criteria is met.
142
 
     *
143
 
     * When the queue is empty, null is returned.
144
 
     *
145
 
     * @method next
146
 
     * @return {Function} the callback to execute
147
 
     */
148
 
    next : function () {
149
 
        var callback;
150
 
 
151
 
        while (this._q.length) {
152
 
            callback = this._q[0] = this._prepare(this._q[0]);
153
 
            if (callback && callback.until()) {
154
 
                this.fire(SHIFT, { callback: callback });
155
 
                callback = null;
156
 
            } else {
157
 
                break;
158
 
            }
159
 
        }
160
 
 
161
 
        return callback || null;
162
 
    },
163
 
 
164
 
    /**
165
 
     * Default functionality for the &quot;shift&quot; event.  Shifts the
166
 
     * callback stored in the event object's <em>callback</em> property from
167
 
     * the queue if it is the first item.
168
 
     *
169
 
     * @method _defShiftFn
170
 
     * @param e {Event} The event object
171
 
     * @protected
172
 
     */
173
 
    _defShiftFn : function (e) {
174
 
        if (this.indexOf(e.callback) === 0) {
175
 
            this._q.shift();
176
 
        }
177
 
    },
178
 
 
179
 
    /**
180
 
     * Creates a wrapper function to execute the callback using the aggregated 
181
 
     * configuration generated by combining the static AsyncQueue.defaults, the
182
 
     * instance defaults, and the specified callback settings.
183
 
     *
184
 
     * The wrapper function is decorated with the callback configuration as
185
 
     * properties for runtime modification.
186
 
     *
187
 
     * @method _prepare
188
 
     * @param callback {Object|Function} the raw callback
189
 
     * @return {Function} a decorated function wrapper to execute the callback
190
 
     * @protected
191
 
     */
192
 
    _prepare: function (callback) {
193
 
        if (isFunction(callback) && callback._prepared) {
194
 
            return callback;
195
 
        }
196
 
 
197
 
        var config = Y.merge(
198
 
            Queue.defaults,
199
 
            { context : this, args: [], _prepared: true },
200
 
            this.defaults,
201
 
            (isFunction(callback) ? { fn: callback } : callback)),
202
 
            
203
 
            wrapper = Y.bind(function () {
204
 
                if (!wrapper._running) {
205
 
                    wrapper.iterations--;
206
 
                }
207
 
                if (isFunction(wrapper.fn)) {
208
 
                    wrapper.fn.apply(wrapper.context || Y,
209
 
                                     Y.Array(wrapper.args));
210
 
                }
211
 
            }, this);
212
 
            
213
 
        return Y.mix(wrapper, config);
214
 
    },
215
 
 
216
 
    /**
217
 
     * Sets the queue in motion.  All queued callbacks will be executed in
218
 
     * order unless pause() or stop() is called or if one of the callbacks is
219
 
     * configured with autoContinue: false.
220
 
     *
221
 
     * @method run
222
 
     * @return {AsyncQueue} the AsyncQueue instance
223
 
     * @chainable
224
 
     */
225
 
    run : function () {
226
 
        var callback,
227
 
            cont = true;
228
 
 
229
 
        for (callback = this.next();
230
 
            cont && callback && !this.isRunning();
231
 
            callback = this.next())
232
 
        {
233
 
            cont = (callback.timeout < 0) ?
234
 
                this._execute(callback) :
235
 
                this._schedule(callback);
236
 
        }
237
 
 
238
 
        if (!callback) {
239
 
            /**
240
 
             * Event fired after the last queued callback is executed.
241
 
             * @event complete
242
 
             */
243
 
            this.fire('complete');
244
 
        }
245
 
 
246
 
        return this;
247
 
    },
248
 
 
249
 
    /**
250
 
     * Handles the execution of callbacks. Returns a boolean indicating
251
 
     * whether it is appropriate to continue running.
252
 
     *
253
 
     * @method _execute
254
 
     * @param callback {Object} the callback object to execute
255
 
     * @return {Boolean} whether the run loop should continue
256
 
     * @protected
257
 
     */
258
 
    _execute : function (callback) {
259
 
        this._running = callback._running = true;
260
 
 
261
 
        callback.iterations--;
262
 
        this.fire(EXECUTE, { callback: callback });
263
 
 
264
 
        var cont = this._running && callback.autoContinue;
265
 
 
266
 
        this._running = callback._running = false;
267
 
 
268
 
        return cont;
269
 
    },
270
 
 
271
 
    /**
272
 
     * Schedules the execution of asynchronous callbacks.
273
 
     *
274
 
     * @method _schedule
275
 
     * @param callback {Object} the callback object to execute
276
 
     * @return {Boolean} whether the run loop should continue
277
 
     * @protected
278
 
     */
279
 
    _schedule : function (callback) {
280
 
        this._running = Y.later(callback.timeout, this, function () {
281
 
            if (this._execute(callback)) {
282
 
                this.run();
283
 
            }
284
 
        });
285
 
 
286
 
        return false;
287
 
    },
288
 
 
289
 
    /**
290
 
     * Determines if the queue is waiting for a callback to complete execution.
291
 
     *
292
 
     * @method isRunning
293
 
     * @return {Boolean} true if queue is waiting for a 
294
 
     *                   from any initiated transactions
295
 
     */
296
 
    isRunning : function () {
297
 
        return !!this._running;
298
 
    },
299
 
 
300
 
    /**
301
 
     * Default functionality for the &quot;execute&quot; event.  Executes the
302
 
     * callback function
303
 
     *
304
 
     * @method _defExecFn
305
 
     * @param e {Event} the event object
306
 
     * @protected
307
 
     */
308
 
    _defExecFn : function (e) {
309
 
        e.callback();
310
 
    },
311
 
 
312
 
    /**
313
 
     * Add any number of callbacks to the end of the queue. Callbacks may be
314
 
     * provided as functions or objects.
315
 
     *
316
 
     * @method add
317
 
     * @param callback* {Function|Object} 0..n callbacks
318
 
     * @return {AsyncQueue} the AsyncQueue instance
319
 
     * @chainable
320
 
     */
321
 
    add : function () {
322
 
        this.fire('add', { callbacks: Y.Array(arguments,0,true) });
323
 
 
324
 
        return this;
325
 
    },
326
 
 
327
 
    /**
328
 
     * Default functionality for the &quot;add&quot; event.  Adds the callbacks
329
 
     * in the event facade to the queue. Callbacks successfully added to the
330
 
     * queue are present in the event's <code>added</code> property in the
331
 
     * after phase.
332
 
     *
333
 
     * @method _defAddFn
334
 
     * @param e {Event} the event object
335
 
     * @protected
336
 
     */
337
 
    _defAddFn : function(e) {
338
 
        var _q = this._q,
339
 
            added = [];
340
 
 
341
 
        Y.Array.each(e.callbacks, function (c) {
342
 
            if (isObject(c)) {
343
 
                _q.push(c);
344
 
                added.push(c);
345
 
            }
346
 
        });
347
 
 
348
 
        e.added = added;
349
 
    },
350
 
 
351
 
    /**
352
 
     * Pause the execution of the queue after the execution of the current
353
 
     * callback completes.  If called from code outside of a queued callback,
354
 
     * clears the timeout for the pending callback. Paused queue can be
355
 
     * restarted with q.run()
356
 
     *
357
 
     * @method pause
358
 
     * @return {AsyncQueue} the AsyncQueue instance
359
 
     * @chainable
360
 
     */
361
 
    pause: function () {
362
 
        if (isObject(this._running)) {
363
 
            this._running.cancel();
364
 
        }
365
 
 
366
 
        this._running = false;
367
 
 
368
 
        return this;
369
 
    },
370
 
 
371
 
    /**
372
 
     * Stop and clear the queue after the current execution of the
373
 
     * current callback completes.
374
 
     *
375
 
     * @method stop
376
 
     * @return {AsyncQueue} the AsyncQueue instance
377
 
     * @chainable
378
 
     */
379
 
    stop : function () { 
380
 
        this._q = [];
381
 
 
382
 
        return this.pause();
383
 
    },
384
 
 
385
 
    /** 
386
 
     * Returns the current index of a callback.  Pass in either the id or
387
 
     * callback function from getCallback.
388
 
     *
389
 
     * @method indexOf
390
 
     * @param callback {String|Function} the callback or its specified id
391
 
     * @return {Number} index of the callback or -1 if not found
392
 
     */
393
 
    indexOf : function (callback) {
394
 
        var i = 0, len = this._q.length, c;
395
 
 
396
 
        for (; i < len; ++i) {
397
 
            c = this._q[i];
398
 
            if (c === callback || c.id === callback) {
399
 
                return i;
400
 
            }
401
 
        }
402
 
 
403
 
        return -1;
404
 
    },
405
 
 
406
 
    /**
407
 
     * Retrieve a callback by its id.  Useful to modify the configuration
408
 
     * while the queue is running.
409
 
     *
410
 
     * @method getCallback
411
 
     * @param id {String} the id assigned to the callback
412
 
     * @return {Object} the callback object
413
 
     */
414
 
    getCallback : function (id) {
415
 
        var i = this.indexOf(id);
416
 
 
417
 
        return (i > -1) ? this._q[i] : null;
418
 
    },
419
 
 
420
 
    /**
421
 
     * Promotes the named callback to the top of the queue. If a callback is
422
 
     * currently executing or looping (via until or iterations), the promotion
423
 
     * is scheduled to occur after the current callback has completed.
424
 
     *
425
 
     * @method promote
426
 
     * @param callback {String|Object} the callback object or a callback's id
427
 
     * @return {AsyncQueue} the AsyncQueue instance
428
 
     * @chainable
429
 
     */
430
 
    promote : function (callback) {
431
 
        var payload = { callback : callback },e;
432
 
 
433
 
        if (this.isRunning()) {
434
 
            e = this.after(SHIFT, function () {
435
 
                    this.fire(PROMOTE, payload);
436
 
                    e.detach();
437
 
                }, this);
438
 
        } else {
439
 
            this.fire(PROMOTE, payload);
440
 
        }
441
 
 
442
 
        return this;
443
 
    },
444
 
 
445
 
    /**
446
 
     * <p>Default functionality for the &quot;promote&quot; event.  Promotes the
447
 
     * named callback to the head of the queue.</p>
448
 
     *
449
 
     * <p>The event object will contain a property &quot;callback&quot;, which
450
 
     * holds the id of a callback or the callback object itself.</p>
451
 
     *
452
 
     * @method _defPromoteFn
453
 
     * @param e {Event} the custom event
454
 
     * @protected
455
 
     */
456
 
    _defPromoteFn : function (e) {
457
 
        var i = this.indexOf(e.callback),
458
 
            promoted = (i > -1) ? this._q.splice(i,1)[0] : null;
459
 
 
460
 
        e.promoted = promoted;
461
 
 
462
 
        if (promoted) {
463
 
            this._q.unshift(promoted);
464
 
        }
465
 
    },
466
 
 
467
 
    /**
468
 
     * Removes the callback from the queue.  If the queue is active, the
469
 
     * removal is scheduled to occur after the current callback has completed.
470
 
     *
471
 
     * @method remove
472
 
     * @param callback {String|Object} the callback object or a callback's id
473
 
     * @return {AsyncQueue} the AsyncQueue instance
474
 
     * @chainable
475
 
     */
476
 
    remove : function (callback) {
477
 
        var payload = { callback : callback },e;
478
 
 
479
 
        // Can't return the removed callback because of the deferral until
480
 
        // current callback is complete
481
 
        if (this.isRunning()) {
482
 
            e = this.after(SHIFT, function () {
483
 
                    this.fire(REMOVE, payload);
484
 
                    e.detach();
485
 
                },this);
486
 
        } else {
487
 
            this.fire(REMOVE, payload);
488
 
        }
489
 
 
490
 
        return this;
491
 
    },
492
 
 
493
 
    /**
494
 
     * <p>Default functionality for the &quot;remove&quot; event.  Removes the
495
 
     * callback from the queue.</p>
496
 
     *
497
 
     * <p>The event object will contain a property &quot;callback&quot;, which
498
 
     * holds the id of a callback or the callback object itself.</p>
499
 
     *
500
 
     * @method _defRemoveFn
501
 
     * @param e {Event} the custom event
502
 
     * @protected
503
 
     */
504
 
    _defRemoveFn : function (e) {
505
 
        var i = this.indexOf(e.callback);
506
 
 
507
 
        e.removed = (i > -1) ? this._q.splice(i,1)[0] : null;
508
 
    },
509
 
 
510
 
    /**
511
 
     * Returns the number of callbacks in the queue.
512
 
     *
513
 
     * @method size
514
 
     * @return {Number}
515
 
     */
516
 
    size : function () {
517
 
        // next() flushes callbacks that have met their until() criteria and
518
 
        // therefore shouldn't count since they wouldn't execute anyway.
519
 
        if (!this.isRunning()) {
520
 
            this.next();
521
 
        }
522
 
 
523
 
        return this._q.length;
524
 
    }
525
 
});
526
 
 
527
 
 
528
 
 
529
 
}, '3.2.0' ,{requires:['event-custom']});