hack around React having its own bubbling phase
parent
5c1c1f64b6
commit
10a74696b3
|
@ -106,7 +106,7 @@ const LoggedInView = React.createClass({
|
||||||
|
|
||||||
CallMediaHandler.loadDevices();
|
CallMediaHandler.loadDevices();
|
||||||
|
|
||||||
document.addEventListener('keydown', this._onKeyDown);
|
document.addEventListener('keydown', this._onNativeKeyDown, false);
|
||||||
|
|
||||||
this._sessionStore = sessionStore;
|
this._sessionStore = sessionStore;
|
||||||
this._sessionStoreToken = this._sessionStore.addListener(
|
this._sessionStoreToken = this._sessionStore.addListener(
|
||||||
|
@ -136,7 +136,7 @@ const LoggedInView = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount: function() {
|
componentWillUnmount: function() {
|
||||||
document.removeEventListener('keydown', this._onKeyDown);
|
document.removeEventListener('keydown', this._onNativeKeyDown, false);
|
||||||
this._matrixClient.removeListener("accountData", this.onAccountData);
|
this._matrixClient.removeListener("accountData", this.onAccountData);
|
||||||
this._matrixClient.removeListener("sync", this.onSync);
|
this._matrixClient.removeListener("sync", this.onSync);
|
||||||
this._matrixClient.removeListener("RoomState.events", this.onRoomStateEvents);
|
this._matrixClient.removeListener("RoomState.events", this.onRoomStateEvents);
|
||||||
|
@ -272,6 +272,42 @@ const LoggedInView = React.createClass({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
SOME HACKERY BELOW:
|
||||||
|
React optimizes event handlers, by always attaching only 1 handler to the document for a given type.
|
||||||
|
It then internally determines the order in which React event handlers should be called,
|
||||||
|
emulating the capture and bubbling phases the DOM also has.
|
||||||
|
|
||||||
|
But, as the native handler for React is always attached on the document,
|
||||||
|
it will always run last for bubbling (first for capturing) handlers,
|
||||||
|
and thus React basically has its own event phases, and will always run
|
||||||
|
after (before for capturing) any native other event handlers (as they tend to be attached last).
|
||||||
|
|
||||||
|
So ideally one wouldn't mix React and native event handlers to have bubbling working as expected,
|
||||||
|
but we do need a native event handler here on the document,
|
||||||
|
to get keydown events when there is no focused element (target=body).
|
||||||
|
|
||||||
|
We also do need bubbling here to give child components a chance to call `stopPropagation()`,
|
||||||
|
for keydown events it can handle itself, and shouldn't be redirected to the composer.
|
||||||
|
|
||||||
|
So we listen with React on this component to get any events on focused elements, and get bubbling working as expected.
|
||||||
|
We also listen with a native listener on the document to get keydown events when no element is focused.
|
||||||
|
Bubbling is irrelevant here as the target is the body element.
|
||||||
|
*/
|
||||||
|
_onReactKeyDown: function(ev) {
|
||||||
|
// events caught while bubbling up on the root element
|
||||||
|
// of this component, so something must be focused.
|
||||||
|
this._onKeyDown(ev);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onNativeKeyDown: function(ev) {
|
||||||
|
// only pass this if there is no focused element.
|
||||||
|
// if there is, _onKeyDown will be called by the
|
||||||
|
// react keydown handler that respects the react bubbling order.
|
||||||
|
if (ev.target === document.body) {
|
||||||
|
this._onKeyDown(ev);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_onKeyDown: function(ev) {
|
_onKeyDown: function(ev) {
|
||||||
/*
|
/*
|
||||||
|
@ -560,7 +596,7 @@ const LoggedInView = React.createClass({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='mx_MatrixChat_wrapper' aria-hidden={this.props.hideToSRUsers} onMouseDown={this._onMouseDown} onMouseUp={this._onMouseUp}>
|
<div onKeyDown={this._onReactKeyDown} className='mx_MatrixChat_wrapper' aria-hidden={this.props.hideToSRUsers} onMouseDown={this._onMouseDown} onMouseUp={this._onMouseUp}>
|
||||||
{ topBar }
|
{ topBar }
|
||||||
<DragDropContext onDragEnd={this._onDragEnd}>
|
<DragDropContext onDragEnd={this._onDragEnd}>
|
||||||
<div ref={this._setResizeContainerRef} className={bodyClasses}>
|
<div ref={this._setResizeContainerRef} className={bodyClasses}>
|
||||||
|
|
Loading…
Reference in New Issue