254 lines
9.5 KiB
JavaScript
254 lines
9.5 KiB
JavaScript
|
/**
|
||
|
* Copyright 2013-present, 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.
|
||
|
*
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
var _prodInvariant = require('./reactProdInvariant');
|
||
|
|
||
|
var invariant = require('fbjs/lib/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);
|
||
|
!(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;
|
||
|
if (EventPluginRegistry.plugins[pluginIndex]) {
|
||
|
continue;
|
||
|
}
|
||
|
!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;
|
||
|
EventPluginRegistry.plugins[pluginIndex] = pluginModule;
|
||
|
var publishedEvents = pluginModule.eventTypes;
|
||
|
for (var eventName in publishedEvents) {
|
||
|
!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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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) {
|
||
|
!!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;
|
||
|
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) {
|
||
|
!!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;
|
||
|
EventPluginRegistry.registrationNameModules[registrationName] = pluginModule;
|
||
|
EventPluginRegistry.registrationNameDependencies[registrationName] = pluginModule.eventTypes[eventName].dependencies;
|
||
|
|
||
|
if (process.env.NODE_ENV !== 'production') {
|
||
|
var lowerCasedName = registrationName.toLowerCase();
|
||
|
EventPluginRegistry.possibleRegistrationNames[lowerCasedName] = registrationName;
|
||
|
|
||
|
if (registrationName === 'onDoubleClick') {
|
||
|
EventPluginRegistry.possibleRegistrationNames.ondblclick = registrationName;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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: {},
|
||
|
|
||
|
/**
|
||
|
* Mapping from lowercase registration names to the properly cased version,
|
||
|
* used to warn in the case of missing event handlers. Available
|
||
|
* only in __DEV__.
|
||
|
* @type {Object}
|
||
|
*/
|
||
|
possibleRegistrationNames: process.env.NODE_ENV !== 'production' ? {} : null,
|
||
|
// Trust the developer to only use possibleRegistrationNames in __DEV__
|
||
|
|
||
|
/**
|
||
|
* 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) {
|
||
|
!!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;
|
||
|
// 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) {
|
||
|
!!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;
|
||
|
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;
|
||
|
}
|
||
|
if (dispatchConfig.phasedRegistrationNames !== undefined) {
|
||
|
// pulling phasedRegistrationNames out of dispatchConfig helps Flow see
|
||
|
// that it is not undefined.
|
||
|
var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
|
||
|
|
||
|
for (var phase in phasedRegistrationNames) {
|
||
|
if (!phasedRegistrationNames.hasOwnProperty(phase)) {
|
||
|
continue;
|
||
|
}
|
||
|
var pluginModule = EventPluginRegistry.registrationNameModules[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];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (process.env.NODE_ENV !== 'production') {
|
||
|
var possibleRegistrationNames = EventPluginRegistry.possibleRegistrationNames;
|
||
|
for (var lowerCasedName in possibleRegistrationNames) {
|
||
|
if (possibleRegistrationNames.hasOwnProperty(lowerCasedName)) {
|
||
|
delete possibleRegistrationNames[lowerCasedName];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
module.exports = EventPluginRegistry;
|