react-native-enriched 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +3 -9
  2. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +4 -1
  3. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +2 -1
  4. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.cpp +5 -0
  5. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.h +1 -45
  6. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt +53 -12
  7. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewLayoutManager.kt +7 -56
  8. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +19 -22
  9. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewPackage.kt +2 -0
  10. package/android/src/main/java/com/swmansion/enriched/MeasurementStore.kt +158 -0
  11. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedCodeBlockSpan.kt +36 -1
  12. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedImageSpan.kt +132 -11
  13. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedSpans.kt +65 -46
  14. package/android/src/main/java/com/swmansion/enriched/spans/utils/ForceRedrawSpan.kt +13 -0
  15. package/android/src/main/java/com/swmansion/enriched/styles/HtmlStyle.kt +2 -9
  16. package/android/src/main/java/com/swmansion/enriched/styles/InlineStyles.kt +1 -0
  17. package/android/src/main/java/com/swmansion/enriched/styles/ParagraphStyles.kt +110 -3
  18. package/android/src/main/java/com/swmansion/enriched/styles/ParametrizedStyles.kt +75 -32
  19. package/android/src/main/java/com/swmansion/enriched/utils/AsyncDrawable.kt +91 -0
  20. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java +38 -15
  21. package/android/src/main/java/com/swmansion/enriched/utils/ResourceManager.kt +26 -0
  22. package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedSpanWatcher.kt +3 -1
  23. package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedTextWatcher.kt +1 -1
  24. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.cpp +15 -2
  25. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.h +1 -0
  26. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.cpp +1 -2
  27. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/conversions.h +27 -0
  28. package/android/src/main/res/drawable/broken_image.xml +10 -0
  29. package/ios/EnrichedTextInputView.h +3 -1
  30. package/ios/EnrichedTextInputView.mm +167 -68
  31. package/ios/config/InputConfig.h +6 -0
  32. package/ios/config/InputConfig.mm +32 -0
  33. package/ios/generated/RNEnrichedTextInputViewSpec/Props.cpp +5 -0
  34. package/ios/generated/RNEnrichedTextInputViewSpec/Props.h +1 -45
  35. package/ios/generated/RNEnrichedTextInputViewSpec/RCTComponentViewHelpers.h +20 -4
  36. package/ios/inputParser/InputParser.mm +179 -31
  37. package/ios/inputTextView/InputTextView.mm +3 -5
  38. package/ios/internals/EnrichedTextInputViewShadowNode.h +1 -0
  39. package/ios/internals/EnrichedTextInputViewShadowNode.mm +29 -17
  40. package/ios/styles/BlockQuoteStyle.mm +5 -26
  41. package/ios/styles/BoldStyle.mm +2 -0
  42. package/ios/styles/CodeBlockStyle.mm +228 -0
  43. package/ios/styles/H1Style.mm +1 -0
  44. package/ios/styles/H2Style.mm +1 -0
  45. package/ios/styles/H3Style.mm +1 -0
  46. package/ios/styles/ImageStyle.mm +158 -0
  47. package/ios/styles/InlineCodeStyle.mm +2 -0
  48. package/ios/styles/ItalicStyle.mm +2 -0
  49. package/ios/styles/LinkStyle.mm +15 -7
  50. package/ios/styles/MentionStyle.mm +133 -36
  51. package/ios/styles/OrderedListStyle.mm +5 -8
  52. package/ios/styles/StrikethroughStyle.mm +2 -0
  53. package/ios/styles/UnderlineStyle.mm +2 -0
  54. package/ios/styles/UnorderedListStyle.mm +5 -8
  55. package/ios/utils/BaseStyleProtocol.h +1 -0
  56. package/ios/utils/ImageData.h +10 -0
  57. package/ios/utils/ImageData.mm +4 -0
  58. package/ios/utils/LayoutManagerExtension.mm +118 -3
  59. package/ios/utils/OccurenceUtils.h +4 -0
  60. package/ios/utils/OccurenceUtils.mm +47 -0
  61. package/ios/utils/ParagraphAttributesUtils.h +1 -0
  62. package/ios/utils/ParagraphAttributesUtils.mm +87 -20
  63. package/ios/utils/StringExtension.h +1 -1
  64. package/ios/utils/StringExtension.mm +17 -8
  65. package/ios/utils/StyleHeaders.h +12 -0
  66. package/ios/utils/ZeroWidthSpaceUtils.mm +22 -10
  67. package/lib/module/EnrichedTextInput.js +4 -2
  68. package/lib/module/EnrichedTextInput.js.map +1 -1
  69. package/lib/module/EnrichedTextInputNativeComponent.ts +7 -5
  70. package/lib/module/normalizeHtmlStyle.js +0 -4
  71. package/lib/module/normalizeHtmlStyle.js.map +1 -1
  72. package/lib/typescript/src/EnrichedTextInput.d.ts +3 -6
  73. package/lib/typescript/src/EnrichedTextInput.d.ts.map +1 -1
  74. package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts +2 -5
  75. package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts.map +1 -1
  76. package/lib/typescript/src/normalizeHtmlStyle.d.ts.map +1 -1
  77. package/package.json +1 -1
  78. package/src/EnrichedTextInput.tsx +6 -7
  79. package/src/EnrichedTextInputNativeComponent.ts +7 -5
  80. package/src/normalizeHtmlStyle.ts +0 -4
