From 4622532ca4f9cc6bcadeb4940614b67f232a57ec Mon Sep 17 00:00:00 2001 From: Ahmed El-Helw Date: Fri, 1 Jul 2016 15:12:57 -0700 Subject: [PATCH] Fix TextInput Spannable flags Summary: The TextInput spannables are being set wrong by Nodes. Consequently, when you hit space after a word, anything you type is highlighted, though it shouldn't be. Differential Revision: D3507516 --- .../facebook/react/flat/FlatTextShadowNode.java | 14 +++++++++++--- .../com/facebook/react/flat/RCTRawText.java | 6 +++++- .../facebook/react/flat/RCTTextInlineImage.java | 6 +++++- .../com/facebook/react/flat/RCTTextInput.java | 5 +++++ .../com/facebook/react/flat/RCTVirtualText.java | 17 +++++++++++------ .../com/facebook/react/flat/StateBuilder.java | 2 +- 6 files changed, 38 insertions(+), 12 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatTextShadowNode.java index 11b834421..893e50851 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatTextShadowNode.java @@ -59,17 +59,25 @@ import com.facebook.react.uimanager.ReactShadowNode; return false; } + /* package */ boolean isEditable() { + return false; + } + /** * Recursively visits FlatTextShadowNode and its children, * applying spans to SpannableStringBuilder. */ - /* package */ final void applySpans(SpannableStringBuilder builder) { + /* package */ final void applySpans(SpannableStringBuilder builder, boolean isEditable) { if (mTextBegin != mTextEnd || shouldAllowEmptySpans()) { - performApplySpans(builder, mTextBegin, mTextEnd); + performApplySpans(builder, mTextBegin, mTextEnd, isEditable); } } protected abstract void performCollectText(SpannableStringBuilder builder); - protected abstract void performApplySpans(SpannableStringBuilder builder, int begin, int end); + protected abstract void performApplySpans( + SpannableStringBuilder builder, + int begin, + int end, + boolean isEditable); protected abstract void performCollectAttachDetachListeners(StateBuilder stateBuilder); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTRawText.java b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTRawText.java index 093f32e91..4d675b943 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTRawText.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTRawText.java @@ -31,7 +31,11 @@ import com.facebook.react.uimanager.annotations.ReactProp; } @Override - protected void performApplySpans(SpannableStringBuilder builder, int begin, int end) { + protected void performApplySpans( + SpannableStringBuilder builder, + int begin, + int end, + boolean isEditable) { builder.setSpan( this, begin, diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInlineImage.java b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInlineImage.java index 5682b04b2..cf61b6bbd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInlineImage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInlineImage.java @@ -50,7 +50,11 @@ import com.facebook.react.uimanager.annotations.ReactProp; } @Override - protected void performApplySpans(SpannableStringBuilder builder, int begin, int end) { + protected void performApplySpans( + SpannableStringBuilder builder, + int begin, + int end, + boolean isEditable) { mInlineImageSpan.freeze(); builder.setSpan( mInlineImageSpan, diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInput.java b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInput.java index 459d1bb13..c8bfa3e1b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInput.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInput.java @@ -169,6 +169,11 @@ public class RCTTextInput extends RCTVirtualText implements AndroidView, CSSNode return true; } + @Override + boolean isEditable() { + return true; + } + @Override protected void performCollectText(SpannableStringBuilder builder) { if (mText != null) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTVirtualText.java b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTVirtualText.java index 9929e4f3a..f594a1765 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTVirtualText.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTVirtualText.java @@ -54,14 +54,19 @@ import com.facebook.react.uimanager.annotations.ReactProp; } @Override - protected void performApplySpans(SpannableStringBuilder builder, int begin, int end) { + protected void performApplySpans(SpannableStringBuilder builder, int begin, int end, boolean isEditable) { mFontStylingSpan.freeze(); // All spans will automatically extend to the right of the text, but not the left - except // for spans that start at the beginning of the text. - final int flag = begin == 0 ? - Spannable.SPAN_INCLUSIVE_INCLUSIVE : - Spannable.SPAN_EXCLUSIVE_INCLUSIVE; + final int flag; + if (isEditable) { + flag = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE; + } else { + flag = begin == 0 ? + Spannable.SPAN_INCLUSIVE_INCLUSIVE : + Spannable.SPAN_EXCLUSIVE_INCLUSIVE; + } builder.setSpan( mFontStylingSpan, @@ -81,7 +86,7 @@ import com.facebook.react.uimanager.annotations.ReactProp; for (int i = 0, childCount = getChildCount(); i < childCount; ++i) { FlatTextShadowNode child = (FlatTextShadowNode) getChildAt(i); - child.applySpans(builder); + child.applySpans(builder, isEditable); } } @@ -259,7 +264,7 @@ import com.facebook.react.uimanager.annotations.ReactProp; /* package */ final SpannableStringBuilder getText() { SpannableStringBuilder sb = new SpannableStringBuilder(); collectText(sb); - applySpans(sb); + applySpans(sb, isEditable()); return sb; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/StateBuilder.java b/ReactAndroid/src/main/java/com/facebook/react/flat/StateBuilder.java index 492b565d0..aa575c77b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/StateBuilder.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/StateBuilder.java @@ -233,7 +233,7 @@ import com.facebook.react.uimanager.events.EventDispatcher; float clipBottom) { boolean hasUpdates = node.hasNewLayout(); - boolean expectingUpdate = hasUpdates || node.isUpdated() || + boolean expectingUpdate = hasUpdates || node.isUpdated() || node.hasUnseenUpdates() || node.clipBoundsChanged(clipLeft, clipTop, clipRight, clipBottom); if (SKIP_UP_TO_DATE_NODES && !expectingUpdate) { return false;