diff --git a/ios/ReactNativeRichTextEditorView.h b/ios/ReactNativeRichTextEditorView.h index 0da90ef59..3e7fb107e 100644 --- a/ios/ReactNativeRichTextEditorView.h +++ b/ios/ReactNativeRichTextEditorView.h @@ -4,6 +4,7 @@ #import "EditorConfig.h" #import "EditorParser.h" #import "BaseStyleProtocol.h" +#import "EditorTextView.h" #ifndef ReactNativeRichTextEditorViewNativeComponent_h #define ReactNativeRichTextEditorViewNativeComponent_h @@ -11,7 +12,7 @@ NS_ASSUME_NONNULL_BEGIN @interface ReactNativeRichTextEditorView : RCTViewComponentView { - @public UITextView *textView; + @public EditorTextView *textView; @public NSRange recentlyChangedRange; @public EditorConfig *config; @public EditorParser *parser; diff --git a/ios/ReactNativeRichTextEditorView.mm b/ios/ReactNativeRichTextEditorView.mm index 35fdcab30..8418bf336 100644 --- a/ios/ReactNativeRichTextEditorView.mm +++ b/ios/ReactNativeRichTextEditorView.mm @@ -13,7 +13,6 @@ #import "StyleHeaders.h" #import "WordsUtils.h" #import "LayoutManagerExtension.h" -#import "EditorTextView.h" using namespace facebook::react; @@ -137,6 +136,7 @@ - (void)setupTextView { textView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0); textView.textContainer.lineFragmentPadding = 0; textView.delegate = self; + textView.editor = self; textView.layoutManager.editor = self; } diff --git a/ios/editorTextView/EditorTextView.h b/ios/editorTextView/EditorTextView.h index de46f287d..d51371643 100644 --- a/ios/editorTextView/EditorTextView.h +++ b/ios/editorTextView/EditorTextView.h @@ -2,4 +2,5 @@ #import @interface EditorTextView : UITextView +@property (nonatomic, weak) id editor; @end diff --git a/ios/editorTextView/EditorTextView.mm b/ios/editorTextView/EditorTextView.mm index 7760de16e..042e457c5 100644 --- a/ios/editorTextView/EditorTextView.mm +++ b/ios/editorTextView/EditorTextView.mm @@ -7,7 +7,7 @@ @implementation EditorTextView - (void)copy:(id)sender { - ReactNativeRichTextEditorView *typedEditor = (ReactNativeRichTextEditorView *)self.delegate; + ReactNativeRichTextEditorView *typedEditor = (ReactNativeRichTextEditorView *)_editor; if(typedEditor == nullptr) { return; } NSString *plainText = [typedEditor->textView.textStorage.string substringWithRange:typedEditor->textView.selectedRange]; @@ -27,7 +27,7 @@ - (void)copy:(id)sender { } - (void)paste:(id)sender { - ReactNativeRichTextEditorView *typedEditor = (ReactNativeRichTextEditorView *)self.delegate; + ReactNativeRichTextEditorView *typedEditor = (ReactNativeRichTextEditorView *)_editor; if(typedEditor == nullptr) { return; } UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; @@ -61,8 +61,8 @@ - (void)paste:(id)sender { if([pasteboardTypes containsObject:UTTypePlainText.identifier]) { NSString *plainString = [pasteboard valueForPasteboardType:UTTypePlainText.identifier]; currentRange.length > 0 - ? [TextInsertionUtils replaceText:plainString inView:typedEditor->textView at:currentRange additionalAttributes:nullptr] - : [TextInsertionUtils insertText:plainString inView:typedEditor->textView at:currentRange.location additionalAttributes:nullptr]; + ? [TextInsertionUtils replaceText:plainString inView:typedEditor->textView at:currentRange additionalAttributes:nullptr editor:typedEditor] + : [TextInsertionUtils insertText:plainString inView:typedEditor->textView at:currentRange.location additionalAttributes:nullptr editor:typedEditor]; } } } else if([pasteboardTypes containsObject:UTTypePlainText.identifier]) { @@ -70,17 +70,17 @@ - (void)paste:(id)sender { NSString *plainString = [pasteboard valueForPasteboardType:UTTypePlainText.identifier]; currentRange.length > 0 - ? [TextInsertionUtils replaceText:plainString inView:typedEditor->textView at:currentRange additionalAttributes:nullptr] - : [TextInsertionUtils insertText:plainString inView:typedEditor->textView at:currentRange.location additionalAttributes:nullptr]; + ? [TextInsertionUtils replaceText:plainString inView:typedEditor->textView at:currentRange additionalAttributes:nullptr editor:typedEditor] + : [TextInsertionUtils insertText:plainString inView:typedEditor->textView at:currentRange.location additionalAttributes:nullptr editor:typedEditor]; } } - (void)cut:(id)sender { - ReactNativeRichTextEditorView *typedEditor = (ReactNativeRichTextEditorView *)self.delegate; + ReactNativeRichTextEditorView *typedEditor = (ReactNativeRichTextEditorView *)_editor; if(typedEditor == nullptr) { return; } [self copy:sender]; - [TextInsertionUtils replaceText:@"" inView:typedEditor->textView at:typedEditor->textView.selectedRange additionalAttributes:nullptr]; + [TextInsertionUtils replaceText:@"" inView:typedEditor->textView at:typedEditor->textView.selectedRange additionalAttributes:nullptr editor:typedEditor]; } @end diff --git a/ios/parser/EditorParser.mm b/ios/parser/EditorParser.mm index e0bff1035..573a8a561 100644 --- a/ios/parser/EditorParser.mm +++ b/ios/parser/EditorParser.mm @@ -354,7 +354,7 @@ - (void)replaceFromHtml:(NSString * _Nonnull)html range:(NSRange)range { NSArray *stylesInfo = (NSArray *)processingResult[1]; // we can use ready replace util - [TextInsertionUtils replaceText:plainText inView:_editor->textView at:range additionalAttributes:nil]; + [TextInsertionUtils replaceText:plainText inView:_editor->textView at:range additionalAttributes:nil editor:_editor]; [self applyProcessedStyles:stylesInfo offsetFromBeginning:range.location]; [_editor anyTextMayHaveBeenModified]; @@ -366,7 +366,7 @@ - (void)insertFromHtml:(NSString * _Nonnull)html location:(NSInteger)location { NSArray *stylesInfo = (NSArray *)processingResult[1]; // same here, insertion utils got our back - [TextInsertionUtils insertText:plainText inView:_editor->textView at:location additionalAttributes:nil]; + [TextInsertionUtils insertText:plainText inView:_editor->textView at:location additionalAttributes:nil editor:_editor]; [self applyProcessedStyles:stylesInfo offsetFromBeginning:location]; [_editor anyTextMayHaveBeenModified]; diff --git a/ios/styles/LinkStyle.mm b/ios/styles/LinkStyle.mm index ecd3620b7..ce12f064d 100644 --- a/ios/styles/LinkStyle.mm +++ b/ios/styles/LinkStyle.mm @@ -140,7 +140,7 @@ - (void)addLink:(NSString*)text url:(NSString*)url range:(NSRange)range manual:( if(range.length == 0) { // insert link - [TextInsertionUtils insertText:text inView:_editor->textView at:range.location additionalAttributes:newAttrs]; + [TextInsertionUtils insertText:text inView:_editor->textView at:range.location additionalAttributes:newAttrs editor:_editor]; } else if([currentText isEqualToString:text]) { // apply link attributes [_editor->textView.textStorage addAttributes:newAttrs range:range]; @@ -152,7 +152,7 @@ - (void)addLink:(NSString*)text url:(NSString*)url range:(NSRange)range manual:( } } else { // replace text with link - [TextInsertionUtils replaceText:text inView:_editor->textView at:range additionalAttributes:newAttrs]; + [TextInsertionUtils replaceText:text inView:_editor->textView at:range additionalAttributes:newAttrs editor:_editor]; } // mandatory connected links check diff --git a/ios/styles/MentionStyle.mm b/ios/styles/MentionStyle.mm index b1997e1a4..7f74f7fd8 100644 --- a/ios/styles/MentionStyle.mm +++ b/ios/styles/MentionStyle.mm @@ -164,7 +164,7 @@ - (void)addMention:(NSString *)indicator text:(NSString *)text attributes:(NSStr // add a single space after the mention NSString *newText = [NSString stringWithFormat:@"%@ ", text]; NSRange rangeToBeReplaced = [_activeMentionRange rangeValue]; - [TextInsertionUtils replaceText:newText inView: _editor->textView at:rangeToBeReplaced additionalAttributes:nullptr]; + [TextInsertionUtils replaceText:newText inView: _editor->textView at:rangeToBeReplaced additionalAttributes:nullptr editor:_editor]; // THEN, add the attributes to not apply them on the space [_editor->textView.textStorage addAttributes:newAttrs range:NSMakeRange(rangeToBeReplaced.location, text.length)]; @@ -230,9 +230,9 @@ - (void)startMentionWithIndicator:(NSString *)indicator { NSRange newSelect = NSMakeRange(currentRange.location + finalString.length + (addSpaceAfter ? -1 : 0), 0); if(currentRange.length == 0) { - [TextInsertionUtils insertText:finalString inView:_editor->textView at:currentRange.location additionalAttributes:nullptr]; + [TextInsertionUtils insertText:finalString inView:_editor->textView at:currentRange.location additionalAttributes:nullptr editor:_editor]; } else { - [TextInsertionUtils replaceText:finalString inView:_editor->textView at:currentRange additionalAttributes:nullptr]; + [TextInsertionUtils replaceText:finalString inView:_editor->textView at:currentRange additionalAttributes:nullptr editor:_editor]; } [_editor->textView reactFocus]; diff --git a/ios/styles/OrderedListStyle.mm b/ios/styles/OrderedListStyle.mm index 3af05aa75..b2740bec1 100644 --- a/ios/styles/OrderedListStyle.mm +++ b/ios/styles/OrderedListStyle.mm @@ -49,7 +49,7 @@ - (void)addAttributes:(NSRange)range { NSRange fixedRange = NSMakeRange([value rangeValue].location + offset, [value rangeValue].length); if(fixedRange.length == 0) { - [TextInsertionUtils insertText:@" " inView:_editor->textView at:fixedRange.location additionalAttributes:nullptr]; + [TextInsertionUtils insertText:@" " inView:_editor->textView at:fixedRange.location additionalAttributes:nullptr editor:_editor]; fixedRange = NSMakeRange(fixedRange.location, 1); offset += 1; } @@ -144,7 +144,7 @@ - (BOOL)handleBackspaceInRange:(NSRange)range replacementText:(NSString *)text { // if there is only a space left we should also remove it as it's apple's placholder for empty lists if([[_editor->textView.textStorage.string substringWithRange:paragraphRange] isEqualToString:@" "]) { - [TextInsertionUtils replaceText:@"" inView:_editor->textView at:paragraphRange additionalAttributes:nullptr]; + [TextInsertionUtils replaceText:@"" inView:_editor->textView at:paragraphRange additionalAttributes:nullptr editor:_editor]; return YES; } } @@ -166,7 +166,7 @@ - (BOOL)tryHandlingListShorcutInRange:(NSRange)range replacementText:(NSString * } // remove the number - [TextInsertionUtils replaceText:@"" inView:_editor->textView at:NSMakeRange(paragraphRange.location, 1) additionalAttributes:nullptr]; + [TextInsertionUtils replaceText:@"" inView:_editor->textView at:NSMakeRange(paragraphRange.location, 1) additionalAttributes:nullptr editor:_editor]; if(prevEmitHtml) { _editor->emitHtml = YES; diff --git a/ios/styles/UnorderedListStyle.mm b/ios/styles/UnorderedListStyle.mm index 7da7fc492..01057f89d 100644 --- a/ios/styles/UnorderedListStyle.mm +++ b/ios/styles/UnorderedListStyle.mm @@ -49,7 +49,7 @@ - (void)addAttributes:(NSRange)range { NSRange fixedRange = NSMakeRange([value rangeValue].location + offset, [value rangeValue].length); if(fixedRange.length == 0) { - [TextInsertionUtils insertText:@" " inView:_editor->textView at:fixedRange.location additionalAttributes:nullptr]; + [TextInsertionUtils insertText:@" " inView:_editor->textView at:fixedRange.location additionalAttributes:nullptr editor:_editor]; fixedRange = NSMakeRange(fixedRange.location, 1); offset += 1; } @@ -144,7 +144,7 @@ - (BOOL)handleBackspaceInRange:(NSRange)range replacementText:(NSString *)text { // if there is only a space left we should also remove it as it's apple's placholder for empty lists if([[_editor->textView.textStorage.string substringWithRange:paragraphRange] isEqualToString:@" "]) { - [TextInsertionUtils replaceText:@"" inView:_editor->textView at:paragraphRange additionalAttributes:nullptr]; + [TextInsertionUtils replaceText:@"" inView:_editor->textView at:paragraphRange additionalAttributes:nullptr editor:_editor]; return YES; } } @@ -166,7 +166,7 @@ - (BOOL)tryHandlingListShorcutInRange:(NSRange)range replacementText:(NSString * } // remove the dash - [TextInsertionUtils replaceText:@"" inView:_editor->textView at:NSMakeRange(paragraphRange.location, 1) additionalAttributes:nullptr]; + [TextInsertionUtils replaceText:@"" inView:_editor->textView at:NSMakeRange(paragraphRange.location, 1) additionalAttributes:nullptr editor:_editor]; if(prevEmitHtml) { _editor->emitHtml = YES; diff --git a/ios/utils/TextInsertionUtils.h b/ios/utils/TextInsertionUtils.h index 0a5241942..d9f97914e 100644 --- a/ios/utils/TextInsertionUtils.h +++ b/ios/utils/TextInsertionUtils.h @@ -1,6 +1,7 @@ #import +#import "ReactNativeRichTextEditorView.h" @interface TextInsertionUtils : NSObject -+ (void)insertText:(NSString*)text inView:(UITextView*)textView at:(NSInteger)index additionalAttributes:(NSDictionary*)additionalAttrs; -+ (void)replaceText:(NSString*)text inView:(UITextView*)textView at:(NSRange)range additionalAttributes:(NSDictionary*)additionalAttrs; ++ (void)insertText:(NSString*)text inView:(UITextView*)textView at:(NSInteger)index additionalAttributes:(NSDictionary*)additionalAttrs editor:(ReactNativeRichTextEditorView *)editor; ++ (void)replaceText:(NSString*)text inView:(UITextView*)textView at:(NSRange)range additionalAttributes:(NSDictionary*)additionalAttrs editor:(ReactNativeRichTextEditorView *)editor; @end diff --git a/ios/utils/TextInsertionUtils.mm b/ios/utils/TextInsertionUtils.mm index b6243561a..5fef5afbf 100644 --- a/ios/utils/TextInsertionUtils.mm +++ b/ios/utils/TextInsertionUtils.mm @@ -1,9 +1,9 @@ #import "TextInsertionUtils.h" #import "UIView+React.h" -#import "ReactNativeRichTextEditorView.h" + @implementation TextInsertionUtils -+ (void)insertText:(NSString*)text inView:(UITextView*)textView at:(NSInteger)index additionalAttributes:(NSDictionary*)additionalAttrs { ++ (void)insertText:(NSString*)text inView:(UITextView*)textView at:(NSInteger)index additionalAttributes:(NSDictionary*)additionalAttrs editor:(ReactNativeRichTextEditorView *)editor { NSMutableDictionary *copiedAttrs = [textView.typingAttributes mutableCopy]; if(additionalAttrs != nullptr) { [copiedAttrs addEntriesFromDictionary: additionalAttrs]; @@ -15,13 +15,12 @@ + (void)insertText:(NSString*)text inView:(UITextView*)textView at:(NSInteger)in [textView reactFocus]; textView.selectedRange = NSMakeRange(index + text.length, 0); - ReactNativeRichTextEditorView *typedEditor = (ReactNativeRichTextEditorView *)textView.delegate; - if(typedEditor != nullptr) { - typedEditor->recentlyChangedRange = NSMakeRange(index, text.length); + if(editor != nullptr) { + editor->recentlyChangedRange = NSMakeRange(index, text.length); } } -+ (void)replaceText:(NSString*)text inView:(UITextView*)textView at:(NSRange)range additionalAttributes:(NSDictionary*)additionalAttrs { ++ (void)replaceText:(NSString*)text inView:(UITextView*)textView at:(NSRange)range additionalAttributes:(NSDictionary*)additionalAttrs editor:(ReactNativeRichTextEditorView *)editor { [textView.textStorage replaceCharactersInRange:range withString:text]; if(additionalAttrs != nullptr) { [textView.textStorage addAttributes:additionalAttrs range:NSMakeRange(range.location, [text length])]; @@ -30,9 +29,8 @@ + (void)replaceText:(NSString*)text inView:(UITextView*)textView at:(NSRange)ran [textView reactFocus]; textView.selectedRange = NSMakeRange(range.location + text.length, 0); - ReactNativeRichTextEditorView *typedEditor = (ReactNativeRichTextEditorView *)textView.delegate; - if(typedEditor != nullptr) { - typedEditor->recentlyChangedRange = NSMakeRange(range.location, text.length); + if(editor != nullptr) { + editor->recentlyChangedRange = NSMakeRange(range.location, text.length); } } @end