@@ -0,0 +1,228 @@
1
+ #import "StyleHeaders.h"
2
+ #import "EnrichedTextInputView.h"
3
+ #import "FontExtension.h"
4
+ #import "OccurenceUtils.h"
5
+ #import "ParagraphsUtils.h"
6
+ #import "TextInsertionUtils.h"
7
+ #import "ColorExtension.h"
8
+
9
+ @implementation CodeBlockStyle {
10
+ EnrichedTextInputView *_input;
11
+ NSArray *_stylesToExclude;
12
+ }
13
+
14
+ + (StyleType)getStyleType { return CodeBlock; }
15
+
16
+ + (BOOL)isParagraphStyle { return YES; }
17
+
18
+ - (instancetype)initWithInput:(id)input {
19
+ self = [super init];
20
+ _input = (EnrichedTextInputView *)input;
21
+ _stylesToExclude = @[ @(InlineCode), @(Mention), @(Link) ];
22
+ return self;
23
+ }
24
+
25
+ - (void)applyStyle:(NSRange)range {
26
+ BOOL isStylePresent = [self detectStyle:range];
27
+ if(range.length >= 1) {
28
+ isStylePresent ? [self removeAttributes:range] : [self addAttributes:range];
29
+ } else {
30
+ isStylePresent ? [self removeTypingAttributes] : [self addTypingAttributes];
31
+ }
32
+ }
33
+
34
+ - (void)addAttributes:(NSRange)range {
35
+ NSTextList *codeBlockList = [[NSTextList alloc] initWithMarkerFormat:@"codeblock" options:0];
36
+ NSArray *paragraphs = [ParagraphsUtils getSeparateParagraphsRangesIn:_input->textView range:range];
37
+ // if we fill empty lines with zero width spaces, we need to offset later ranges
38
+ NSInteger offset = 0;
39
+ NSRange preModificationRange = _input->textView.selectedRange;
40
+
41
+ // to not emit any space filling selection/text changes
42
+ _input->blockEmitting = YES;
43
+
44
+ for (NSValue *value in paragraphs) {
45
+ NSRange pRange = NSMakeRange([value rangeValue].location + offset, [value rangeValue].length);
46
+ // length 0 with first line, length 1 and newline with some empty lines in the middle
47
+ if(pRange.length == 0 ||
48
+ (pRange.length == 1 &&
49
+ [[NSCharacterSet newlineCharacterSet] characterIsMember: [_input->textView.textStorage.string characterAtIndex:pRange.location]])
50
+ ) {
51
+ [TextInsertionUtils insertText:@"\u200B" at:pRange.location additionalAttributes:nullptr input:_input withSelection:NO];
52
+ pRange = NSMakeRange(pRange.location, pRange.length + 1);
53
+ offset += 1;
54
+ }
55
+
56
+ [_input->textView.textStorage enumerateAttribute:NSParagraphStyleAttributeName inRange:pRange options:0
57
+ usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
58
+ NSMutableParagraphStyle *pStyle = [(NSParagraphStyle *)value mutableCopy];
59
+ pStyle.textLists = @[codeBlockList];
60
+ [_input->textView.textStorage addAttribute:NSParagraphStyleAttributeName value:pStyle range:range];
61
+ }
62
+ ];
63
+ }
64
+
65
+ // back to emitting
66
+ _input->blockEmitting = NO;
67
+
68
+ if(preModificationRange.length == 0) {
69
+ // fix selection if only one line was possibly made a list and filled with a space
70
+ _input->textView.selectedRange = preModificationRange;
71
+ } else {
72
+ // in other cases, fix the selection with newly made offsets
73
+ _input->textView.selectedRange = NSMakeRange(preModificationRange.location, preModificationRange.length + offset);
74
+ }
75
+
76
+ // also add typing attributes
77
+ NSMutableDictionary *typingAttrs = [_input->textView.typingAttributes mutableCopy];
78
+ NSMutableParagraphStyle *pStyle = [typingAttrs[NSParagraphStyleAttributeName] mutableCopy];
79
+ pStyle.textLists = @[codeBlockList];
80
+ typingAttrs[NSParagraphStyleAttributeName] = pStyle;
81
+
82
+ _input->textView.typingAttributes = typingAttrs;
83
+ }
84
+
85
+ - (void)addTypingAttributes {
86
+ [self addAttributes:_input->textView.selectedRange];
87
+ }
88
+
89
+ - (void)removeAttributes:(NSRange)range {
90
+ NSArray *paragraphs = [ParagraphsUtils getSeparateParagraphsRangesIn:_input->textView range:range];
91
+
92
+ [_input->textView.textStorage beginEditing];
93
+
94
+ for(NSValue *value in paragraphs) {
95
+ NSRange pRange = [value rangeValue];
96
+
97
+ [_input->textView.textStorage enumerateAttribute:NSParagraphStyleAttributeName inRange:pRange options:0
98
+ usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
99
+ NSMutableParagraphStyle *pStyle = [(NSParagraphStyle *)value mutableCopy];
100
+ pStyle.textLists = @[];
101
+ [_input->textView.textStorage addAttribute:NSParagraphStyleAttributeName value:pStyle range:range];
102
+ }
103
+ ];
104
+ }
105
+
106
+ [_input->textView.textStorage endEditing];
107
+
108
+ // also remove typing attributes
109
+ NSMutableDictionary *typingAttrs = [_input->textView.typingAttributes mutableCopy];
110
+ NSMutableParagraphStyle *pStyle = [typingAttrs[NSParagraphStyleAttributeName] mutableCopy];
111
+ pStyle.textLists = @[];
112
+
113
+ typingAttrs[NSParagraphStyleAttributeName] = pStyle;
114
+
115
+ _input->textView.typingAttributes = typingAttrs;
116
+ }
117
+
118
+ - (void)removeTypingAttributes {
119
+ [self removeAttributes:_input->textView.selectedRange];
120
+ }
121
+
122
+ - (BOOL)handleBackspaceInRange:(NSRange)range replacementText:(NSString *)text {
123
+ if([self detectStyle:_input->textView.selectedRange] && text.length == 0) {
124
+ // backspace while the style is active
125
+
126
+ NSRange paragraphRange = [_input->textView.textStorage.string paragraphRangeForRange:_input->textView.selectedRange];
127
+
128
+ if(NSEqualRanges(_input->textView.selectedRange, NSMakeRange(0, 0))) {
129
+ // a backspace on the very first input's line quote
130
+ // it doesn't run textVieDidChange so we need to manually remove attributes
131
+ [self removeAttributes:paragraphRange];
132
+ return YES;
133
+ }
134
+ }
135
+ return NO;
136
+ }
137
+
138
+ - (BOOL)styleCondition:(id _Nullable)value :(NSRange)range {
139
+ NSParagraphStyle *paragraph = (NSParagraphStyle *)value;
140
+ return paragraph != nullptr && paragraph.textLists.count == 1 && [paragraph.textLists.firstObject.markerFormat isEqualToString:@"codeblock"];
141
+ }
142
+
143
+ - (BOOL)detectStyle:(NSRange)range {
144
+ if(range.length >= 1) {
145
+ return [OccurenceUtils detect:NSParagraphStyleAttributeName withInput:_input inRange:range
146
+ withCondition: ^BOOL(id _Nullable value, NSRange range) {
147
+ return [self styleCondition:value :range];
148
+ }
149
+ ];
150
+ } else {
151
+ return [OccurenceUtils detect:NSParagraphStyleAttributeName withInput:_input atIndex:range.location checkPrevious:YES
152
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
153
+ return [self styleCondition:value :range];
154
+ }
155
+ ];
156
+ }
157
+ }
158
+
159
+ - (BOOL)anyOccurence:(NSRange)range {
160
+ return [OccurenceUtils any:NSParagraphStyleAttributeName withInput:_input inRange:range
161
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
162
+ return [self styleCondition:value :range];
163
+ }
164
+ ];
165
+ }
166
+
167
+ - (NSArray<StylePair *> *_Nullable)findAllOccurences:(NSRange)range {
168
+ return [OccurenceUtils all:NSParagraphStyleAttributeName withInput:_input inRange:range
169
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
170
+ return [self styleCondition:value :range];
171
+ }
172
+ ];
173
+ }
174
+
175
+ - (void)manageCodeBlockFontAndColor {
176
+ if([[_input->config codeBlockFgColor] isEqualToColor:[_input->config primaryColor]]) {
177
+ return;
178
+ }
179
+
180
+ NSRange wholeRange = NSMakeRange(0, _input->textView.textStorage.string.length);
181
+ NSArray *paragraphs = [ParagraphsUtils getSeparateParagraphsRangesIn:_input->textView range:wholeRange];
182
+
183
+ for(NSValue *pValue in paragraphs) {
184
+ NSRange paragraphRange = [pValue rangeValue];
185
+ NSArray *properRanges = [OccurenceUtils getRangesWithout:_stylesToExclude withInput:_input inRange:paragraphRange];
186
+
187
+ for(NSValue *value in properRanges) {
188
+ NSRange currRange = [value rangeValue];
189
+ BOOL selfDetected = [self detectStyle:currRange];
190
+
191
+ [_input->textView.textStorage enumerateAttribute:NSFontAttributeName inRange:currRange options:0
192
+ usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
193
+ UIFont *currentFont = (UIFont *)value;
194
+ UIFont *newFont = nullptr;
195
+
196
+ BOOL isCodeFont = [[currentFont familyName] isEqualToString:[[_input->config monospacedFont] familyName]];
197
+
198
+ if (isCodeFont && !selfDetected) {
199
+ newFont = [[[_input->config primaryFont] withFontTraits:currentFont] setSize:currentFont.pointSize];
200
+ } else if (!isCodeFont && selfDetected) {
201
+ newFont = [[[_input->config monospacedFont] withFontTraits:currentFont] setSize:currentFont.pointSize];
202
+ }
203
+
204
+ if (newFont != nullptr) {
205
+ [_input->textView.textStorage addAttribute:NSFontAttributeName value:newFont range:range];
206
+ }
207
+ }];
208
+
209
+ [_input->textView.textStorage enumerateAttribute:NSForegroundColorAttributeName inRange:currRange options:0
210
+ usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
211
+ UIColor *newColor = nullptr;
212
+ BOOL colorApplied = [(UIColor *)value isEqualToColor:[_input->config codeBlockFgColor]];
213
+
214
+ if(colorApplied && !selfDetected) {
215
+ newColor = [_input->config primaryColor];
216
+ } else if(!colorApplied && selfDetected) {
217
+ newColor = [_input->config codeBlockFgColor];
218
+ }
219
+
220
+ if(newColor != nullptr) {
221
+ [_input->textView.textStorage addAttribute:NSForegroundColorAttributeName value:newColor range:range];
222
+ }
223
+ }];
224
+ }
225
+ }
226
+ }
227
+
228
+ @end
@@ -3,6 +3,7 @@
3
3
 
