UNPKG

9.62 kBJavaScriptView Raw
1/**
2 * Copyright (c) 2013-present, Facebook, Inc.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 *
8 */
9
10'use strict';
11
12var _prodInvariant = require('./reactProdInvariant');
13
14var invariant = require('fbjs/lib/invariant');
15
16/**
17 * Injectable ordering of event plugins.
18 */
19var eventPluginOrder = null;
20
21/**
22 * Injectable mapping from names to event plugin modules.
23 */
24var namesToPlugins = {};
25
26/**
27 * Recomputes the plugin list using the injected plugins and plugin ordering.
28 *
29 * @private
30 */
31function recomputePluginOrdering() {
32 if (!eventPluginOrder) {
33 // Wait until an `eventPluginOrder` is injected.
34 return;
35 }
36 for (var pluginName in namesToPlugins) {
37 var pluginModule = namesToPlugins[pluginName];
38 var pluginIndex = eventPluginOrder.indexOf(pluginName);
39 !(pluginIndex > -1) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `%s`.', pluginName) : _prodInvariant('96', pluginName) : void 0;
40 if (EventPluginRegistry.plugins[pluginIndex]) {
41 continue;
42 }
43 !pluginModule.extractEvents ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `%s` does not.', pluginName) : _prodInvariant('97', pluginName) : void 0;
44 EventPluginRegistry.plugins[pluginIndex] = pluginModule;
45 var publishedEvents = pluginModule.eventTypes;
46 for (var eventName in publishedEvents) {
47 !publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', eventName, pluginName) : _prodInvariant('98', eventName, pluginName) : void 0;
48 }
49 }
50}
51
52/**
53 * Publishes an event so that it can be dispatched by the supplied plugin.
54 *
55 * @param {object} dispatchConfig Dispatch configuration for the event.
56 * @param {object} PluginModule Plugin publishing the event.
57 * @return {boolean} True if the event was successfully published.
58 * @private
59 */
60function publishEventForPlugin(dispatchConfig, pluginModule, eventName) {
61 !!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.', eventName) : _prodInvariant('99', eventName) : void 0;
62 EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig;
63
64 var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
65 if (phasedRegistrationNames) {
66 for (var phaseName in phasedRegistrationNames) {
67 if (phasedRegistrationNames.hasOwnProperty(phaseName)) {
68 var phasedRegistrationName = phasedRegistrationNames[phaseName];
69 publishRegistrationName(phasedRegistrationName, pluginModule, eventName);
70 }
71 }
72 return true;
73 } else if (dispatchConfig.registrationName) {
74 publishRegistrationName(dispatchConfig.registrationName, pluginModule, eventName);
75 return true;
76 }
77 return false;
78}
79
80/**
81 * Publishes a registration name that is used to identify dispatched events and
82 * can be used with `EventPluginHub.putListener` to register listeners.
83 *
84 * @param {string} registrationName Registration name to add.
85 * @param {object} PluginModule Plugin publishing the event.
86 * @private
87 */
88function publishRegistrationName(registrationName, pluginModule, eventName) {
89 !!EventPluginRegistry.registrationNameModules[registrationName] ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.', registrationName) : _prodInvariant('100', registrationName) : void 0;
90 EventPluginRegistry.registrationNameModules[registrationName] = pluginModule;
91 EventPluginRegistry.registrationNameDependencies[registrationName] = pluginModule.eventTypes[eventName].dependencies;
92
93 if (process.env.NODE_ENV !== 'production') {
94 var lowerCasedName = registrationName.toLowerCase();
95 EventPluginRegistry.possibleRegistrationNames[lowerCasedName] = registrationName;
96
97 if (registrationName === 'onDoubleClick') {
98 EventPluginRegistry.possibleRegistrationNames.ondblclick = registrationName;
99 }
100 }
101}
102
103/**
104 * Registers plugins so that they can extract and dispatch events.
105 *
106 * @see {EventPluginHub}
107 */
108var EventPluginRegistry = {
109 /**
110 * Ordered list of injected plugins.
111 */
112 plugins: [],
113
114 /**
115 * Mapping from event name to dispatch config
116 */
117 eventNameDispatchConfigs: {},
118
119 /**
120 * Mapping from registration name to plugin module
121 */
122 registrationNameModules: {},
123
124 /**
125 * Mapping from registration name to event name
126 */
127 registrationNameDependencies: {},
128
129 /**
130 * Mapping from lowercase registration names to the properly cased version,
131 * used to warn in the case of missing event handlers. Available
132 * only in __DEV__.
133 * @type {Object}
134 */
135 possibleRegistrationNames: process.env.NODE_ENV !== 'production' ? {} : null,
136 // Trust the developer to only use possibleRegistrationNames in __DEV__
137
138 /**
139 * Injects an ordering of plugins (by plugin name). This allows the ordering
140 * to be decoupled from injection of the actual plugins so that ordering is
141 * always deterministic regardless of packaging, on-the-fly injection, etc.
142 *
143 * @param {array} InjectedEventPluginOrder
144 * @internal
145 * @see {EventPluginHub.injection.injectEventPluginOrder}
146 */
147 injectEventPluginOrder: function (injectedEventPluginOrder) {
148 !!eventPluginOrder ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React.') : _prodInvariant('101') : void 0;
149 // Clone the ordering so it cannot be dynamically mutated.
150 eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder);
151 recomputePluginOrdering();
152 },
153
154 /**
155 * Injects plugins to be used by `EventPluginHub`. The plugin names must be
156 * in the ordering injected by `injectEventPluginOrder`.
157 *
158 * Plugins can be injected as part of page initialization or on-the-fly.
159 *
160 * @param {object} injectedNamesToPlugins Map from names to plugin modules.
161 * @internal
162 * @see {EventPluginHub.injection.injectEventPluginsByName}
163 */
164 injectEventPluginsByName: function (injectedNamesToPlugins) {
165 var isOrderingDirty = false;
166 for (var pluginName in injectedNamesToPlugins) {
167 if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) {
168 continue;
169 }
170 var pluginModule = injectedNamesToPlugins[pluginName];
171 if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== pluginModule) {
172 !!namesToPlugins[pluginName] ? process.env.NODE_ENV !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.', pluginName) : _prodInvariant('102', pluginName) : void 0;
173 namesToPlugins[pluginName] = pluginModule;
174 isOrderingDirty = true;
175 }
176 }
177 if (isOrderingDirty) {
178 recomputePluginOrdering();
179 }
180 },
181
182 /**
183 * Looks up the plugin for the supplied event.
184 *
185 * @param {object} event A synthetic event.
186 * @return {?object} The plugin that created the supplied event.
187 * @internal
188 */
189 getPluginModuleForEvent: function (event) {
190 var dispatchConfig = event.dispatchConfig;
191 if (dispatchConfig.registrationName) {
192 return EventPluginRegistry.registrationNameModules[dispatchConfig.registrationName] || null;
193 }
194 if (dispatchConfig.phasedRegistrationNames !== undefined) {
195 // pulling phasedRegistrationNames out of dispatchConfig helps Flow see
196 // that it is not undefined.
197 var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
198
199 for (var phase in phasedRegistrationNames) {
200 if (!phasedRegistrationNames.hasOwnProperty(phase)) {
201 continue;
202 }
203 var pluginModule = EventPluginRegistry.registrationNameModules[phasedRegistrationNames[phase]];
204 if (pluginModule) {
205 return pluginModule;
206 }
207 }
208 }
209 return null;
210 },
211
212 /**
213 * Exposed for unit testing.
214 * @private
215 */
216 _resetEventPlugins: function () {
217 eventPluginOrder = null;
218 for (var pluginName in namesToPlugins) {
219 if (namesToPlugins.hasOwnProperty(pluginName)) {
220 delete namesToPlugins[pluginName];
221 }
222 }
223 EventPluginRegistry.plugins.length = 0;
224
225 var eventNameDispatchConfigs = EventPluginRegistry.eventNameDispatchConfigs;
226 for (var eventName in eventNameDispatchConfigs) {
227 if (eventNameDispatchConfigs.hasOwnProperty(eventName)) {
228 delete eventNameDispatchConfigs[eventName];
229 }
230 }
231
232 var registrationNameModules = EventPluginRegistry.registrationNameModules;
233 for (var registrationName in registrationNameModules) {
234 if (registrationNameModules.hasOwnProperty(registrationName)) {
235 delete registrationNameModules[registrationName];
236 }
237 }
238
239 if (process.env.NODE_ENV !== 'production') {
240 var possibleRegistrationNames = EventPluginRegistry.possibleRegistrationNames;
241 for (var lowerCasedName in possibleRegistrationNames) {
242 if (possibleRegistrationNames.hasOwnProperty(lowerCasedName)) {
243 delete possibleRegistrationNames[lowerCasedName];
244 }
245 }
246 }
247 }
248};
249
250module.exports = EventPluginRegistry;
\No newline at end of file