UNPKG

7.95 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'use strict';
12
13var _prodInvariant = require('./reactProdInvariant');
14
15var ReactErrorUtils = require('./ReactErrorUtils');
16
17var invariant = require('fbjs/lib/invariant');
18var warning = require('fbjs/lib/warning');
19
20/**
21 * Injected dependencies:
22 */
23
24/**
25 * - `ComponentTree`: [required] Module that can convert between React instances
26 * and actual node references.
27 */
28var ComponentTree;
29var TreeTraversal;
30var injection = {
31 injectComponentTree: function (Injected) {
32 ComponentTree = Injected;
33 if (process.env.NODE_ENV !== 'production') {
34 process.env.NODE_ENV !== 'production' ? warning(Injected && Injected.getNodeFromInstance && Injected.getInstanceFromNode, 'EventPluginUtils.injection.injectComponentTree(...): Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.') : void 0;
35 }
36 },
37 injectTreeTraversal: function (Injected) {
38 TreeTraversal = Injected;
39 if (process.env.NODE_ENV !== 'production') {
40 process.env.NODE_ENV !== 'production' ? warning(Injected && Injected.isAncestor && Injected.getLowestCommonAncestor, 'EventPluginUtils.injection.injectTreeTraversal(...): Injected ' + 'module is missing isAncestor or getLowestCommonAncestor.') : void 0;
41 }
42 }
43};
44
45function isEndish(topLevelType) {
46 return topLevelType === 'topMouseUp' || topLevelType === 'topTouchEnd' || topLevelType === 'topTouchCancel';
47}
48
49function isMoveish(topLevelType) {
50 return topLevelType === 'topMouseMove' || topLevelType === 'topTouchMove';
51}
52function isStartish(topLevelType) {
53 return topLevelType === 'topMouseDown' || topLevelType === 'topTouchStart';
54}
55
56var validateEventDispatches;
57if (process.env.NODE_ENV !== 'production') {
58 validateEventDispatches = function (event) {
59 var dispatchListeners = event._dispatchListeners;
60 var dispatchInstances = event._dispatchInstances;
61
62 var listenersIsArr = Array.isArray(dispatchListeners);
63 var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0;
64
65 var instancesIsArr = Array.isArray(dispatchInstances);
66 var instancesLen = instancesIsArr ? dispatchInstances.length : dispatchInstances ? 1 : 0;
67
68 process.env.NODE_ENV !== 'production' ? warning(instancesIsArr === listenersIsArr && instancesLen === listenersLen, 'EventPluginUtils: Invalid `event`.') : void 0;
69 };
70}
71
72/**
73 * Dispatch the event to the listener.
74 * @param {SyntheticEvent} event SyntheticEvent to handle
75 * @param {boolean} simulated If the event is simulated (changes exn behavior)
76 * @param {function} listener Application-level callback
77 * @param {*} inst Internal component instance
78 */
79function executeDispatch(event, simulated, listener, inst) {
80 var type = event.type || 'unknown-event';
81 event.currentTarget = EventPluginUtils.getNodeFromInstance(inst);
82 if (simulated) {
83 ReactErrorUtils.invokeGuardedCallbackWithCatch(type, listener, event);
84 } else {
85 ReactErrorUtils.invokeGuardedCallback(type, listener, event);
86 }
87 event.currentTarget = null;
88}
89
90/**
91 * Standard/simple iteration through an event's collected dispatches.
92 */
93function executeDispatchesInOrder(event, simulated) {
94 var dispatchListeners = event._dispatchListeners;
95 var dispatchInstances = event._dispatchInstances;
96 if (process.env.NODE_ENV !== 'production') {
97 validateEventDispatches(event);
98 }
99 if (Array.isArray(dispatchListeners)) {
100 for (var i = 0; i < dispatchListeners.length; i++) {
101 if (event.isPropagationStopped()) {
102 break;
103 }
104 // Listeners and Instances are two parallel arrays that are always in sync.
105 executeDispatch(event, simulated, dispatchListeners[i], dispatchInstances[i]);
106 }
107 } else if (dispatchListeners) {
108 executeDispatch(event, simulated, dispatchListeners, dispatchInstances);
109 }
110 event._dispatchListeners = null;
111 event._dispatchInstances = null;
112}
113
114/**
115 * Standard/simple iteration through an event's collected dispatches, but stops
116 * at the first dispatch execution returning true, and returns that id.
117 *
118 * @return {?string} id of the first dispatch execution who's listener returns
119 * true, or null if no listener returned true.
120 */
121function executeDispatchesInOrderStopAtTrueImpl(event) {
122 var dispatchListeners = event._dispatchListeners;
123 var dispatchInstances = event._dispatchInstances;
124 if (process.env.NODE_ENV !== 'production') {
125 validateEventDispatches(event);
126 }
127 if (Array.isArray(dispatchListeners)) {
128 for (var i = 0; i < dispatchListeners.length; i++) {
129 if (event.isPropagationStopped()) {
130 break;
131 }
132 // Listeners and Instances are two parallel arrays that are always in sync.
133 if (dispatchListeners[i](event, dispatchInstances[i])) {
134 return dispatchInstances[i];
135 }
136 }
137 } else if (dispatchListeners) {
138 if (dispatchListeners(event, dispatchInstances)) {
139 return dispatchInstances;
140 }
141 }
142 return null;
143}
144
145/**
146 * @see executeDispatchesInOrderStopAtTrueImpl
147 */
148function executeDispatchesInOrderStopAtTrue(event) {
149 var ret = executeDispatchesInOrderStopAtTrueImpl(event);
150 event._dispatchInstances = null;
151 event._dispatchListeners = null;
152 return ret;
153}
154
155/**
156 * Execution of a "direct" dispatch - there must be at most one dispatch
157 * accumulated on the event or it is considered an error. It doesn't really make
158 * sense for an event with multiple dispatches (bubbled) to keep track of the
159 * return values at each dispatch execution, but it does tend to make sense when
160 * dealing with "direct" dispatches.
161 *
162 * @return {*} The return value of executing the single dispatch.
163 */
164function executeDirectDispatch(event) {
165 if (process.env.NODE_ENV !== 'production') {
166 validateEventDispatches(event);
167 }
168 var dispatchListener = event._dispatchListeners;
169 var dispatchInstance = event._dispatchInstances;
170 !!Array.isArray(dispatchListener) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'executeDirectDispatch(...): Invalid `event`.') : _prodInvariant('103') : void 0;
171 event.currentTarget = dispatchListener ? EventPluginUtils.getNodeFromInstance(dispatchInstance) : null;
172 var res = dispatchListener ? dispatchListener(event) : null;
173 event.currentTarget = null;
174 event._dispatchListeners = null;
175 event._dispatchInstances = null;
176 return res;
177}
178
179/**
180 * @param {SyntheticEvent} event
181 * @return {boolean} True iff number of dispatches accumulated is greater than 0.
182 */
183function hasDispatches(event) {
184 return !!event._dispatchListeners;
185}
186
187/**
188 * General utilities that are useful in creating custom Event Plugins.
189 */
190var EventPluginUtils = {
191 isEndish: isEndish,
192 isMoveish: isMoveish,
193 isStartish: isStartish,
194
195 executeDirectDispatch: executeDirectDispatch,
196 executeDispatchesInOrder: executeDispatchesInOrder,
197 executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
198 hasDispatches: hasDispatches,
199
200 getInstanceFromNode: function (node) {
201 return ComponentTree.getInstanceFromNode(node);
202 },
203 getNodeFromInstance: function (node) {
204 return ComponentTree.getNodeFromInstance(node);
205 },
206 isAncestor: function (a, b) {
207 return TreeTraversal.isAncestor(a, b);
208 },
209 getLowestCommonAncestor: function (a, b) {
210 return TreeTraversal.getLowestCommonAncestor(a, b);
211 },
212 getParentInstance: function (inst) {
213 return TreeTraversal.getParentInstance(inst);
214 },
215 traverseTwoPhase: function (target, fn, arg) {
216 return TreeTraversal.traverseTwoPhase(target, fn, arg);
217 },
218 traverseEnterLeave: function (from, to, fn, argFrom, argTo) {
219 return TreeTraversal.traverseEnterLeave(from, to, fn, argFrom, argTo);
220 },
221
222 injection: injection
223};
224
225module.exports = EventPluginUtils;
\No newline at end of file