4
4
  @implementation H1Style
5
5
  + (StyleType)getStyleType { return H1; }
6
+ + (BOOL)isParagraphStyle { return YES; }
6
7
  - (CGFloat)getHeadingFontSize { return [((EnrichedTextInputView *)input)->config h1FontSize]; }
7
8
  - (BOOL)isHeadingBold {
8
9
  return [((EnrichedTextInputView *)input)->config h1Bold];
@@ -3,6 +3,7 @@
3
3
 
4
4
  @implementation H2Style
5
5
  + (StyleType)getStyleType { return H2; }
6
+ + (BOOL)isParagraphStyle { return YES; }
6
7
  - (CGFloat)getHeadingFontSize { return [((EnrichedTextInputView *)input)->config h2FontSize]; }
7
8
  - (BOOL)isHeadingBold {
8
9
  return [((EnrichedTextInputView *)input)->config h2Bold];
@@ -3,6 +3,7 @@
3
3
 
4
4
  @implementation H3Style
5
5
  + (StyleType)getStyleType { return H3; }
6
+ + (BOOL)isParagraphStyle { return YES; }
6
7
  - (CGFloat)getHeadingFontSize { return [((EnrichedTextInputView *)input)->config h3FontSize]; }
7
8
  - (BOOL)isHeadingBold {
8
9
  return [((EnrichedTextInputView *)input)->config h3Bold];
@@ -0,0 +1,158 @@
1
+ #import "StyleHeaders.h"
2
+ #import "EnrichedTextInputView.h"
3
+ #import "OccurenceUtils.h"
4
+ #import "TextInsertionUtils.h"
5
+
6
+ // custom NSAttributedStringKey to differentiate the image
7
+ static NSString *const ImageAttributeName = @"ImageAttributeName";
8
+
9
+ @implementation ImageStyle {
10
+ EnrichedTextInputView *_input;
11
+ }
12
+
13
+ + (StyleType)getStyleType { return Image; }
14
+
15
+ + (BOOL)isParagraphStyle { return NO; }
16
+
17
+ - (instancetype)initWithInput:(id)input {
18
+ self = [super init];
19
+ _input = (EnrichedTextInputView *)input;
20
+ return self;
21
+ }
22
+
23
+ - (void)applyStyle:(NSRange)range {
24
+ // no-op for image
25
+ }
26
+
27
+ - (void)addAttributes:(NSRange)range {
28
+ // no-op for image
29
+ }
30
+
31
+ - (void)addTypingAttributes {
32
+ // no-op for image
33
+ }
34
+
35
+ - (void)removeAttributes:(NSRange)range {
36
+ [_input->textView.textStorage beginEditing];
37
+ [_input->textView.textStorage removeAttribute:ImageAttributeName range:range];
38
+ [_input->textView.textStorage removeAttribute:NSAttachmentAttributeName range:range];
39
+ [_input->textView.textStorage endEditing];
40
+ }
41
+
42
+ - (void)removeTypingAttributes {
43
+ NSMutableDictionary *currentAttributes = [_input->textView.typingAttributes mutableCopy];
44
+ [currentAttributes removeObjectForKey:ImageAttributeName];
45
+ [currentAttributes removeObjectForKey:NSAttachmentAttributeName];
46
+ _input->textView.typingAttributes = currentAttributes;
47
+ }
48
+
49
+ - (BOOL)styleCondition:(id _Nullable)value :(NSRange)range {
50
+ return [value isKindOfClass:[ImageData class]];
51
+ }
52
+
53
+ - (BOOL)anyOccurence:(NSRange)range {
54
+ return [OccurenceUtils any:ImageAttributeName withInput:_input inRange:range
55
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
56
+ return [self styleCondition:value :range];
57
+ }
58
+ ];
59
+ }
60
+
61
+ - (BOOL)detectStyle:(NSRange)range {
62
+ if (range.length >= 1) {
63
+ return [OccurenceUtils detect:ImageAttributeName withInput:_input inRange:range
64
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
65
+ return [self styleCondition:value :range];
66
+ }
67
+ ];
68
+ } else {
69
+ return [OccurenceUtils detect:ImageAttributeName withInput:_input atIndex:range.location checkPrevious:YES
70
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
71
+ return [self styleCondition:value :range];
72
+ }
73
+ ];
74
+ }
75
+ }
76
+
77
+ - (NSArray<StylePair *> * _Nullable)findAllOccurences:(NSRange)range {
78
+ return [OccurenceUtils all:ImageAttributeName withInput:_input inRange:range
79
+ withCondition:^BOOL(id _Nullable value, NSRange range) {
80
+ return [self styleCondition:value :range];
81
+ }
82
+ ];
83
+ }
84
+
85
+ - (ImageData *)getImageDataAt:(NSUInteger)location
86
+ {
87
+ NSRange imageRange = NSMakeRange(0, 0);
88
+ NSRange inputRange = NSMakeRange(0, _input->textView.textStorage.length);
89
+
90
+ // don't search at the very end of input
91
+ NSUInteger searchLocation = location;
92
+ if(searchLocation == _input->textView.textStorage.length) {
93
+ return nullptr;
94
+ }
95
+
96
+ ImageData *imageData = [_input->textView.textStorage
97
+ attribute:ImageAttributeName
98
+ atIndex:searchLocation
99
+ longestEffectiveRange: &imageRange
100
+ inRange:inputRange
101
+ ];
102
+
103
+ return imageData;
104
+ }
105
+
106
+ - (void)addImageAtRange:(NSRange)range imageData:(ImageData *)imageData withSelection:(BOOL)withSelection
107
+ {
108
+ UIImage *img = [self prepareImageFromUri:imageData.uri];
109
+
110
+ NSDictionary *attributes = [@{
111
+ NSAttachmentAttributeName: [self prepareImageAttachement:img width:imageData.width height:imageData.height],
112
+ ImageAttributeName: imageData,
113
+ } mutableCopy];
114
+
115
+ // Use the Object Replacement Character for Image.
116
+ // This tells TextKit "something non-text goes here".
117
+ NSString *imagePlaceholder = @"\uFFFC";
118
+
119
+ if (range.length == 0) {
120
+ [TextInsertionUtils insertText:imagePlaceholder at:range.location additionalAttributes:attributes input:_input withSelection:withSelection];
121
+ } else {
122
+ [TextInsertionUtils replaceText:imagePlaceholder
123
+ at:range
124
+ additionalAttributes:attributes
125
+ input:_input
126
+ withSelection:withSelection];
127
+ }
128
+ }
129
+
130
+ - (void)addImage:(NSString *)uri width:(CGFloat)width height:(CGFloat)height {
131
+ ImageData *data = [[ImageData alloc] init];
132
+ data.uri = uri;
133
+ data.width = width;
134
+ data.height = height;
135
+
136
+ [self addImageAtRange:_input->textView.selectedRange imageData:data withSelection:YES];
137
+ }
138
+
139
+ -(NSTextAttachment *)prepareImageAttachement:(UIImage *)image width:(CGFloat)width height:(CGFloat)height
140
+ {
141
+
142
+ NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
143
+ attachment.image = image;
144
+ attachment.bounds = CGRectMake(0, 0, width, height);
145
+
146
+ return attachment;
147
+ }
148
+
149
+ - (UIImage *)prepareImageFromUri:(NSString *)uri
150
+ {
151
+ NSURL *url = [NSURL URLWithString:uri];
152
+ NSData *imgData = [NSData dataWithContentsOfURL:url];
153
+ UIImage *image = [UIImage imageWithData:imgData];
154
+
155
+ return image;
156
+ }
157
+
158
+ @end
@@ -11,6 +11,8 @@
11
11
 
