-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
Copy pathevents.js
164 lines (137 loc) · 5.49 KB
/
events.js
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/**
* Copyright 2012-2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
/* global jQuery:false */
var EventEmitter = require('events').EventEmitter;
var Events = {
init: function(plotObj) {
/*
* If we have already instantiated an emitter for this plot
* return early.
*/
if(plotObj._ev instanceof EventEmitter) return plotObj;
var ev = new EventEmitter();
var internalEv = new EventEmitter();
/*
* Assign to plot._ev while we still live in a land
* where plot is a DOM element with stuff attached to it.
* In the future we can make plot the event emitter itself.
*/
plotObj._ev = ev;
/*
* Create a second event handler that will manage events *internally*.
* This allows parts of plotly to respond to thing like relayout without
* having to use the user-facing event handler. They cannot peacefully
* coexist on the same handler because a user invoking
* plotObj.removeAllListeners() would detach internal events, breaking
* plotly.
*/
plotObj._internalEv = internalEv;
/*
* Assign bound methods from the ev to the plot object. These methods
* will reference the 'this' of plot._ev even though they are methods
* of plot. This will keep the event machinery away from the plot object
* which currently is often a DOM element but presents an API that will
* continue to function when plot becomes an emitter. Not all EventEmitter
* methods have been bound to `plot` as some do not currently add value to
* the Plotly event API.
*/
plotObj.on = ev.on.bind(ev);
plotObj.once = ev.once.bind(ev);
plotObj.removeListener = ev.removeListener.bind(ev);
plotObj.removeAllListeners = ev.removeAllListeners.bind(ev);
/*
* Create funtions for managing internal events. These are *only* triggered
* by the mirroring of external events via the emit function.
*/
plotObj._internalOn = internalEv.on.bind(internalEv);
plotObj._internalOnce = internalEv.once.bind(internalEv);
plotObj._removeInternalListener = internalEv.removeListener.bind(internalEv);
plotObj._removeAllInternalListeners = internalEv.removeAllListeners.bind(internalEv);
/*
* We must wrap emit to continue to support JQuery events. The idea
* is to check to see if the user is using JQuery events, if they are
* we emit JQuery events to trigger user handlers as well as the EventEmitter
* events.
*/
plotObj.emit = function(event, data) {
if(typeof jQuery !== 'undefined') {
jQuery(plotObj).trigger(event, data);
}
ev.emit(event, data);
internalEv.emit(event, data);
};
return plotObj;
},
/*
* This function behaves like jQueries triggerHandler. It calls
* all handlers for a particular event and returns the return value
* of the LAST handler. This function also triggers jQuery's
* triggerHandler for backwards compatibility.
*
* Note: triggerHandler has been recommended for deprecation in v2.0.0,
* so the additional behavior of triggerHandler triggering internal events
* is deliberate excluded in order to avoid reinforcing more usage.
*/
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
*/
if(typeof jQuery !== 'undefined') {
jQueryHandlerValue = jQuery(plotObj).triggerHandler(event, data);
}
/*
* Now run all the node style event handlers
*/
var ev = plotObj._ev;
if(!ev) return jQueryHandlerValue;
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);
}
/*
* Now call the final handler and collect its value
*/
nodeEventHandlerValue = lastHandler(data);
/*
* Return either the jquery handler value if it exists or the
* nodeEventHandler value. Jquery event value superceeds nodejs
* events for backwards compatability reasons.
*/
return jQueryHandlerValue !== undefined ? jQueryHandlerValue :
nodeEventHandlerValue;
},
purge: function(plotObj) {
delete plotObj._ev;
delete plotObj.on;
delete plotObj.once;
delete plotObj.removeListener;
delete plotObj.removeAllListeners;
delete plotObj.emit;
delete plotObj._ev;
delete plotObj._internalEv;
delete plotObj._internalOn;
delete plotObj._internalOnce;
delete plotObj._removeInternalListener;
delete plotObj._removeAllInternalListeners;
return plotObj;
}
};
module.exports = Events;