Files
react/src/event/EventPluginRegistry.js
T
yungsters 279792f891 Fix EventPluginRegistry Unit Tests
Dumping the mock cache isn't dirying the modules, so we have to unit test a different way. If we can fix our unit test framework, we should revert this.

Also, I added strict mode to `EventPluginRegistry.js`.
2013-06-13 20:38:23 -07:00

231 lines
6.7 KiB
JavaScript

/**
* @providesModule EventPluginRegistry
* @typechecks
*/
"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);
invariant(
pluginIndex > -1,
'EventPluginRegistry: Cannot inject event plugins that do not exist in ' +
'the plugin ordering, `%s`.',
pluginName
);
if (EventPluginRegistry.plugins[pluginIndex]) {
continue;
}
invariant(
PluginModule.extractEvents,
'EventPluginRegistry: Event plugins must implement an `extractEvents` ' +
'method, but `%s` does not.',
pluginName
);
EventPluginRegistry.plugins[pluginIndex] = PluginModule;
var publishedEvents = PluginModule.abstractEventTypes;
for (var eventName in publishedEvents) {
invariant(
publishEventForPlugin(publishedEvents[eventName], PluginModule),
'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.',
eventName,
pluginName
);
}
}
}
/**
* 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) {
var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
if (phasedRegistrationNames) {
for (var phaseName in phasedRegistrationNames) {
if (phasedRegistrationNames.hasOwnProperty(phaseName)) {
var phasedRegistrationName = phasedRegistrationNames[phaseName];
publishRegistrationName(phasedRegistrationName, PluginModule);
}
}
return true;
} else if (dispatchConfig.registrationName) {
publishRegistrationName(dispatchConfig.registrationName, PluginModule);
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) {
invariant(
!EventPluginRegistry.registrationNames[registrationName],
'EventPluginHub: More than one plugin attempted to publish the same ' +
'registration name, `%s`.',
registrationName
);
EventPluginRegistry.registrationNames[registrationName] = PluginModule;
EventPluginRegistry.registrationNamesKeys.push(registrationName);
}
/**
* Registers plugins so that they can extract and dispatch events.
*
* @see {EventPluginHub}
*/
var EventPluginRegistry = {
/**
* Ordered list of injected plugins.
*/
plugins: [],
/**
* Mapping from registration names to plugin modules.
*/
registrationNames: {},
/**
* The keys of `registrationNames`.
*/
registrationNamesKeys: [],
/**
* 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) {
invariant(
!EventPluginOrder,
'EventPluginRegistry: Cannot inject event plugin ordering more than once.'
);
// 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[pluginName] !== PluginModule) {
invariant(
!namesToPlugins[pluginName],
'EventPluginRegistry: Cannot inject two different event plugins ' +
'using the same name, `%s`.',
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.reactEventType;
if (dispatchConfig.registrationName) {
return EventPluginRegistry.registrationNames[
dispatchConfig.registrationName
] || null;
}
for (var phase in dispatchConfig.phasedRegistrationNames) {
if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) {
continue;
}
var PluginModule = EventPluginRegistry.registrationNames[
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 registrationNames = EventPluginRegistry.registrationNames;
for (var registrationName in registrationNames) {
if (registrationNames.hasOwnProperty(registrationName)) {
delete registrationNames[registrationName];
}
}
EventPluginRegistry.registrationNamesKeys.length = 0;
}
};
module.exports = EventPluginRegistry;