Skip to content

Commit e1c2d02

Browse files
petehuntzpao
authored andcommitted
Create ReactEventListener
Per our discussion friday, this creates ReactEventListener and renames variables to use the "handle" nomenclature.
1 parent a6cd945 commit e1c2d02

15 files changed

Lines changed: 348 additions & 282 deletions
Lines changed: 102 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,31 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*
16-
* @providesModule ReactEventEmitter
16+
* @providesModule ReactBrowserEventEmitter
1717
* @typechecks static-only
1818
*/
1919

2020
"use strict";
2121

2222
var EventConstants = require('EventConstants');
23-
var EventListener = require('EventListener');
2423
var EventPluginHub = require('EventPluginHub');
2524
var EventPluginRegistry = require('EventPluginRegistry');
26-
var ExecutionEnvironment = require('ExecutionEnvironment');
2725
var ReactEventEmitterMixin = require('ReactEventEmitterMixin');
2826
var ViewportMetrics = require('ViewportMetrics');
2927

30-
var invariant = require('invariant');
3128
var isEventSupported = require('isEventSupported');
3229
var merge = require('merge');
3330

3431
/**
35-
* Summary of `ReactEventEmitter` event handling:
32+
* Summary of `ReactBrowserEventEmitter` event handling:
3633
*
37-
* - Top-level delegation is used to trap native browser events. We normalize
38-
* and de-duplicate events to account for browser quirks.
34+
* - Top-level delegation is used to trap most native browser events. This
35+
* may only occur in the main thread and is the responsibility of
36+
* ReactEventListener, which is injected and can therefore support pluggable
37+
* event sources. This is the only work that occurs in the main thread.
38+
*
39+
* - We normalize and de-duplicate events to account for browser quirks. This
40+
* may be done in the worker thread.
3941
*
4042
* - Forward these native events (with the associated top-level type used to
4143
* trap it) to `EventPluginHub`, which in turn will ask plugins if they want
@@ -48,11 +50,16 @@ var merge = require('merge');
4850
*
4951
* Overview of React and the event system:
5052
*
51-
* .
5253
* +------------+ .
5354
* | DOM | .
55+
* +------------+ .
56+
* | .
57+
* v .
58+
* +------------+ .
59+
* | ReactEvent | .
60+
* | Listener | .
5461
* +------------+ . +-----------+
55-
* + . +--------+|SimpleEvent|
62+
* | . +--------+|SimpleEvent|
5663
* | . | |Plugin |
5764
* +-----|------+ . v +-----------+
5865
* | | | . +--------------+ +------------+
@@ -139,68 +146,31 @@ function getListeningForDocument(mountAt) {
139146
}
140147

141148
/**
142-
* Traps top-level events by using event bubbling.
149+
* `ReactBrowserEventEmitter` is used to attach top-level event listeners. For
150+
* example:
143151
*
144-
* @param {string} topLevelType Record from `EventConstants`.
145-
* @param {string} handlerBaseName Event name (e.g. "click").
146-
* @param {DOMEventTarget} element Element on which to attach listener.
147-
* @return {object} An object with a remove function which will forcefully
148-
* remove the listener.
149-
* @internal
150-
*/
151-
function trapBubbledEvent(topLevelType, handlerBaseName, element) {
152-
return EventListener.listen(
153-
element,
154-
handlerBaseName,
155-
ReactEventEmitter.TopLevelCallbackCreator.createTopLevelCallback(
156-
topLevelType
157-
)
158-
);
159-
}
160-
161-
/**
162-
* Traps a top-level event by using event capturing.
163-
*
164-
* @param {string} topLevelType Record from `EventConstants`.
165-
* @param {string} handlerBaseName Event name (e.g. "click").
166-
* @param {DOMEventTarget} element Element on which to attach listener.
167-
* @return {object} An object with a remove function which will forcefully
168-
* remove the listener.
169-
* @internal
170-
*/
171-
function trapCapturedEvent(topLevelType, handlerBaseName, element) {
172-
return EventListener.capture(
173-
element,
174-
handlerBaseName,
175-
ReactEventEmitter.TopLevelCallbackCreator.createTopLevelCallback(
176-
topLevelType
177-
)
178-
);
179-
}
180-
181-
/**
182-
* `ReactEventEmitter` is used to attach top-level event listeners. For example:
183-
*
184-
* ReactEventEmitter.putListener('myID', 'onClick', myFunction);
152+
* ReactBrowserEventEmitter.putListener('myID', 'onClick', myFunction);
185153
*
186154
* This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
187155
*
188156
* @internal
189157
*/
190-
var ReactEventEmitter = merge(ReactEventEmitterMixin, {
158+
var ReactBrowserEventEmitter = merge(ReactEventEmitterMixin, {
191159

192160
/**
193-
* React references `ReactEventTopLevelCallback` using this property in order
194-
* to allow dependency injection.
161+
* Injectable event backend
195162
*/
196-
TopLevelCallbackCreator: null,
163+
ReactEventListener: null,
197164

198165
injection: {
199166
/**
200-
* @param {function} TopLevelCallbackCreator
167+
* @param {object} ReactEventListener
201168
*/
202-
injectTopLevelCallbackCreator: function(TopLevelCallbackCreator) {
203-
ReactEventEmitter.TopLevelCallbackCreator = TopLevelCallbackCreator;
169+
injectReactEventListener: function(ReactEventListener) {
170+
ReactEventListener.setHandleTopLevel(
171+
ReactBrowserEventEmitter.handleTopLevel
172+
);
173+
ReactBrowserEventEmitter.ReactEventListener = ReactEventListener;
204174
}
205175
},
206176

@@ -210,13 +180,8 @@ var ReactEventEmitter = merge(ReactEventEmitterMixin, {
210180
* @param {boolean} enabled True if callbacks should be enabled.
211181
*/
212182
setEnabled: function(enabled) {
213-
invariant(
214-
ExecutionEnvironment.canUseDOM,
215-
'setEnabled(...): Cannot toggle event listening in a Worker thread. ' +
216-
'This is likely a bug in the framework. Please report immediately.'
217-
);
218-
if (ReactEventEmitter.TopLevelCallbackCreator) {
219-
ReactEventEmitter.TopLevelCallbackCreator.setEnabled(enabled);
183+
if (ReactBrowserEventEmitter.ReactEventListener) {
184+
ReactBrowserEventEmitter.ReactEventListener.setEnabled(enabled);
220185
}
221186
},
222187

@@ -225,8 +190,8 @@ var ReactEventEmitter = merge(ReactEventEmitterMixin, {
225190
*/
226191
isEnabled: function() {
227192
return !!(
228-
ReactEventEmitter.TopLevelCallbackCreator &&
229-
ReactEventEmitter.TopLevelCallbackCreator.isEnabled()
193+
ReactBrowserEventEmitter.ReactEventListener &&
194+
ReactBrowserEventEmitter.ReactEventListener.isEnabled()
230195
);
231196
},
232197

@@ -249,10 +214,10 @@ var ReactEventEmitter = merge(ReactEventEmitterMixin, {
249214
* they bubble to document.
250215
*
251216
* @param {string} registrationName Name of listener (e.g. `onClick`).
252-
* @param {DOMDocument} contentDocument Document which owns the container
217+
* @param {object} contentDocumentHandle Document which owns the container
253218
*/
254-
listenTo: function(registrationName, contentDocument) {
255-
var mountAt = contentDocument;
219+
listenTo: function(registrationName, contentDocumentHandle) {
220+
var mountAt = contentDocumentHandle;
256221
var isListening = getListeningForDocument(mountAt);
257222
var dependencies = EventPluginRegistry.
258223
registrationNameDependencies[registrationName];
@@ -268,49 +233,102 @@ var ReactEventEmitter = merge(ReactEventEmitterMixin, {
268233

269234
if (topLevelType === topLevelTypes.topWheel) {
270235
if (isEventSupported('wheel')) {
271-
trapBubbledEvent(topLevelTypes.topWheel, 'wheel', mountAt);
236+
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
237+
topLevelTypes.topWheel,
238+
'wheel',
239+
mountAt
240+
);
272241
} else if (isEventSupported('mousewheel')) {
273-
trapBubbledEvent(topLevelTypes.topWheel, 'mousewheel', mountAt);
242+
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
243+
topLevelTypes.topWheel,
244+
'mousewheel',
245+
mountAt
246+
);
274247
} else {
275248
// Firefox needs to capture a different mouse scroll event.
276249
// @see http://www.quirksmode.org/dom/events/tests/scroll.html
277-
trapBubbledEvent(
250+
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
278251
topLevelTypes.topWheel,
279252
'DOMMouseScroll',
280-
mountAt);
253+
mountAt
254+
);
281255
}
282256
} else if (topLevelType === topLevelTypes.topScroll) {
283257

284258
if (isEventSupported('scroll', true)) {
285-
trapCapturedEvent(topLevelTypes.topScroll, 'scroll', mountAt);
259+
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
260+
topLevelTypes.topScroll,
261+
'scroll',
262+
mountAt
263+
);
286264
} else {
287-
trapBubbledEvent(topLevelTypes.topScroll, 'scroll', window);
265+
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
266+
topLevelTypes.topScroll,
267+
'scroll',
268+
ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE
269+
);
288270
}
289271
} else if (topLevelType === topLevelTypes.topFocus ||
290272
topLevelType === topLevelTypes.topBlur) {
291273

292274
if (isEventSupported('focus', true)) {
293-
trapCapturedEvent(topLevelTypes.topFocus, 'focus', mountAt);
294-
trapCapturedEvent(topLevelTypes.topBlur, 'blur', mountAt);
275+
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
276+
topLevelTypes.topFocus,
277+
'focus',
278+
mountAt
279+
);
280+
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
281+
topLevelTypes.topBlur,
282+
'blur',
283+
mountAt
284+
);
295285
} else if (isEventSupported('focusin')) {
296286
// IE has `focusin` and `focusout` events which bubble.
297287
// @see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
298-
trapBubbledEvent(topLevelTypes.topFocus, 'focusin', mountAt);
299-
trapBubbledEvent(topLevelTypes.topBlur, 'focusout', mountAt);
288+
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
289+
topLevelTypes.topFocus,
290+
'focusin',
291+
mountAt
292+
);
293+
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
294+
topLevelTypes.topBlur,
295+
'focusout',
296+
mountAt
297+
);
300298
}
301299

302300
// to make sure blur and focus event listeners are only attached once
303301
isListening[topLevelTypes.topBlur] = true;
304302
isListening[topLevelTypes.topFocus] = true;
305303
} else if (topEventMapping.hasOwnProperty(dependency)) {
306-
trapBubbledEvent(topLevelType, topEventMapping[dependency], mountAt);
304+
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
305+
topLevelType,
306+
topEventMapping[dependency],
307+
mountAt
308+
);
307309
}
308310

309311
isListening[dependency] = true;
310312
}
311313
}
312314
},
313315

316+
trapBubbledEvent: function(topLevelType, handlerBaseName, handle) {
317+
return ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
318+
topLevelType,
319+
handlerBaseName,
320+
handle
321+
);
322+
},
323+
324+
trapCapturedEvent: function(topLevelType, handlerBaseName, handle) {
325+
return ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
326+
topLevelType,
327+
handlerBaseName,
328+
handle
329+
);
330+
},
331+
314332
/**
315333
* Listens to window scroll and resize events. We cache scroll values so that
316334
* application code can access them without triggering reflows.
@@ -322,8 +340,7 @@ var ReactEventEmitter = merge(ReactEventEmitterMixin, {
322340
ensureScrollValueMonitoring: function(){
323341
if (!isMonitoringScrollValue) {
324342
var refresh = ViewportMetrics.refreshScrollValues;
325-
EventListener.listen(window, 'scroll', refresh);
326-
EventListener.listen(window, 'resize', refresh);
343+
ReactBrowserEventEmitter.ReactEventListener.monitorScrollValue(refresh);
327344
isMonitoringScrollValue = true;
328345
}
329346
},
@@ -338,12 +355,8 @@ var ReactEventEmitter = merge(ReactEventEmitterMixin, {
338355

339356
deleteListener: EventPluginHub.deleteListener,
340357

341-
deleteAllListeners: EventPluginHub.deleteAllListeners,
342-
343-
trapBubbledEvent: trapBubbledEvent,
344-
345-
trapCapturedEvent: trapCapturedEvent
358+
deleteAllListeners: EventPluginHub.deleteAllListeners
346359

347360
});
348361

349-
module.exports = ReactEventEmitter;
362+
module.exports = ReactBrowserEventEmitter;

src/browser/ReactPutListenerQueue.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"use strict";
2020

2121
var PooledClass = require('PooledClass');
22-
var ReactEventEmitter = require('ReactEventEmitter');
22+
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
2323

2424
var mixInto = require('mixInto');
2525

@@ -39,7 +39,7 @@ mixInto(ReactPutListenerQueue, {
3939
putListeners: function() {
4040
for (var i = 0; i < this.listenersToPut.length; i++) {
4141
var listenerToPut = this.listenersToPut[i];
42-
ReactEventEmitter.putListener(
42+
ReactBrowserEventEmitter.putListener(
4343
listenerToPut.rootNodeID,
4444
listenerToPut.propKey,
4545
listenerToPut.propValue

src/browser/ReactReconcileTransaction.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
var CallbackQueue = require('CallbackQueue');
2323
var PooledClass = require('PooledClass');
24-
var ReactEventEmitter = require('ReactEventEmitter');
24+
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
2525
var ReactInputSelection = require('ReactInputSelection');
2626
var ReactPutListenerQueue = require('ReactPutListenerQueue');
2727
var Transaction = require('Transaction');
@@ -50,21 +50,22 @@ var SELECTION_RESTORATION = {
5050
*/
5151
var EVENT_SUPPRESSION = {
5252
/**
53-
* @return {boolean} The enabled status of `ReactEventEmitter` before the
54-
* reconciliation.
53+
* @return {boolean} The enabled status of `ReactBrowserEventEmitter` before
54+
* the reconciliation.
5555
*/
5656
initialize: function() {
57-
var currentlyEnabled = ReactEventEmitter.isEnabled();
58-
ReactEventEmitter.setEnabled(false);
57+
var currentlyEnabled = ReactBrowserEventEmitter.isEnabled();
58+
ReactBrowserEventEmitter.setEnabled(false);
5959
return currentlyEnabled;
6060
},
6161

6262
/**
63-
* @param {boolean} previouslyEnabled Enabled status of `ReactEventEmitter`
64-
* before the reconciliation occured. `close` restores the previous value.
63+
* @param {boolean} previouslyEnabled Enabled status of
64+
* `ReactBrowserEventEmitter` before the reconciliation occured. `close`
65+
* restores the previous value.
6566
*/
6667
close: function(previouslyEnabled) {
67-
ReactEventEmitter.setEnabled(previouslyEnabled);
68+
ReactBrowserEventEmitter.setEnabled(previouslyEnabled);
6869
}
6970
};
7071

0 commit comments

Comments
 (0)