Skip to content

Commit

Permalink
fix and 🔒 triggerHandlers for ".once" handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
etpinard committed May 1, 2018
1 parent 02a85bf commit 9a7cc14
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 17 deletions.
46 changes: 29 additions & 17 deletions src/lib/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ var Events = {
plotObj.removeAllListeners = ev.removeAllListeners.bind(ev);

/*
* Create funtions for managing internal events. These are *only* triggered
* Create functions for managing internal events. These are *only* triggered
* by the mirroring of external events via the emit function.
*/
plotObj._internalOn = internalEv.on.bind(internalEv);
Expand Down Expand Up @@ -93,6 +93,7 @@ var Events = {
triggerHandler: function(plotObj, event, data) {
var jQueryHandlerValue;
var nodeEventHandlerValue;

/*
* If jQuery exists run all its handlers for this event and
* collect the return value of the LAST handler function
Expand All @@ -110,30 +111,41 @@ var Events = {
var handlers = ev._events[event];
if(!handlers) return jQueryHandlerValue;

/*
* handlers can be function or an array of functions
*/
if(typeof handlers === 'function') handlers = [handlers];
var lastHandler = handlers.pop();

/*
* Call all the handlers except the last one.
*/
for(var i = 0; i < handlers.length; i++) {
handlers[i](data);
// making sure 'this' is the EventEmitter instance
function apply(handler) {
// The 'once' case, we can't just call handler() as we need
// the return value here. So,
// - remove handler
// - call listener and grab return value!
// - stash 'fired' key to not call handler twice
if(handler.listener) {
ev.removeListener(event, handler.listener);
if(!handler.fired) {
handler.fired = true;
return handler.listener.apply(ev, [data]);
}
} else {
return handler.apply(ev, [data]);
}
}

/*
* Now call the final handler and collect its value
*/
nodeEventHandlerValue = lastHandler(data);
// handlers can be function or an array of functions
handlers = Array.isArray(handlers) ? handlers : [handlers];

var i;
for(i = 0; i < handlers.length - 1; i++) {
apply(handlers[i]);
}
// now call the final handler and collect its value
nodeEventHandlerValue = apply(handlers[i]);

/*
* Return either the jQuery handler value if it exists or the
* nodeEventHandler value. jQuery event value supersedes nodejs
* events for backwards compatibility reasons.
*/
return jQueryHandlerValue !== undefined ? jQueryHandlerValue :
return jQueryHandlerValue !== undefined ?
jQueryHandlerValue :
nodeEventHandlerValue;
},

Expand Down
19 changes: 19 additions & 0 deletions test/jasmine/tests/events_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,25 @@ describe('Events', function() {
expect(eventBaton).toBe(3);
expect(result).toBe('pong');
});

it('works with *once* event handlers', function() {
var eventBaton = 0;

Events.init(plotDiv);

plotDiv.once('ping', function() {
eventBaton++;
return 'pong';
});

var result = Events.triggerHandler(plotDiv, 'ping');
expect(result).toBe('pong');
expect(eventBaton).toBe(1);

var nop = Events.triggerHandler(plotDiv, 'ping');
expect(nop).toBeUndefined();
expect(eventBaton).toBe(1);
});
});

describe('purge', function() {
Expand Down

0 comments on commit 9a7cc14

Please sign in to comment.