UNPKG

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