zulip-mobile
zulip-mobile copied to clipboard
Rich text can be pasted into input box on Android
When a user copies and pastes formatted text (for instance, from a web browser), the rich text is pasted into the compose box. This is incorrect, we should strip this formatting instead.
See this CZO thread for details.
The next step here is to look at what we get from onChangeText
when rich text is pasted in, since that seems like the most likely route to fix this.
- simple texts are being stored in state,

- Only the
\n
next Line is retained byTextInput
@vaibhavs2, it looks like Wesley is specifically asking about what gets passed to onChangeText
; could you log all the arguments it's getting called with when you paste rich text in?
The function has single argument that get passed to onChangeText
and from the argument state is getting data that's why I directly comment with state data
.
I tried
<TextInput onChangeText={(value)=>{this.setState({message:value})}} multiline style={{borderWidth:2, borderColor:'red',}}>
<Text style={{ fontWeight:'bold'}}>hey therer</Text>
<Text style = {{color:'red'}}> I don't know what to write</Text>
<Text style = {{fontWeight:'bold', fontSize:20}}> I don't know what to write</Text>
</TextInput>

I think TextInput is doing something same under the hood when we paste rich text from somewhere and return us simple text
Thanks @vaibhavs2 !
So the answer to what onChangeText
gives us is that it's just the plain text.
Which agrees with the RN docs, which say the type it passes to that callback is just string
. So that fits, at least.
Given that RN is only actually giving us the plain text, not any of the formatting, it seems like an outright bug in RN that it accepts formatting on paste and shows the formatting in the input.
Though from what we saw in that chat thread linked above, it seems like Android may not give RN an easy way to fix this bug.
I think the next step is to search the RN issue tracker and see if there's an existing issue. If there is, then link to it here.
If there isn't, then the step after that would be to file a good bug report on RN. The key work to do to make a good bug report is that it shouldn't be about Zulip; instead it should have a simple repro, where you link to a tiny new RN app that demonstrates the bug and does nothing else. That way someone interested in fixing the RN bug can focus on that minimal repro.
Issue Created https://github.com/facebook/react-native/issues/31442
As described on this CZO thread, this issue can lead to a very awkward user experience.
For how to go about resolving this issue:
At the Android level, there's a handy solution that @WesleyAC found in a Stack Overflow answer:
A perfect and easy way: Override the EditText's onTextContextMenuItem and intercept the android.R.id.paste to be android.R.id.pasteAsPlainText
This works on Android >= M, which covers all the Android versions we support.
Then to apply that in Zulip:
-
I think the ideal solution is that React Native upstream should apply that fix in the implementation of the
TextInput
component.(It's already the case that the only data
TextInput
actually exposes to the app is the plain text -- so the fact that it lets the user paste formatted text, and shows that formatting back, is basically a bug in RN because there's no way the app can end up respecting that formatting.) -
Alternatively, without any changes to RN, I think it should be possible to make our own component with a name like
FixedTextInput
, using inheritance in the native code to avoid needing to duplicate most of the existing implementation.OTOH TextInput has a more complicated implementation than most components, so this may not be simple. The relevant subclass of Android
EditText
is inReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
, and we should be able to make a pretty simple subclass of that that just adds the needed behavior by overridingonTextContextMenuItem
… but then I'm not sure what other scaffolding is needed around that in order to get a React component that can be used in place of the upstreamTextInput
.
So one route to a fix would be to try the second approach, with a subclass, and then when it's working send a PR upstream to React Native to fix TextInput
itself. This would be good, provided that it doesn't end up involving too much extra scaffolding, because it'd mean a straightforward way for us to have the fix immediately while the fix works its way through getting merged upstream and then going into a RN release we upgrade to.
Alternatively, we could go straight for the upstream fix. Then there'd be a lag of a few months before we're on an RN release that has the fix. We could simply accept that lag, or we'd also have the option of switching to our own patched version of RN with the fix applied.
The upstream issue https://github.com/facebook/react-native/issues/31442 has apparently been fixed! Thanks @vaibhavs2 for filing it :slightly_smiling_face:
(And from the PR thread — at https://github.com/facebook/react-native/pull/38189#issuecomment-1639757105 and https://github.com/facebook/react-native/pull/38189#pullrequestreview-1542055466 — it's clear that our discussion here was key in getting this fixed, by making it clear why the existing behavior was a bug. So good work everyone.)