eventable.coffee

Eventable is a lightweight asynchronous replacement for node's EventEmitter which also runs beautifully in the browser.

class Eventable
	
	listeners: {}
	

emitter.on(name, listener(args..., [callback]))

Attach a listener to the "name" event, creating the event if it does not yet exist.

	
	on: (name, listener) ->
		
		@listeners[name] ||= []
		@listeners[name].push(listener)
	

emitter.emit(name, args..., callback)

Run all listeners attached under the "name" event with args. After they are all done executing, fire callback

	
	emit: (name, args..., callback = ->) ->
		

Create a callback to track the completion of async listeners.

		remaining = 1
		emitter = @
		listenerCallback = (err) ->
			if !--remaining || err
				callback(err)
		

Add the callback to the end of args

		args.push(listenerCallback)
		

Get all of listeners for the event

		listeners = @listeners[name]
		

Fire each listener. If the listener has the right number of args to be async, increment the number of expected async listeners.

		if listeners
			for listener in listeners
				if (listener.length >= args.length)
					remaining++
				listener.apply(this, args)
		

If there were no async listeners (or any that fired their callback syncronously) the final callback will never run. To circumvent this, we fire listenerCallback once always. You will notice above that remaining starts at 1 for this purpose.

		listenerCallback()

Export this class

module.exports = Eventable