12
12
  + (StyleType)getStyleType { return InlineCode; }
13
13
 
14
+ + (BOOL)isParagraphStyle { return NO; }
15
+
14
16
  - (instancetype)initWithInput:(id)input {
15
17
  self = [super init];
16
18
  _input = (EnrichedTextInputView *)input;
@@ -9,6 +9,8 @@
9
9
 
10
10
  + (StyleType)getStyleType { return Italic; }
11
11
 
12
+ + (BOOL)isParagraphStyle { return NO; }
13
+
12
14
  - (instancetype)initWithInput:(id)input {
13
15
  self = [super init];
14
16
  _input = (EnrichedTextInputView *)input;
@@ -15,6 +15,8 @@ static NSString *const AutomaticLinkAttributeName = @"AutomaticLinkAttributeName
15
15
 
16
16
  + (StyleType)getStyleType { return Link; }
17
17
 
18
+ + (BOOL)isParagraphStyle { return NO; }
19
+
18
20
  - (instancetype)initWithInput:(id)input {
19
21
  self = [super init];
20
22
  _input = (EnrichedTextInputView *)input;
@@ -167,7 +169,6 @@ static NSString *const AutomaticLinkAttributeName = @"AutomaticLinkAttributeName
167
169
  }
168
170
 
169
171
  [self manageLinkTypingAttributes];
170
- [_input anyTextMayHaveBeenModified];
171
172
  }
172
173
 
173
174
  // get exact link data at the given location if it exists
@@ -224,20 +225,22 @@ static NSString *const AutomaticLinkAttributeName = @"AutomaticLinkAttributeName
224
225
  }
