From 19aa1169bfea493e58f39b32f1d60144d7a0bd07 Mon Sep 17 00:00:00 2001 From: dsc Date: Tue, 24 Apr 2012 12:55:04 -0700 Subject: [PATCH] Adds auto-triggering on-ready-registrations. --- lib/base/base-mixin.co | 49 +++++++++++++++++++++++ lib/util/wait-event.co | 101 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 0 deletions(-) create mode 100644 lib/util/wait-event.co diff --git a/lib/base/base-mixin.co b/lib/base/base-mixin.co index 93385b5..fd10c59 100644 --- a/lib/base/base-mixin.co +++ b/lib/base/base-mixin.co @@ -29,6 +29,55 @@ BaseBackboneMixin = exports.BaseBackboneMixin = + + ### Events + + /** + * Whether we're ready. + * @type Boolean + */ + ready : false + + + /** + * Triggers the 'ready' event if it has not yet been triggered. + * Subsequent listeners added to this event will be auto-triggered. + * @returns {this} + */ + triggerReady: -> + return this if @ready + @ready = true + @trigger 'ready', this + this + + /** + * Resets the 'ready' event to its non-triggered state, firing the + */ + resetReady: -> + return this unless @ready + @ready = false + @trigger 'ready-reset', this + this + + /** + * Wrap {@link Backbone.Event#on} registration to handle registrations + * on 'ready' after we've broadcast the event. Handler will always still + * be registered, however, in case the emitter is reset. + * + * @param {String} events Space-separated events for which to register. + * @param {Function} callback + * @param {Object} [context] + * @returns {this} + */ + on: (events, callback, context) -> + return this if not callback + Backbone.Events.on ... + if @ready and _.contains events.split(/\s+/), 'ready' + callback.call context or this, this + this + + + ### Synchronization /** diff --git a/lib/util/wait-event.co b/lib/util/wait-event.co new file mode 100644 index 0000000..96e2009 --- /dev/null +++ b/lib/util/wait-event.co @@ -0,0 +1,101 @@ +{EventEmitter} = require 'events' + + +/** + * @class An EventEmitter with a ratchet-up waiting counter. + */ +class exports.WaitingEmitter extends EventEmitter + + /** + * Count of outstanding tasks. + * @type Number + */ + waitingOn : 0 + + + /** + * Increment the waiting task counter. + * @returns {this} + */ + wait: -> + count = @waitingOn + @waitingOn += 1 + # console.log "#this.wait! #count --> #{@waitingOn}" + # console.trace() + @trigger('start-waiting', this) if count is 0 and @waitingOn > 0 + this + + /** + * Decrement the waiting task counter. + * @returns {this} + */ + unwait: -> + count = @waitingOn + @waitingOn -= 1 + # console.warn "#this.unwait! #{@waitingOn} < 0" if @waitingOn < 0 + # console.log "#this.unwait! #count --> #{@waitingOn}" + # console.trace() + @trigger('stop-waiting', this) if @waitingOn is 0 and count > 0 + this + + /** + * @param {Function} fn Function to wrap. + * @returns {Function} A function wrapping the passed function with a call + * to `unwait()`, then delegating with current context and arguments. + */ + unwaitAnd: (fn) -> + self = this + -> + # console.log "#self.unwaitAnd( function #{fn.name or fn.displayName}() )" + # console.trace() + self.unwait(); fn ... + + + +/** + * @class An EventEmitter that auto-triggers new handlers once "ready". + */ +class exports.ReadyEmitter extends EventEmitter + readyEventName : 'ready' + ready : false + + /** + * Triggers the 'ready' event if it has not yet been triggered. + * Subsequent listeners added to this event will be auto-triggered. + * @returns {this} + */ + triggerReady: -> + return this if @ready + @ready = true + @emit @readyEventName, this + this + + /** + * Resets the 'ready' event to its non-triggered state, firing the + */ + resetReady: -> + return this unless @ready + @ready = false + @emit "#{@readyEventName}-reset", this + this + + + /** + * Wrap {@link EventEmitter#on} registration to handle registrations + * on 'ready' after we've broadcast the event. Handler will always still + * be registered, however, in case the emitter is reset. + * + * @param {String} events Space-separated events for which to register. + * @param {Function} callback + * @param {Object} [context] + * @returns {this} + */ + on: (events, callback, context) -> + return this if not callback + super ... + if @ready and _.contains events.split(/\s+/), @readyEventName + callback.call context or this, this + this + + + -- 1.7.0.4