-
Notifications
You must be signed in to change notification settings - Fork 282
/
event_emitter.coffee
115 lines (90 loc) · 2.96 KB
/
event_emitter.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# EventEmitter with support for catch-all listeners and mixin
# TODO: Write tests
###
# Usage
Extend EventEmitterModule class to use its features.
EventEmitterModule = require './event_emitter'
class MyClass extends EventEmitterModule
obj = new MyClass
obj.on 'testevent', (a, b, c) ->
console.log "received testevent a=#{a} b=#{b} c=#{c}"
obj.onAny (eventName, data...) ->
console.log "received by onAny: eventName=#{eventName} data=#{data}"
obj.emit 'testevent', 111, 222, 333
obj.emit 'anotherevent', 'hello'
Alternatively, you can add EventEmitterModule features to
an existing class with `mixin`.
class MyClass
# Add EventEmitterModule features to MyClass
EventEmitterModule.mixin MyClass
obj = new MyClass
obj.on 'testevent', ->
console.log "received testevent"
obj.emit 'testevent'
Also, EventEmitterModule can be injected dynamically into
an object, but with slightly worse performance.
class MyClass
constructor: ->
EventEmitterModule.inject this
obj = new MyClass
obj.on 'testevent', ->
console.log "received testevent"
obj.emit 'testevent'
###
class EventEmitterModule
# Apply EventEmitterModule to the class
@mixin: (cls) ->
proto = EventEmitterModule.prototype
for name in Object.getOwnPropertyNames(proto)
if name is 'constructor'
continue
try
cls::[name] = proto[name]
catch e
throw new Error "Call EventEmitterModule.mixin() after the class definition"
return
# Inject EventEmitterModule into the object
@inject: (obj) ->
proto = EventEmitterModule.prototype
for name in Object.getOwnPropertyNames(proto)
if name is 'constructor'
continue
obj[name] = proto[name]
obj.eventListeners = {}
obj.catchAllEventListeners = []
return
emit: (name, data...) ->
if @eventListeners?[name]?
for listener in @eventListeners[name]
listener data...
if @catchAllEventListeners?
for listener in @catchAllEventListeners
listener name, data...
return
onAny: (listener) ->
if @catchAllEventListeners?
@catchAllEventListeners.push listener
else
@catchAllEventListeners = [ listener ]
offAny: (listener) ->
if @catchAllEventListeners?
for _listener, i in @catchAllEventListeners
if _listener is listener
@catchAllEventListeners[i..i] = [] # remove element at index i
return
on: (name, listener) ->
if not @eventListeners?
@eventListeners = {}
if @eventListeners[name]?
@eventListeners[name].push listener
else
@eventListeners[name] = [ listener ]
removeListener: (name, listener) ->
if @eventListeners?[name]?
for _listener, i in @eventListeners[name]
if _listener is listener
@eventListeners[name][i..i] = [] # remove element at index i
return
off: (name, listener) ->
@removeListener arguments...
module.exports = EventEmitterModule