Skip to content

Commit 9a7cc14

Browse files
committed
fix and 🔒 triggerHandlers for ".once" handlers
1 parent 02a85bf commit 9a7cc14

File tree

2 files changed

+48
-17
lines changed

2 files changed

+48
-17
lines changed

Diff for: src/lib/events.js

+29-17
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ var Events = {
5858
plotObj.removeAllListeners = ev.removeAllListeners.bind(ev);
5959

6060
/*
61-
* Create funtions for managing internal events. These are *only* triggered
61+
* Create functions for managing internal events. These are *only* triggered
6262
* by the mirroring of external events via the emit function.
6363
*/
6464
plotObj._internalOn = internalEv.on.bind(internalEv);
@@ -93,6 +93,7 @@ var Events = {
9393
triggerHandler: function(plotObj, event, data) {
9494
var jQueryHandlerValue;
9595
var nodeEventHandlerValue;
96+
9697
/*
9798
* If jQuery exists run all its handlers for this event and
9899
* collect the return value of the LAST handler function
@@ -110,30 +111,41 @@ var Events = {
110111
var handlers = ev._events[event];
111112
if(!handlers) return jQueryHandlerValue;
112113

113-
/*
114-
* handlers can be function or an array of functions
115-
*/
116-
if(typeof handlers === 'function') handlers = [handlers];
117-
var lastHandler = handlers.pop();
118-
119-
/*
120-
* Call all the handlers except the last one.
121-
*/
122-
for(var i = 0; i < handlers.length; i++) {
123-
handlers[i](data);
114+
// making sure 'this' is the EventEmitter instance
115+
function apply(handler) {
116+
// The 'once' case, we can't just call handler() as we need
117+
// the return value here. So,
118+
// - remove handler
119+
// - call listener and grab return value!
120+
// - stash 'fired' key to not call handler twice
121+
if(handler.listener) {
122+
ev.removeListener(event, handler.listener);
123+
if(!handler.fired) {
124+
handler.fired = true;
125+
return handler.listener.apply(ev, [data]);
126+
}
127+
} else {
128+
return handler.apply(ev, [data]);
129+
}
124130
}
125131

126-
/*
127-
* Now call the final handler and collect its value
128-
*/
129-
nodeEventHandlerValue = lastHandler(data);
132+
// handlers can be function or an array of functions
133+
handlers = Array.isArray(handlers) ? handlers : [handlers];
134+
135+
var i;
136+
for(i = 0; i < handlers.length - 1; i++) {
137+
apply(handlers[i]);
138+
}
139+
// now call the final handler and collect its value
140+
nodeEventHandlerValue = apply(handlers[i]);
130141

131142
/*
132143
* Return either the jQuery handler value if it exists or the
133144
* nodeEventHandler value. jQuery event value supersedes nodejs
134145
* events for backwards compatibility reasons.
135146
*/
136-
return jQueryHandlerValue !== undefined ? jQueryHandlerValue :
147+
return jQueryHandlerValue !== undefined ?
148+
jQueryHandlerValue :
137149
nodeEventHandlerValue;
138150
},
139151

Diff for: test/jasmine/tests/events_test.js

+19
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,25 @@ describe('Events', function() {
220220
expect(eventBaton).toBe(3);
221221
expect(result).toBe('pong');
222222
});
223+
224+
it('works with *once* event handlers', function() {
225+
var eventBaton = 0;
226+
227+
Events.init(plotDiv);
228+
229+
plotDiv.once('ping', function() {
230+
eventBaton++;
231+
return 'pong';
232+
});
233+
234+
var result = Events.triggerHandler(plotDiv, 'ping');
235+
expect(result).toBe('pong');
236+
expect(eventBaton).toBe(1);
237+
238+
var nop = Events.triggerHandler(plotDiv, 'ping');
239+
expect(nop).toBeUndefined();
240+
expect(eventBaton).toBe(1);
241+
});
223242
});
224243

225244
describe('purge', function() {

0 commit comments

Comments
 (0)