Add MediaEvent Handlers for Video/Audio components
blainekasten committed
Jul 29, 2015 at 23:25 UTC
bdf377ff021b8d1dfabde302f7e4398e394939d4
5 files changed
+318
-39
docs/docs/ref-05-events.md
+8
@@ -193,3 +193,11 @@ Number deltaX
193
Number deltaY
194
Number deltaZ
195
```
196
+
197
+### Media Events
198
+
199
+Event names:
200
+
201
+```
202
+onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting
203
+```
src/renderers/dom/client/ReactBrowserEventEmitter.js
+23
@@ -84,7 +84,10 @@ var reactTopListenersCounter = 0;
84
// lower node than `document`), binding at `document` would cause duplicate
85
// events so we don't include them here
86
var topEventMapping = {
87
+ topAbort: 'abort',
88
topBlur: 'blur',
89
+ topCanPlay: 'canplay',
90
+ topCanPlayThrough: 'canplaythrough',
91
topChange: 'change',
92
topClick: 'click',
93
topCompositionEnd: 'compositionend',
@@ -102,24 +105,44 @@ var topEventMapping = {
105
topDragOver: 'dragover',
106
topDragStart: 'dragstart',
107
topDrop: 'drop',
108
+ topDurationChange: 'durationchange',
109
+ topEmptied: 'emptied',
110
+ topEnded: 'ended',
111
+ topError: 'error',
112
topFocus: 'focus',
113
topInput: 'input',
114
topKeyDown: 'keydown',
115
topKeyPress: 'keypress',
116
topKeyUp: 'keyup',
117
+ topLoadedData: 'loadeddata',
118
+ topLoadedMetadata: 'loadedmetadata',
119
+ topLoadStart: 'loadstart',
120
topMouseDown: 'mousedown',
121
topMouseMove: 'mousemove',
122
topMouseOut: 'mouseout',
123
topMouseOver: 'mouseover',
124
topMouseUp: 'mouseup',
125
+ topOnEncrypted: 'onencrypted',
126
+ topPause: 'pause',
127
topPaste: 'paste',
128
+ topPlay: 'play',
129
+ topPlaying: 'playing',
130
+ topProgress: 'progress',
131
+ topRateChange: 'ratechange',
132
+ topSeeking: 'seeking',
133
+ topSeeked: 'seeked',
134
topScroll: 'scroll',
135
topSelectionChange: 'selectionchange',
136
+ topStalled: 'stalled',
137
+ topSuspend: 'suspend',
138
topTextInput: 'textInput',
139
+ topTimeUpdate: 'timeupdate',
140
topTouchCancel: 'touchcancel',
141
topTouchEnd: 'touchend',
142
topTouchMove: 'touchmove',
143
topTouchStart: 'touchstart',
144
+ topVolumeChange: 'volumechange',
145
+ topWaiting: 'waiting',
146
topWheel: 'wheel',
147
};
148
src/renderers/dom/client/eventPlugins/SimpleEventPlugin.js
+215
-39
@@ -35,12 +35,30 @@ var warning = require('warning');
35
var topLevelTypes = EventConstants.topLevelTypes;
36
37
var eventTypes = {
38
+ abort: {
39
+ phasedRegistrationNames: {
40
+ bubbled: keyOf({onAbort: true}),
41
+ captured: keyOf({onAbortCapture: true}),
42
+ },
43
+ },
44
blur: {
45
phasedRegistrationNames: {
46
bubbled: keyOf({onBlur: true}),
47
captured: keyOf({onBlurCapture: true}),
48
},
49
},
50
+ canPlay: {
51
+ phasedRegistrationNames: {
52
+ bubbled: keyOf({onCanPlay: true}),
53
+ captured: keyOf({onCanPlayCapture: true}),
54
+ },
55
+ },
56
+ canPlayThrough: {
57
+ phasedRegistrationNames: {
58
+ bubbled: keyOf({onCanPlayThrough: true}),
59
+ captured: keyOf({onCanPlayThroughCapture: true}),
60
+ },
61
+ },
62
click: {
63
phasedRegistrationNames: {
64
bubbled: keyOf({onClick: true}),
@@ -119,6 +137,30 @@ var eventTypes = {
137
captured: keyOf({onDropCapture: true}),
138
},
139
},
140
+ durationChange: {
141
+ phasedRegistrationNames: {
142
+ bubbled: keyOf({onDurationChange: true}),
143
+ captured: keyOf({onDurationChangeCapture: true}),
144
+ },
145
+ },
146
+ emptied: {
147
+ phasedRegistrationNames: {
148
+ bubbled: keyOf({onEmptied: true}),
149
+ captured: keyOf({onEmptiedCapture: true}),
150
+ },
151
+ },
152
+ ended: {
153
+ phasedRegistrationNames: {
154
+ bubbled: keyOf({onEnded: true}),
155
+ captured: keyOf({onEndedCapture: true}),
156
+ },
157
+ },
158
+ error: {
159
+ phasedRegistrationNames: {
160
+ bubbled: keyOf({onError: true}),
161
+ captured: keyOf({onErrorCapture: true}),
162
+ },
163
+ },
164
focus: {
165
phasedRegistrationNames: {
166
bubbled: keyOf({onFocus: true}),
@@ -155,10 +197,22 @@ var eventTypes = {
197
captured: keyOf({onLoadCapture: true}),
198
},
199
},
158
- error: {
200
+ loadedData: {
201
phasedRegistrationNames: {
160
- bubbled: keyOf({onError: true}),
161
- captured: keyOf({onErrorCapture: true}),
202
+ bubbled: keyOf({onLoadedData: true}),
203
+ captured: keyOf({onLoadedDataCapture: true}),
204
+ },
205
+ },
206
+ loadedMetadata: {
207
+ phasedRegistrationNames: {
208
+ bubbled: keyOf({onLoadedMetadata: true}),
209
+ captured: keyOf({onLoadedMetadataCapture: true}),
210
+ },
211
+ },
212
+ loadStart: {
213
+ phasedRegistrationNames: {
214
+ bubbled: keyOf({onLoadStart: true}),
215
+ captured: keyOf({onLoadStartCapture: true}),
216
},
217
},
218
// Note: We do not allow listening to mouseOver events. Instead, use the
@@ -193,12 +247,48 @@ var eventTypes = {
247
captured: keyOf({onMouseUpCapture: true}),
248
},
249
},
250
+ onEncrypted: {
251
+ phasedRegistrationNames: {
252
+ bubbled: keyOf({onEncrypted: true}),
253
+ captured: keyOf({onEncryptedCapture: true}),
254
+ },
255
+ },
256
paste: {
257
phasedRegistrationNames: {
258
bubbled: keyOf({onPaste: true}),
259
captured: keyOf({onPasteCapture: true}),
260
},
261
},
262
+ pause: {
263
+ phasedRegistrationNames: {
264
+ bubbled: keyOf({onPause: true}),
265
+ captured: keyOf({onPauseCapture: true}),
266
+ },
267
+ },
268
+ play: {
269
+ phasedRegistrationNames: {
270
+ bubbled: keyOf({onPlay: true}),
271
+ captured: keyOf({onPlayCapture: true}),
272
+ },
273
+ },
274
+ playing: {
275
+ phasedRegistrationNames: {
276
+ bubbled: keyOf({onPlaying: true}),
277
+ captured: keyOf({onPlayingCapture: true}),
278
+ },
279
+ },
280
+ progress: {
281
+ phasedRegistrationNames: {
282
+ bubbled: keyOf({onProgress: true}),
283
+ captured: keyOf({onProgressCapture: true}),
284
+ },
285
+ },
286
+ rateChange: {
287
+ phasedRegistrationNames: {
288
+ bubbled: keyOf({onRateChange: true}),
289
+ captured: keyOf({onRateChangeCapture: true}),
290
+ },
291
+ },
292
reset: {
293
phasedRegistrationNames: {
294
bubbled: keyOf({onReset: true}),
@@ -211,12 +301,42 @@ var eventTypes = {
301
captured: keyOf({onScrollCapture: true}),
302
},
303
},
304
+ seeked: {
305
+ phasedRegistrationNames: {
306
+ bubbled: keyOf({onSeeked: true}),
307
+ captured: keyOf({onSeekedCapture: true}),
308
+ },
309
+ },
310
+ seeking: {
311
+ phasedRegistrationNames: {
312
+ bubbled: keyOf({onSeeking: true}),
313
+ captured: keyOf({onSeekingCapture: true}),
314
+ },
315
+ },
316
+ stalled: {
317
+ phasedRegistrationNames: {
318
+ bubbled: keyOf({onStalled: true}),
319
+ captured: keyOf({onStalledCapture: true}),
320
+ },
321
+ },
322
submit: {
323
phasedRegistrationNames: {
324
bubbled: keyOf({onSubmit: true}),
325
captured: keyOf({onSubmitCapture: true}),
326
},
327
},
328
+ suspend: {
329
+ phasedRegistrationNames: {
330
+ bubbled: keyOf({onSuspend: true}),
331
+ captured: keyOf({onSuspendCapture: true}),
332
+ },
333
+ },
334
+ timeUpdate: {
335
+ phasedRegistrationNames: {
336
+ bubbled: keyOf({onTimeUpdate: true}),
337
+ captured: keyOf({onTimeUpdateCapture: true}),
338
+ },
339
+ },
340
touchCancel: {
341
phasedRegistrationNames: {
342
bubbled: keyOf({onTouchCancel: true}),
@@ -241,6 +361,18 @@ var eventTypes = {
361
captured: keyOf({onTouchStartCapture: true}),
362
},
363
},
364
+ volumeChange: {
365
+ phasedRegistrationNames: {
366
+ bubbled: keyOf({onVolumeChange: true}),
367
+ captured: keyOf({onVolumeChangeCapture: true}),
368
+ },
369
+ },
370
+ waiting: {
371
+ phasedRegistrationNames: {
372
+ bubbled: keyOf({onWaiting: true}),
373
+ captured: keyOf({onWaitingCapture: true}),
374
+ },
375
+ },
376
wheel: {
377
phasedRegistrationNames: {
378
bubbled: keyOf({onWheel: true}),
@@ -250,41 +382,63 @@ var eventTypes = {
382
};
383
384
var topLevelEventsToDispatchConfig = {
253
- topBlur: eventTypes.blur,
254
- topClick: eventTypes.click,
255
- topContextMenu: eventTypes.contextMenu,
256
- topCopy: eventTypes.copy,
257
- topCut: eventTypes.cut,
258
- topDoubleClick: eventTypes.doubleClick,
259
- topDrag: eventTypes.drag,
260
- topDragEnd: eventTypes.dragEnd,
261
- topDragEnter: eventTypes.dragEnter,
262
- topDragExit: eventTypes.dragExit,
263
- topDragLeave: eventTypes.dragLeave,
264
- topDragOver: eventTypes.dragOver,
265
- topDragStart: eventTypes.dragStart,
266
- topDrop: eventTypes.drop,
267
- topError: eventTypes.error,
268
- topFocus: eventTypes.focus,
269
- topInput: eventTypes.input,
270
- topKeyDown: eventTypes.keyDown,
271
- topKeyPress: eventTypes.keyPress,
272
- topKeyUp: eventTypes.keyUp,
273
- topLoad: eventTypes.load,
274
- topMouseDown: eventTypes.mouseDown,
275
- topMouseMove: eventTypes.mouseMove,
276
- topMouseOut: eventTypes.mouseOut,
277
- topMouseOver: eventTypes.mouseOver,
278
- topMouseUp: eventTypes.mouseUp,
279
- topPaste: eventTypes.paste,
280
- topReset: eventTypes.reset,
281
- topScroll: eventTypes.scroll,
282
- topSubmit: eventTypes.submit,
283
- topTouchCancel: eventTypes.touchCancel,
284
- topTouchEnd: eventTypes.touchEnd,
285
- topTouchMove: eventTypes.touchMove,
286
- topTouchStart: eventTypes.touchStart,
287
- topWheel: eventTypes.wheel,
385
+ topAbort: eventTypes.abort,
386
+ topBlur: eventTypes.blur,
387
+ topCanPlay: eventTypes.canPlay,
388
+ topCanPlayThrough: eventTypes.canPlayThrough,
389
+ topClick: eventTypes.click,
390
+ topContextMenu: eventTypes.contextMenu,
391
+ topCopy: eventTypes.copy,
392
+ topCut: eventTypes.cut,
393
+ topDoubleClick: eventTypes.doubleClick,
394
+ topDrag: eventTypes.drag,
395
+ topDragEnd: eventTypes.dragEnd,
396
+ topDragEnter: eventTypes.dragEnter,
397
+ topDragExit: eventTypes.dragExit,
398
+ topDragLeave: eventTypes.dragLeave,
399
+ topDragOver: eventTypes.dragOver,
400
+ topDragStart: eventTypes.dragStart,
401
+ topDrop: eventTypes.drop,
402
+ topDurationChange: eventTypes.durationChange,
403
+ topEmptied: eventTypes.emptied,
404
+ topEnded: eventTypes.ended,
405
+ topError: eventTypes.error,
406
+ topFocus: eventTypes.focus,
407
+ topInput: eventTypes.input,
408
+ topKeyDown: eventTypes.keyDown,
409
+ topKeyPress: eventTypes.keyPress,
410
+ topKeyUp: eventTypes.keyUp,
411
+ topLoad: eventTypes.load,
412
+ topLoadedData: eventTypes.loadedData,
413
+ topLoadedMetadata: eventTypes.loadedMetadata,
414
+ topLoadStart: eventTypes.loadStart,
415
+ topMouseDown: eventTypes.mouseDown,
416
+ topMouseMove: eventTypes.mouseMove,
417
+ topMouseOut: eventTypes.mouseOut,
418
+ topMouseOver: eventTypes.mouseOver,
419
+ topMouseUp: eventTypes.mouseUp,
420
+ topOnEncrypted: eventTypes.onEncrypted,
421
+ topPause: eventTypes.pause,
422
+ topPaste: eventTypes.paste,
423
+ topPlay: eventTypes.play,
424
+ topPlaying: eventTypes.playing,
425
+ topProgress: eventTypes.progress,
426
+ topRateChange: eventTypes.rateChange,
427
+ topReset: eventTypes.reset,
428
+ topSeeked: eventTypes.seeked,
429
+ topSeeking: eventTypes.seeking,
430
+ topScroll: eventTypes.scroll,
431
+ topStalled: eventTypes.stalled,
432
+ topSubmit: eventTypes.submit,
433
+ topSuspend: eventTypes.suspend,
434
+ topTimeUpdate: eventTypes.timeUpdate,
435
+ topTouchCancel: eventTypes.touchCancel,
436
+ topTouchEnd: eventTypes.touchEnd,
437
+ topTouchMove: eventTypes.touchMove,
438
+ topTouchStart: eventTypes.touchStart,
439
+ topVolumeChange: eventTypes.volumeChange,
440
+ topWaiting: eventTypes.waiting,
441
+ topWheel: eventTypes.wheel,
442
};
443
444
for (var type in topLevelEventsToDispatchConfig) {
@@ -342,11 +496,33 @@ var SimpleEventPlugin = {
496
}
497
var EventConstructor;
498
switch (topLevelType) {
499
+ case topLevelTypes.topAbort:
500
+ case topLevelTypes.topCanPlay:
501
+ case topLevelTypes.topCanPlayThrough:
502
+ case topLevelTypes.topDurationChange:
503
+ case topLevelTypes.topEmptied:
504
+ case topLevelTypes.topEnded:
505
+ case topLevelTypes.topError:
506
case topLevelTypes.topInput:
507
case topLevelTypes.topLoad:
347
- case topLevelTypes.topError:
508
+ case topLevelTypes.topLoadedData:
509
+ case topLevelTypes.topLoadedMetadata:
510
+ case topLevelTypes.topLoadStart:
511
+ case topLevelTypes.topOnEncrypted:
512
+ case topLevelTypes.topPause:
513
+ case topLevelTypes.topPlay:
514
+ case topLevelTypes.topPlaying:
515
+ case topLevelTypes.topProgress:
516
+ case topLevelTypes.topRateChange:
517
case topLevelTypes.topReset:
518
+ case topLevelTypes.topSeeked:
519
+ case topLevelTypes.topSeeking:
520
+ case topLevelTypes.topStalled:
521
case topLevelTypes.topSubmit:
522
+ case topLevelTypes.topSuspend:
523
+ case topLevelTypes.topTimeUpdate:
524
+ case topLevelTypes.topVolumeChange:
525
+ case topLevelTypes.topWaiting:
526
// HTML Events
527
// @see http://www.w3.org/TR/html5/index.html#events-0
528
EventConstructor = SyntheticEvent;
src/renderers/dom/shared/ReactDOMComponent.js
+50
@@ -301,6 +301,34 @@ function putListener() {
301
);
302
}
303
304
+// There are so many media events, it makes sense to just
305
+// maintain a list rather than create a `trapBubbledEvent` for each
306
+var mediaEvents = {
307
+ topAbort: 'abort',
308
+ topCanPlay: 'canplay',
309
+ topCanPlayThrough: 'canplaythrough',
310
+ topDurationChange: 'durationchange',
311
+ topEmptied: 'emptied',
312
+ topEnded: 'ended',
313
+ topError: 'error',
314
+ topLoadedData: 'loadeddata',
315
+ topLoadedMetadata: 'loadedmetadata',
316
+ topLoadStart: 'loadstart',
317
+ topOnEncrypted: 'onencrypted',
318
+ topPause: 'pause',
319
+ topPlay: 'play',
320
+ topPlaying: 'playing',
321
+ topProgress: 'progress',
322
+ topRateChange: 'ratechange',
323
+ topSeeked: 'seeked',
324
+ topSeeking: 'seeking',
325
+ topStalled: 'stalled',
326
+ topSuspend: 'suspend',
327
+ topTimeUpdate: 'timeupdate',
328
+ topVolumeChange: 'volumechange',
329
+ topWaiting: 'waiting',
330
+};
331
+
332
function trapBubbledEventsLocal() {
333
var inst = this;
334
// If a component renders to null or if another component fatals and causes
@@ -321,6 +349,24 @@ function trapBubbledEventsLocal() {
349
node
350
),
351
];
352
+ break;
353
+ case 'video':
354
+ case 'audio':
355
+
356
+ inst._wrapperState.listeners = [];
357
+ // create listener for each media event
358
+ for (var event in mediaEvents) {
359
+ if (mediaEvents.hasOwnProperty(event)) {
360
+ inst._wrapperState.listeners.push(
361
+ ReactBrowserEventEmitter.trapBubbledEvent(
362
+ EventConstants.topLevelTypes[event],
363
+ mediaEvents[event],
364
+ node
365
+ )
366
+ );
367
+ }
368
+ }
369
+
370
break;
371
case 'img':
372
inst._wrapperState.listeners = [
@@ -475,6 +521,8 @@ ReactDOMComponent.Mixin = {
521
case 'iframe':
522
case 'img':
523
case 'form':
524
+ case 'video':
525
+ case 'audio':
526
this._wrapperState = {
527
listeners: null,
528
};
@@ -905,6 +953,8 @@ ReactDOMComponent.Mixin = {
953
case 'iframe':
954
case 'img':
955
case 'form':
956
+ case 'video':
957
+ case 'audio':
958
var listeners = this._wrapperState.listeners;
959
if (listeners) {
960
for (var i = 0; i < listeners.length; i++) {
src/renderers/shared/event/EventConstants.js
+22
@@ -19,7 +19,10 @@ var PropagationPhases = keyMirror({bubbled: null, captured: null});
19
* Types of raw signals from the browser caught at the top level.
20
*/
21
var topLevelTypes = keyMirror({
22
+ topAbort: null,
23
topBlur: null,
24
+ topCanPlay: null,
25
+ topCanPlayThrough: null,
26
topChange: null,
27
topClick: null,
28
topCompositionEnd: null,
@@ -37,6 +40,9 @@ var topLevelTypes = keyMirror({
40
topDragOver: null,
41
topDragStart: null,
42
topDrop: null,
43
+ topDurationChange: null,
44
+ topEmptied: null,
45
+ topEnded: null,
46
topError: null,
47
topFocus: null,
48
topInput: null,
@@ -44,21 +50,37 @@ var topLevelTypes = keyMirror({
50
topKeyPress: null,
51
topKeyUp: null,
52
topLoad: null,
53
+ topLoadedData: null,
54
+ topLoadedMetadata: null,
55
+ topLoadStart: null,
56
topMouseDown: null,
57
topMouseMove: null,
58
topMouseOut: null,
59
topMouseOver: null,
60
topMouseUp: null,
61
+ topOnEncrypted: null,
62
topPaste: null,
63
+ topPause: null,
64
+ topPlay: null,
65
+ topPlaying: null,
66
+ topProgress: null,
67
+ topRateChange: null,
68
topReset: null,
69
topScroll: null,
70
+ topSeeked: null,
71
+ topSeeking: null,
72
topSelectionChange: null,
73
+ topStalled: null,
74
+ topSuspend: null,
75
topSubmit: null,
76
topTextInput: null,
77
+ topTimeUpdate: null,
78
topTouchCancel: null,
79
topTouchEnd: null,
80
topTouchMove: null,
81
topTouchStart: null,
82
+ topVolumeChange: null,
83
+ topWaiting: null,
84
topWheel: null,
85
});
86