You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
276 lines
8.7 KiB
276 lines
8.7 KiB
/** |
|
* Copyright 2013-2015, Facebook, Inc. |
|
* All rights reserved. |
|
* |
|
* This source code is licensed under the BSD-style license found in the |
|
* LICENSE file in the root directory of this source tree. An additional grant |
|
* of patent rights can be found in the PATENTS file in the same directory. |
|
* |
|
* @providesModule EventPluginRegistry |
|
* @typechecks static-only |
|
*/ |
|
|
|
'use strict'; |
|
|
|
var invariant = require("./invariant"); |
|
|
|
/** |
|
* Injectable ordering of event plugins. |
|
*/ |
|
var EventPluginOrder = null; |
|
|
|
/** |
|
* Injectable mapping from names to event plugin modules. |
|
*/ |
|
var namesToPlugins = {}; |
|
|
|
/** |
|
* Recomputes the plugin list using the injected plugins and plugin ordering. |
|
* |
|
* @private |
|
*/ |
|
function recomputePluginOrdering() { |
|
if (!EventPluginOrder) { |
|
// Wait until an `EventPluginOrder` is injected. |
|
return; |
|
} |
|
for (var pluginName in namesToPlugins) { |
|
var PluginModule = namesToPlugins[pluginName]; |
|
var pluginIndex = EventPluginOrder.indexOf(pluginName); |
|
("production" !== process.env.NODE_ENV ? invariant( |
|
pluginIndex > -1, |
|
'EventPluginRegistry: Cannot inject event plugins that do not exist in ' + |
|
'the plugin ordering, `%s`.', |
|
pluginName |
|
) : invariant(pluginIndex > -1)); |
|
if (EventPluginRegistry.plugins[pluginIndex]) { |
|
continue; |
|
} |
|
("production" !== process.env.NODE_ENV ? invariant( |
|
PluginModule.extractEvents, |
|
'EventPluginRegistry: Event plugins must implement an `extractEvents` ' + |
|
'method, but `%s` does not.', |
|
pluginName |
|
) : invariant(PluginModule.extractEvents)); |
|
EventPluginRegistry.plugins[pluginIndex] = PluginModule; |
|
var publishedEvents = PluginModule.eventTypes; |
|
for (var eventName in publishedEvents) { |
|
("production" !== process.env.NODE_ENV ? invariant( |
|
publishEventForPlugin( |
|
publishedEvents[eventName], |
|
PluginModule, |
|
eventName |
|
), |
|
'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', |
|
eventName, |
|
pluginName |
|
) : invariant(publishEventForPlugin( |
|
publishedEvents[eventName], |
|
PluginModule, |
|
eventName |
|
))); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Publishes an event so that it can be dispatched by the supplied plugin. |
|
* |
|
* @param {object} dispatchConfig Dispatch configuration for the event. |
|
* @param {object} PluginModule Plugin publishing the event. |
|
* @return {boolean} True if the event was successfully published. |
|
* @private |
|
*/ |
|
function publishEventForPlugin(dispatchConfig, PluginModule, eventName) { |
|
("production" !== process.env.NODE_ENV ? invariant( |
|
!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName), |
|
'EventPluginHub: More than one plugin attempted to publish the same ' + |
|
'event name, `%s`.', |
|
eventName |
|
) : invariant(!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName))); |
|
EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig; |
|
|
|
var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; |
|
if (phasedRegistrationNames) { |
|
for (var phaseName in phasedRegistrationNames) { |
|
if (phasedRegistrationNames.hasOwnProperty(phaseName)) { |
|
var phasedRegistrationName = phasedRegistrationNames[phaseName]; |
|
publishRegistrationName( |
|
phasedRegistrationName, |
|
PluginModule, |
|
eventName |
|
); |
|
} |
|
} |
|
return true; |
|
} else if (dispatchConfig.registrationName) { |
|
publishRegistrationName( |
|
dispatchConfig.registrationName, |
|
PluginModule, |
|
eventName |
|
); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
/** |
|
* Publishes a registration name that is used to identify dispatched events and |
|
* can be used with `EventPluginHub.putListener` to register listeners. |
|
* |
|
* @param {string} registrationName Registration name to add. |
|
* @param {object} PluginModule Plugin publishing the event. |
|
* @private |
|
*/ |
|
function publishRegistrationName(registrationName, PluginModule, eventName) { |
|
("production" !== process.env.NODE_ENV ? invariant( |
|
!EventPluginRegistry.registrationNameModules[registrationName], |
|
'EventPluginHub: More than one plugin attempted to publish the same ' + |
|
'registration name, `%s`.', |
|
registrationName |
|
) : invariant(!EventPluginRegistry.registrationNameModules[registrationName])); |
|
EventPluginRegistry.registrationNameModules[registrationName] = PluginModule; |
|
EventPluginRegistry.registrationNameDependencies[registrationName] = |
|
PluginModule.eventTypes[eventName].dependencies; |
|
} |
|
|
|
/** |
|
* Registers plugins so that they can extract and dispatch events. |
|
* |
|
* @see {EventPluginHub} |
|
*/ |
|
var EventPluginRegistry = { |
|
|
|
/** |
|
* Ordered list of injected plugins. |
|
*/ |
|
plugins: [], |
|
|
|
/** |
|
* Mapping from event name to dispatch config |
|
*/ |
|
eventNameDispatchConfigs: {}, |
|
|
|
/** |
|
* Mapping from registration name to plugin module |
|
*/ |
|
registrationNameModules: {}, |
|
|
|
/** |
|
* Mapping from registration name to event name |
|
*/ |
|
registrationNameDependencies: {}, |
|
|
|
/** |
|
* Injects an ordering of plugins (by plugin name). This allows the ordering |
|
* to be decoupled from injection of the actual plugins so that ordering is |
|
* always deterministic regardless of packaging, on-the-fly injection, etc. |
|
* |
|
* @param {array} InjectedEventPluginOrder |
|
* @internal |
|
* @see {EventPluginHub.injection.injectEventPluginOrder} |
|
*/ |
|
injectEventPluginOrder: function(InjectedEventPluginOrder) { |
|
("production" !== process.env.NODE_ENV ? invariant( |
|
!EventPluginOrder, |
|
'EventPluginRegistry: Cannot inject event plugin ordering more than ' + |
|
'once. You are likely trying to load more than one copy of React.' |
|
) : invariant(!EventPluginOrder)); |
|
// Clone the ordering so it cannot be dynamically mutated. |
|
EventPluginOrder = Array.prototype.slice.call(InjectedEventPluginOrder); |
|
recomputePluginOrdering(); |
|
}, |
|
|
|
/** |
|
* Injects plugins to be used by `EventPluginHub`. The plugin names must be |
|
* in the ordering injected by `injectEventPluginOrder`. |
|
* |
|
* Plugins can be injected as part of page initialization or on-the-fly. |
|
* |
|
* @param {object} injectedNamesToPlugins Map from names to plugin modules. |
|
* @internal |
|
* @see {EventPluginHub.injection.injectEventPluginsByName} |
|
*/ |
|
injectEventPluginsByName: function(injectedNamesToPlugins) { |
|
var isOrderingDirty = false; |
|
for (var pluginName in injectedNamesToPlugins) { |
|
if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { |
|
continue; |
|
} |
|
var PluginModule = injectedNamesToPlugins[pluginName]; |
|
if (!namesToPlugins.hasOwnProperty(pluginName) || |
|
namesToPlugins[pluginName] !== PluginModule) { |
|
("production" !== process.env.NODE_ENV ? invariant( |
|
!namesToPlugins[pluginName], |
|
'EventPluginRegistry: Cannot inject two different event plugins ' + |
|
'using the same name, `%s`.', |
|
pluginName |
|
) : invariant(!namesToPlugins[pluginName])); |
|
namesToPlugins[pluginName] = PluginModule; |
|
isOrderingDirty = true; |
|
} |
|
} |
|
if (isOrderingDirty) { |
|
recomputePluginOrdering(); |
|
} |
|
}, |
|
|
|
/** |
|
* Looks up the plugin for the supplied event. |
|
* |
|
* @param {object} event A synthetic event. |
|
* @return {?object} The plugin that created the supplied event. |
|
* @internal |
|
*/ |
|
getPluginModuleForEvent: function(event) { |
|
var dispatchConfig = event.dispatchConfig; |
|
if (dispatchConfig.registrationName) { |
|
return EventPluginRegistry.registrationNameModules[ |
|
dispatchConfig.registrationName |
|
] || null; |
|
} |
|
for (var phase in dispatchConfig.phasedRegistrationNames) { |
|
if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) { |
|
continue; |
|
} |
|
var PluginModule = EventPluginRegistry.registrationNameModules[ |
|
dispatchConfig.phasedRegistrationNames[phase] |
|
]; |
|
if (PluginModule) { |
|
return PluginModule; |
|
} |
|
} |
|
return null; |
|
}, |
|
|
|
/** |
|
* Exposed for unit testing. |
|
* @private |
|
*/ |
|
_resetEventPlugins: function() { |
|
EventPluginOrder = null; |
|
for (var pluginName in namesToPlugins) { |
|
if (namesToPlugins.hasOwnProperty(pluginName)) { |
|
delete namesToPlugins[pluginName]; |
|
} |
|
} |
|
EventPluginRegistry.plugins.length = 0; |
|
|
|
var eventNameDispatchConfigs = EventPluginRegistry.eventNameDispatchConfigs; |
|
for (var eventName in eventNameDispatchConfigs) { |
|
if (eventNameDispatchConfigs.hasOwnProperty(eventName)) { |
|
delete eventNameDispatchConfigs[eventName]; |
|
} |
|
} |
|
|
|
var registrationNameModules = EventPluginRegistry.registrationNameModules; |
|
for (var registrationName in registrationNameModules) { |
|
if (registrationNameModules.hasOwnProperty(registrationName)) { |
|
delete registrationNameModules[registrationName]; |
|
} |
|
} |
|
} |
|
|
|
}; |
|
|
|
module.exports = EventPluginRegistry;
|
|
|