From a77ba2b15def456813dc6ed0ddcdc314e2e7a0e5 Mon Sep 17 00:00:00 2001 From: Evan Morikawa Date: Thu, 5 Nov 2015 17:50:40 -0800 Subject: [PATCH] fix(composer): double-composition events supported --- .../contenteditable/contenteditable.cjsx | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/components/contenteditable/contenteditable.cjsx b/src/components/contenteditable/contenteditable.cjsx index 15aa13567..d7dc047ec 100644 --- a/src/components/contenteditable/contenteditable.cjsx +++ b/src/components/contenteditable/contenteditable.cjsx @@ -80,9 +80,12 @@ class Contenteditable extends React.Component @setInnerState editableNode: @_editableNode() + # When we have a composition event in progress, we should not update + # because otherwise our composition event will be blown away. shouldComponentUpdate: (nextProps, nextState) -> - not Utils.isEqualReact(nextProps, @props) or - not Utils.isEqualReact(nextState, @state) + not @_inCompositionEvent and + (not Utils.isEqualReact(nextProps, @props) or + not Utils.isEqualReact(nextState, @state)) componentWillUnmount: => @_editableNode().removeEventListener('contextmenu', @_onShowContextualMenu) @@ -166,10 +169,25 @@ class Contenteditable extends React.Component # Note: Related to composer-view#_onClickComposeBody event.stopPropagation() + # We must set the `inCompositionEvent` flag in addition to tearing down + # the selecton listeners. While the composition event is in progress, we + # want to ignore any input events we get. + # + # It is also possible for a composition event to end and then + # immediately start a new composition event. This happens when two + # composition event-triggering characters are pressed twice in a row. + # When the first composition event ends, the `onInput` method fires (as + # it's supposed to) and sends off an asynchronous update request when we + # `_saveNewHtml`. Before that comes back via new props, the 2nd + # composition event starts. Without the `_inCompositionEvent` flag + # stopping the re-render, the asynchronous update request will cause us + # to re-render and blow away our newly started 2nd composition event. _onCompositionStart: => + @_inCompositionEvent = true @_teardownSelectionListeners() _onCompositionEnd: => + @_inCompositionEvent = false @_setupSelectionListeners() @_onInput()