Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80529 views
1
/**
2
* Copyright 2013-2015, Facebook, Inc.
3
* All rights reserved.
4
*
5
* This source code is licensed under the BSD-style license found in the
6
* LICENSE file in the root directory of this source tree. An additional grant
7
* of patent rights can be found in the PATENTS file in the same directory.
8
*
9
* @providesModule EventPluginHub
10
*/
11
12
'use strict';
13
14
var EventPluginRegistry = require("./EventPluginRegistry");
15
var EventPluginUtils = require("./EventPluginUtils");
16
17
var accumulateInto = require("./accumulateInto");
18
var forEachAccumulated = require("./forEachAccumulated");
19
var invariant = require("./invariant");
20
21
/**
22
* Internal store for event listeners
23
*/
24
var listenerBank = {};
25
26
/**
27
* Internal queue of events that have accumulated their dispatches and are
28
* waiting to have their dispatches executed.
29
*/
30
var eventQueue = null;
31
32
/**
33
* Dispatches an event and releases it back into the pool, unless persistent.
34
*
35
* @param {?object} event Synthetic event to be dispatched.
36
* @private
37
*/
38
var executeDispatchesAndRelease = function(event) {
39
if (event) {
40
var executeDispatch = EventPluginUtils.executeDispatch;
41
// Plugins can provide custom behavior when dispatching events.
42
var PluginModule = EventPluginRegistry.getPluginModuleForEvent(event);
43
if (PluginModule && PluginModule.executeDispatch) {
44
executeDispatch = PluginModule.executeDispatch;
45
}
46
EventPluginUtils.executeDispatchesInOrder(event, executeDispatch);
47
48
if (!event.isPersistent()) {
49
event.constructor.release(event);
50
}
51
}
52
};
53
54
/**
55
* - `InstanceHandle`: [required] Module that performs logical traversals of DOM
56
* hierarchy given ids of the logical DOM elements involved.
57
*/
58
var InstanceHandle = null;
59
60
function validateInstanceHandle() {
61
var valid =
62
InstanceHandle &&
63
InstanceHandle.traverseTwoPhase &&
64
InstanceHandle.traverseEnterLeave;
65
("production" !== process.env.NODE_ENV ? invariant(
66
valid,
67
'InstanceHandle not injected before use!'
68
) : invariant(valid));
69
}
70
71
/**
72
* This is a unified interface for event plugins to be installed and configured.
73
*
74
* Event plugins can implement the following properties:
75
*
76
* `extractEvents` {function(string, DOMEventTarget, string, object): *}
77
* Required. When a top-level event is fired, this method is expected to
78
* extract synthetic events that will in turn be queued and dispatched.
79
*
80
* `eventTypes` {object}
81
* Optional, plugins that fire events must publish a mapping of registration
82
* names that are used to register listeners. Values of this mapping must
83
* be objects that contain `registrationName` or `phasedRegistrationNames`.
84
*
85
* `executeDispatch` {function(object, function, string)}
86
* Optional, allows plugins to override how an event gets dispatched. By
87
* default, the listener is simply invoked.
88
*
89
* Each plugin that is injected into `EventsPluginHub` is immediately operable.
90
*
91
* @public
92
*/
93
var EventPluginHub = {
94
95
/**
96
* Methods for injecting dependencies.
97
*/
98
injection: {
99
100
/**
101
* @param {object} InjectedMount
102
* @public
103
*/
104
injectMount: EventPluginUtils.injection.injectMount,
105
106
/**
107
* @param {object} InjectedInstanceHandle
108
* @public
109
*/
110
injectInstanceHandle: function(InjectedInstanceHandle) {
111
InstanceHandle = InjectedInstanceHandle;
112
if ("production" !== process.env.NODE_ENV) {
113
validateInstanceHandle();
114
}
115
},
116
117
getInstanceHandle: function() {
118
if ("production" !== process.env.NODE_ENV) {
119
validateInstanceHandle();
120
}
121
return InstanceHandle;
122
},
123
124
/**
125
* @param {array} InjectedEventPluginOrder
126
* @public
127
*/
128
injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder,
129
130
/**
131
* @param {object} injectedNamesToPlugins Map from names to plugin modules.
132
*/
133
injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName
134
135
},
136
137
eventNameDispatchConfigs: EventPluginRegistry.eventNameDispatchConfigs,
138
139
registrationNameModules: EventPluginRegistry.registrationNameModules,
140
141
/**
142
* Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent.
143
*
144
* @param {string} id ID of the DOM element.
145
* @param {string} registrationName Name of listener (e.g. `onClick`).
146
* @param {?function} listener The callback to store.
147
*/
148
putListener: function(id, registrationName, listener) {
149
("production" !== process.env.NODE_ENV ? invariant(
150
!listener || typeof listener === 'function',
151
'Expected %s listener to be a function, instead got type %s',
152
registrationName, typeof listener
153
) : invariant(!listener || typeof listener === 'function'));
154
155
var bankForRegistrationName =
156
listenerBank[registrationName] || (listenerBank[registrationName] = {});
157
bankForRegistrationName[id] = listener;
158
},
159
160
/**
161
* @param {string} id ID of the DOM element.
162
* @param {string} registrationName Name of listener (e.g. `onClick`).
163
* @return {?function} The stored callback.
164
*/
165
getListener: function(id, registrationName) {
166
var bankForRegistrationName = listenerBank[registrationName];
167
return bankForRegistrationName && bankForRegistrationName[id];
168
},
169
170
/**
171
* Deletes a listener from the registration bank.
172
*
173
* @param {string} id ID of the DOM element.
174
* @param {string} registrationName Name of listener (e.g. `onClick`).
175
*/
176
deleteListener: function(id, registrationName) {
177
var bankForRegistrationName = listenerBank[registrationName];
178
if (bankForRegistrationName) {
179
delete bankForRegistrationName[id];
180
}
181
},
182
183
/**
184
* Deletes all listeners for the DOM element with the supplied ID.
185
*
186
* @param {string} id ID of the DOM element.
187
*/
188
deleteAllListeners: function(id) {
189
for (var registrationName in listenerBank) {
190
delete listenerBank[registrationName][id];
191
}
192
},
193
194
/**
195
* Allows registered plugins an opportunity to extract events from top-level
196
* native browser events.
197
*
198
* @param {string} topLevelType Record from `EventConstants`.
199
* @param {DOMEventTarget} topLevelTarget The listening component root node.
200
* @param {string} topLevelTargetID ID of `topLevelTarget`.
201
* @param {object} nativeEvent Native browser event.
202
* @return {*} An accumulation of synthetic events.
203
* @internal
204
*/
205
extractEvents: function(
206
topLevelType,
207
topLevelTarget,
208
topLevelTargetID,
209
nativeEvent) {
210
var events;
211
var plugins = EventPluginRegistry.plugins;
212
for (var i = 0, l = plugins.length; i < l; i++) {
213
// Not every plugin in the ordering may be loaded at runtime.
214
var possiblePlugin = plugins[i];
215
if (possiblePlugin) {
216
var extractedEvents = possiblePlugin.extractEvents(
217
topLevelType,
218
topLevelTarget,
219
topLevelTargetID,
220
nativeEvent
221
);
222
if (extractedEvents) {
223
events = accumulateInto(events, extractedEvents);
224
}
225
}
226
}
227
return events;
228
},
229
230
/**
231
* Enqueues a synthetic event that should be dispatched when
232
* `processEventQueue` is invoked.
233
*
234
* @param {*} events An accumulation of synthetic events.
235
* @internal
236
*/
237
enqueueEvents: function(events) {
238
if (events) {
239
eventQueue = accumulateInto(eventQueue, events);
240
}
241
},
242
243
/**
244
* Dispatches all synthetic events on the event queue.
245
*
246
* @internal
247
*/
248
processEventQueue: function() {
249
// Set `eventQueue` to null before processing it so that we can tell if more
250
// events get enqueued while processing.
251
var processingEventQueue = eventQueue;
252
eventQueue = null;
253
forEachAccumulated(processingEventQueue, executeDispatchesAndRelease);
254
("production" !== process.env.NODE_ENV ? invariant(
255
!eventQueue,
256
'processEventQueue(): Additional events were enqueued while processing ' +
257
'an event queue. Support for this has not yet been implemented.'
258
) : invariant(!eventQueue));
259
},
260
261
/**
262
* These are needed for tests only. Do not use!
263
*/
264
__purge: function() {
265
listenerBank = {};
266
},
267
268
__getListenerBank: function() {
269
return listenerBank;
270
}
271
272
};
273
274
module.exports = EventPluginHub;
275
276