From cc959273da78ddee33d85036c7d409dd51347896 Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Thu, 23 Jun 2016 03:53:50 -0700 Subject: [PATCH] Fix multi-character TextInput Reviewed By: hnery Differential Revision: D3457105 fbshipit-source-id: dcb364123ed82842d4fb2dee9108f2805249a8f9 --- Libraries/Text/RCTShadowText.m | 23 ++++++++++--- Libraries/Text/RCTText.m | 1 - Libraries/Text/RCTTextManager.m | 61 +-------------------------------- Libraries/Text/RCTTextView.m | 3 ++ React/Views/RCTViewManager.h | 2 +- 5 files changed, 24 insertions(+), 66 deletions(-) diff --git a/Libraries/Text/RCTShadowText.m b/Libraries/Text/RCTShadowText.m index 271a5d32b..c111dbbd9 100644 --- a/Libraries/Text/RCTShadowText.m +++ b/Libraries/Text/RCTShadowText.m @@ -18,6 +18,7 @@ #import "RCTText.h" #import "RCTUtils.h" #import "RCTConvert.h" +#import "RCTTextView.h" NSString *const RCTShadowViewAttributeName = @"RCTShadowViewAttributeName"; NSString *const RCTIsHighlightedAttributeName = @"IsHighlightedAttributeName"; @@ -98,10 +99,24 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width UIEdgeInsets padding = self.paddingAsInsets; CGFloat width = self.frame.size.width - (padding.left + padding.right); + NSNumber *parentTag = [[self reactSuperview] reactTag]; NSTextStorage *textStorage = [self buildTextStorageForWidth:width widthMode:CSS_MEASURE_MODE_EXACTLY]; - [applierBlocks addObject:^(NSDictionary *viewRegistry) { - RCTText *view = viewRegistry[self.reactTag]; + [applierBlocks addObject:^(NSDictionary *viewRegistry) { + RCTText *view = (RCTText *)viewRegistry[self.reactTag]; view.textStorage = textStorage; + + /** + * NOTE: this logic is included to support rich text editing inside multiline + * `` controls. It is required in order to ensure that the + * textStorage (aka attributed string) is copied over from the RCTShadowText + * to the RCTText view in time to be used to update the editable text content. + * TODO: we should establish a delegate relationship betweeen RCTTextView + * and its contaned RCTText element when they get inserted and get rid of this + */ + UIView *parentView = viewRegistry[parentTag]; + if ([parentView respondsToSelector:@selector(performTextUpdate)]) { + [(RCTTextView *)parentView performTextUpdate]; + } }]; return parentProperties; @@ -167,13 +182,13 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width NSTextContainer *textContainer = [NSTextContainer new]; textContainer.lineFragmentPadding = 0.0; - + if (_numberOfLines > 0) { textContainer.lineBreakMode = _lineBreakMode; } else { textContainer.lineBreakMode = NSLineBreakByClipping; } - + textContainer.maximumNumberOfLines = _numberOfLines; textContainer.size = (CGSize){widthMode == CSS_MEASURE_MODE_UNDEFINED ? CGFLOAT_MAX : width, CGFLOAT_MAX}; diff --git a/Libraries/Text/RCTText.m b/Libraries/Text/RCTText.m index 4a926b246..fec4f31d9 100644 --- a/Libraries/Text/RCTText.m +++ b/Libraries/Text/RCTText.m @@ -155,7 +155,6 @@ static void collectNonTextDescendants(RCTText *view, NSMutableArray *nonTextDesc return reactTag; } - - (void)didMoveToWindow { [super didMoveToWindow]; diff --git a/Libraries/Text/RCTTextManager.m b/Libraries/Text/RCTTextManager.m index cc5149fe7..11a498493 100644 --- a/Libraries/Text/RCTTextManager.m +++ b/Libraries/Text/RCTTextManager.m @@ -78,7 +78,6 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor) - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary *)shadowViewRegistry { - NSMutableSet *textViewTagsToUpdate = [NSMutableSet new]; for (RCTShadowView *rootView in shadowViewRegistry.allValues) { if (![rootView isReactRootView]) { // This isn't a root view @@ -103,19 +102,6 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor) RCTLogError(@"Raw text cannot be used outside of a tag. Not rendering string: '%@'", [(RCTShadowRawText *)shadowView text]); } else { - NSNumber *reactTag = shadowView.reactTag; - // This isn't pretty, but hopefully it's temporary - // the problem is, there's no easy way (besides the viewName) - // to tell from the shadowView if the view is an RKTextView - if ([shadowView.viewName hasSuffix:@"TextView"]) { - // Add to textViewTagsToUpdate only if has a RCTShadowText subview - for (RCTShadowView *subview in shadowView.reactSubviews) { - if ([subview isKindOfClass:[RCTShadowText class]]) { - [textViewTagsToUpdate addObject:reactTag]; - break; - } - } - } for (RCTShadowView *child in [shadowView reactSubviews]) { if ([child isTextDirty]) { [queue addObject:child]; @@ -127,52 +113,7 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor) } } - /** - * NOTE: this logic is included to support rich text editing inside multiline - * `` controls. It is required in order to ensure that the - * textStorage (aka attributed string) is copied over from the RCTShadowText - * to the RCTText view in time to be used to update the editable text content. - */ - if (textViewTagsToUpdate.count) { - - NSMutableArray *uiBlocks = [NSMutableArray new]; - for (NSNumber *reactTag in textViewTagsToUpdate) { - RCTShadowView *shadowTextView = shadowViewRegistry[reactTag]; - RCTShadowText *shadowText; - for (RCTShadowText *subview in shadowTextView.reactSubviews) { - if ([subview isKindOfClass:[RCTShadowText class]]) { - shadowText = subview; - break; - } - } - - UIEdgeInsets padding = shadowText.paddingAsInsets; - CGFloat width = shadowText.frame.size.width - (padding.left + padding.right); - - NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width widthMode:CSS_MEASURE_MODE_EXACTLY]; - [uiBlocks addObject:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { - RCTTextView *textView = viewRegistry[reactTag]; - RCTText *text; - for (RCTText *subview in textView.reactSubviews) { - if ([subview isKindOfClass:[RCTText class]]) { - text = subview; - break; - } - } - - text.textStorage = textStorage; - [textView performTextUpdate]; - }]; - } - - return ^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { - for (RCTViewManagerUIBlock uiBlock in uiBlocks) { - uiBlock(uiManager, viewRegistry); - } - }; - } else { - return nil; - } + return nil; } - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowView:(RCTShadowText *)shadowView diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m index ea0237868..b8a396aa8 100644 --- a/Libraries/Text/RCTTextView.m +++ b/Libraries/Text/RCTTextView.m @@ -125,6 +125,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) attrs[NSBackgroundColorAttributeName] = subview.backgroundColor; _textView.typingAttributes = attrs; } + + [self performTextUpdate]; } } @@ -133,6 +135,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) [super removeReactSubview:subview]; if (_richTextView == subview) { _richTextView = nil; + [self performTextUpdate]; } } diff --git a/React/Views/RCTViewManager.h b/React/Views/RCTViewManager.h index d963e2b4b..71df14862 100644 --- a/React/Views/RCTViewManager.h +++ b/React/Views/RCTViewManager.h @@ -85,7 +85,7 @@ typedef void (^RCTViewManagerUIBlock)(RCTUIManager *uiManager, NSDictionary *)shadowViewRegistry;