225
226
  }
226
227
 
227
- [_input->textView.textStorage
228
+ NSString *manualLink = [_input->textView.textStorage
228
229
  attribute:ManualLinkAttributeName
229
230
  atIndex:searchLocation
230
231
  longestEffectiveRange: &manualLinkRange
231
232
  inRange:inputRange
232
233
  ];
233
- [_input->textView.textStorage
234
+ NSString *automaticLink = [_input->textView.textStorage
234
235
  attribute:AutomaticLinkAttributeName
235
236
  atIndex:searchLocation
236
237
  longestEffectiveRange: &automaticLinkRange
237
238
  inRange:inputRange
238
239
  ];
239
240
 
240
- return manualLinkRange.length == 0 ? automaticLinkRange : manualLinkRange;
241
+ return manualLink == nullptr
242
+ ? automaticLink == nullptr ? NSMakeRange(0, 0) : automaticLinkRange
243
+ : manualLinkRange;
241
244
  }
242
245
 
243
246
  - (void)manageLinkTypingAttributes {
@@ -279,6 +282,7 @@ static NSString *const AutomaticLinkAttributeName = @"AutomaticLinkAttributeName
279
282
  - (void)handleAutomaticLinks:(NSString *)word inRange:(NSRange)wordRange {
280
283
  InlineCodeStyle *inlineCodeStyle = [_input->stylesDict objectForKey:@([InlineCodeStyle getStyleType])];
281
284
  MentionStyle *mentionStyle = [_input->stylesDict objectForKey:@([MentionStyle getStyleType])];
285
+ CodeBlockStyle *codeBlockStyle = [_input->stylesDict objectForKey:@([CodeBlockStyle getStyleType])];
282
286
 
283
287
  if (inlineCodeStyle == nullptr || mentionStyle == nullptr) {
284
288
  return;
@@ -294,6 +298,11 @@ static NSString *const AutomaticLinkAttributeName = @"AutomaticLinkAttributeName
294
298
  return;
295
299
  }
296
300
 
301
+ // we don't recognize links in codeblocks
302
+ if ([codeBlockStyle anyOccurence:wordRange]) {
303
+ return;
304
+ }
305
+
297
306
  // remove connected different links
298
307
  [self removeConnectedLinksIfNeeded:word range:wordRange];
299
308
 
@@ -349,10 +358,9 @@ static NSString *const AutomaticLinkAttributeName = @"AutomaticLinkAttributeName
349
358
  }
350
359
  if(addStyle) {
351
360
  [self addLink:word url:regexPassedUrl range:wordRange manual:NO];
361
+ // emit onLinkDetected if style was added
362
+ [_input emitOnLinkDetectedEvent:word url:regexPassedUrl range:wordRange];
352
363
  }
353
-
354
- // emit onLinkDetected
355
- [_input emitOnLinkDetectedEvent:word url:regexPassedUrl range:wordRange];
356
364
  }
357
365
  }
358
366