react-native-enriched 0.2.0 → 0.2.1
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.
- package/README.md +1 -5
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +3 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +1 -0
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.cpp +10 -0
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.h +7 -0
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt +92 -0
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/events/MentionHandler.kt +1 -1
- package/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt +33 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBlockQuoteSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBoldSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedCodeBlockSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH1Span.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH2Span.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH3Span.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedImageSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedInlineCodeSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedItalicSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedLinkSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedMentionSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedOrderedListSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedSpans.kt +9 -3
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedStrikeThroughSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnderlineSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnorderedListSpan.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedSpan.kt +4 -0
- package/android/src/main/java/com/swmansion/enriched/styles/HtmlStyle.kt +78 -0
- package/android/src/main/java/com/swmansion/enriched/styles/ParagraphStyles.kt +80 -4
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java +8 -0
- package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.cpp +6 -6
- package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.h +6 -6
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputComponentDescriptor.h +19 -19
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.cpp +40 -51
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.h +13 -15
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.cpp +23 -21
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.h +35 -36
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputState.cpp +4 -4
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputState.h +13 -14
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/conversions.h +12 -13
- package/ios/EnrichedTextInputView.h +25 -13
- package/ios/EnrichedTextInputView.mm +872 -581
- package/ios/attachments/ImageAttachment.h +10 -0
- package/ios/attachments/ImageAttachment.mm +34 -0
- package/ios/attachments/MediaAttachment.h +23 -0
- package/ios/attachments/MediaAttachment.mm +31 -0
- package/ios/config/InputConfig.h +6 -6
- package/ios/config/InputConfig.mm +39 -33
- package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.cpp +10 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.h +7 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/RCTComponentViewHelpers.h +21 -0
- package/ios/inputParser/InputParser.h +5 -5
- package/ios/inputParser/InputParser.mm +789 -378
- package/ios/inputTextView/InputTextView.h +1 -1
- package/ios/inputTextView/InputTextView.mm +100 -59
- package/ios/internals/EnrichedTextInputViewComponentDescriptor.h +11 -9
- package/ios/internals/EnrichedTextInputViewShadowNode.h +28 -25
- package/ios/internals/EnrichedTextInputViewShadowNode.mm +45 -40
- package/ios/internals/EnrichedTextInputViewState.h +3 -1
- package/ios/styles/BlockQuoteStyle.mm +189 -118
- package/ios/styles/BoldStyle.mm +95 -63
- package/ios/styles/CodeBlockStyle.mm +204 -128
- package/ios/styles/H1Style.mm +10 -4
- package/ios/styles/H2Style.mm +10 -4
- package/ios/styles/H3Style.mm +10 -4
- package/ios/styles/HeadingStyleBase.mm +129 -84
- package/ios/styles/ImageStyle.mm +75 -73
- package/ios/styles/InlineCodeStyle.mm +148 -85
- package/ios/styles/ItalicStyle.mm +76 -52
- package/ios/styles/LinkStyle.mm +348 -227
- package/ios/styles/MentionStyle.mm +363 -246
- package/ios/styles/OrderedListStyle.mm +171 -106
- package/ios/styles/StrikethroughStyle.mm +52 -35
- package/ios/styles/UnderlineStyle.mm +68 -46
- package/ios/styles/UnorderedListStyle.mm +169 -106
- package/ios/utils/BaseStyleProtocol.h +2 -2
- package/ios/utils/ColorExtension.mm +7 -5
- package/ios/utils/FontExtension.mm +42 -27
- package/ios/utils/LayoutManagerExtension.h +1 -1
- package/ios/utils/LayoutManagerExtension.mm +280 -170
- package/ios/utils/MentionParams.h +0 -1
- package/ios/utils/MentionStyleProps.h +1 -1
- package/ios/utils/MentionStyleProps.mm +27 -20
- package/ios/utils/OccurenceUtils.h +42 -42
- package/ios/utils/OccurenceUtils.mm +142 -119
- package/ios/utils/ParagraphAttributesUtils.h +6 -2
- package/ios/utils/ParagraphAttributesUtils.mm +115 -71
- package/ios/utils/ParagraphsUtils.h +2 -1
- package/ios/utils/ParagraphsUtils.mm +40 -26
- package/ios/utils/StringExtension.h +1 -1
- package/ios/utils/StringExtension.mm +19 -16
- package/ios/utils/StyleHeaders.h +27 -15
- package/ios/utils/TextInsertionUtils.h +13 -2
- package/ios/utils/TextInsertionUtils.mm +38 -20
- package/ios/utils/WordsUtils.h +2 -1
- package/ios/utils/WordsUtils.mm +32 -22
- package/ios/utils/ZeroWidthSpaceUtils.h +3 -1
- package/ios/utils/ZeroWidthSpaceUtils.mm +145 -79
- package/lib/module/EnrichedTextInput.js +39 -1
- package/lib/module/EnrichedTextInput.js.map +1 -1
- package/lib/module/EnrichedTextInputNativeComponent.ts +11 -0
- package/lib/typescript/src/EnrichedTextInput.d.ts +1 -0
- package/lib/typescript/src/EnrichedTextInput.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts +6 -0
- package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts.map +1 -1
- package/package.json +8 -1
- package/src/EnrichedTextInput.tsx +45 -0
- package/src/EnrichedTextInputNativeComponent.ts +11 -0
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
#import "StyleHeaders.h"
|
|
2
1
|
#import "EnrichedTextInputView.h"
|
|
3
2
|
#import "FontExtension.h"
|
|
4
3
|
#import "OccurenceUtils.h"
|
|
4
|
+
#import "StyleHeaders.h"
|
|
5
5
|
#import "TextInsertionUtils.h"
|
|
6
6
|
|
|
7
7
|
@implementation HeadingStyleBase
|
|
8
8
|
|
|
9
9
|
// mock values since H1/2/3Style classes anyway are used
|
|
10
|
-
+ (StyleType)getStyleType {
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
+ (StyleType)getStyleType {
|
|
11
|
+
return None;
|
|
12
|
+
}
|
|
13
|
+
- (CGFloat)getHeadingFontSize {
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
- (BOOL)isHeadingBold {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
13
19
|
|
|
14
20
|
- (EnrichedTextInputView *)typedInput {
|
|
15
21
|
return (EnrichedTextInputView *)input;
|
|
@@ -25,41 +31,54 @@
|
|
|
25
31
|
// but if the paragraph is empty it still is of length 0
|
|
26
32
|
- (void)applyStyle:(NSRange)range {
|
|
27
33
|
BOOL isStylePresent = [self detectStyle:range];
|
|
28
|
-
if(range.length >= 1) {
|
|
29
|
-
isStylePresent ? [self removeAttributes:range]
|
|
34
|
+
if (range.length >= 1) {
|
|
35
|
+
isStylePresent ? [self removeAttributes:range]
|
|
36
|
+
: [self addAttributes:range withTypingAttr:YES];
|
|
30
37
|
} else {
|
|
31
38
|
isStylePresent ? [self removeTypingAttributes] : [self addTypingAttributes];
|
|
32
39
|
}
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
// the range will already be the proper full paragraph/s range
|
|
36
|
-
- (void)addAttributes:(NSRange)range {
|
|
43
|
+
- (void)addAttributes:(NSRange)range withTypingAttr:(BOOL)withTypingAttr {
|
|
37
44
|
[[self typedInput]->textView.textStorage beginEditing];
|
|
38
|
-
[[self typedInput]->textView.textStorage
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
[[self typedInput]->textView.textStorage
|
|
46
|
+
enumerateAttribute:NSFontAttributeName
|
|
47
|
+
inRange:range
|
|
48
|
+
options:0
|
|
49
|
+
usingBlock:^(id _Nullable value, NSRange range,
|
|
50
|
+
BOOL *_Nonnull stop) {
|
|
51
|
+
UIFont *font = (UIFont *)value;
|
|
52
|
+
if (font != nullptr) {
|
|
53
|
+
UIFont *newFont = [font setSize:[self getHeadingFontSize]];
|
|
54
|
+
if ([self isHeadingBold]) {
|
|
55
|
+
newFont = [newFont setBold];
|
|
56
|
+
}
|
|
57
|
+
[[self typedInput]->textView.textStorage
|
|
58
|
+
addAttribute:NSFontAttributeName
|
|
59
|
+
value:newFont
|
|
60
|
+
range:range];
|
|
61
|
+
}
|
|
62
|
+
}];
|
|
50
63
|
[[self typedInput]->textView.textStorage endEditing];
|
|
51
|
-
|
|
64
|
+
|
|
52
65
|
// also toggle typing attributes
|
|
53
|
-
|
|
66
|
+
if (withTypingAttr) {
|
|
67
|
+
[self addTypingAttributes];
|
|
68
|
+
}
|
|
54
69
|
}
|
|
55
70
|
|
|
56
|
-
// will always be called on empty paragraphs so only typing attributes can be
|
|
71
|
+
// will always be called on empty paragraphs so only typing attributes can be
|
|
72
|
+
// changed
|
|
57
73
|
- (void)addTypingAttributes {
|
|
58
|
-
UIFont *currentFontAttr =
|
|
59
|
-
|
|
60
|
-
|
|
74
|
+
UIFont *currentFontAttr =
|
|
75
|
+
(UIFont *)[self typedInput]
|
|
76
|
+
->textView.typingAttributes[NSFontAttributeName];
|
|
77
|
+
if (currentFontAttr != nullptr) {
|
|
78
|
+
NSMutableDictionary *newTypingAttrs =
|
|
79
|
+
[[self typedInput]->textView.typingAttributes mutableCopy];
|
|
61
80
|
UIFont *newFont = [currentFontAttr setSize:[self getHeadingFontSize]];
|
|
62
|
-
if([self isHeadingBold]) {
|
|
81
|
+
if ([self isHeadingBold]) {
|
|
63
82
|
newFont = [newFont setBold];
|
|
64
83
|
}
|
|
65
84
|
newTypingAttrs[NSFontAttributeName] = newFont;
|
|
@@ -69,28 +88,41 @@
|
|
|
69
88
|
|
|
70
89
|
// we need to remove the style from the whole paragraph
|
|
71
90
|
- (void)removeAttributes:(NSRange)range {
|
|
72
|
-
NSRange paragraphRange = [[self typedInput]->textView.textStorage.string
|
|
73
|
-
|
|
91
|
+
NSRange paragraphRange = [[self typedInput]->textView.textStorage.string
|
|
92
|
+
paragraphRangeForRange:range];
|
|
93
|
+
|
|
74
94
|
[[self typedInput]->textView.textStorage beginEditing];
|
|
75
|
-
[[self typedInput]->textView.textStorage
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
95
|
+
[[self typedInput]->textView.textStorage
|
|
96
|
+
enumerateAttribute:NSFontAttributeName
|
|
97
|
+
inRange:paragraphRange
|
|
98
|
+
options:0
|
|
99
|
+
usingBlock:^(id _Nullable value, NSRange range,
|
|
100
|
+
BOOL *_Nonnull stop) {
|
|
101
|
+
if ([self styleCondition:value:range]) {
|
|
102
|
+
UIFont *newFont = [(UIFont *)value
|
|
103
|
+
setSize:[[[self typedInput]->config primaryFontSize]
|
|
104
|
+
floatValue]];
|
|
105
|
+
if ([self isHeadingBold]) {
|
|
106
|
+
newFont = [newFont removeBold];
|
|
107
|
+
}
|
|
108
|
+
[[self typedInput]->textView.textStorage
|
|
109
|
+
addAttribute:NSFontAttributeName
|
|
110
|
+
value:newFont
|
|
111
|
+
range:range];
|
|
112
|
+
}
|
|
113
|
+
}];
|
|
86
114
|
[[self typedInput]->textView.textStorage endEditing];
|
|
87
|
-
|
|
115
|
+
|
|
88
116
|
// typing attributes still need to be removed
|
|
89
|
-
UIFont *currentFontAttr =
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
117
|
+
UIFont *currentFontAttr =
|
|
118
|
+
(UIFont *)[self typedInput]
|
|
119
|
+
->textView.typingAttributes[NSFontAttributeName];
|
|
120
|
+
if (currentFontAttr != nullptr) {
|
|
121
|
+
NSMutableDictionary *newTypingAttrs =
|
|
122
|
+
[[self typedInput]->textView.typingAttributes mutableCopy];
|
|
123
|
+
UIFont *newFont = [currentFontAttr
|
|
124
|
+
setSize:[[[self typedInput]->config primaryFontSize] floatValue]];
|
|
125
|
+
if ([self isHeadingBold]) {
|
|
94
126
|
newFont = [newFont removeBold];
|
|
95
127
|
}
|
|
96
128
|
newTypingAttrs[NSFontAttributeName] = newFont;
|
|
@@ -99,58 +131,67 @@
|
|
|
99
131
|
}
|
|
100
132
|
|
|
101
133
|
- (void)removeTypingAttributes {
|
|
102
|
-
// all the heading still needs to be removed because this function may be
|
|
103
|
-
// typing attributes already get removed in
|
|
134
|
+
// all the heading still needs to be removed because this function may be
|
|
135
|
+
// called in conflicting styles logic typing attributes already get removed in
|
|
136
|
+
// there as well
|
|
104
137
|
[self removeAttributes:[self typedInput]->textView.selectedRange];
|
|
105
138
|
}
|
|
106
139
|
|
|
107
|
-
- (BOOL)styleCondition:(id _Nullable)value
|
|
140
|
+
- (BOOL)styleCondition:(id _Nullable)value:(NSRange)range {
|
|
108
141
|
UIFont *font = (UIFont *)value;
|
|
109
142
|
return font != nullptr && font.pointSize == [self getHeadingFontSize];
|
|
110
143
|
}
|
|
111
144
|
|
|
112
145
|
- (BOOL)detectStyle:(NSRange)range {
|
|
113
|
-
if(range.length >= 1) {
|
|
114
|
-
return [OccurenceUtils detect:NSFontAttributeName
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
146
|
+
if (range.length >= 1) {
|
|
147
|
+
return [OccurenceUtils detect:NSFontAttributeName
|
|
148
|
+
withInput:[self typedInput]
|
|
149
|
+
inRange:range
|
|
150
|
+
withCondition:^BOOL(id _Nullable value, NSRange range) {
|
|
151
|
+
return [self styleCondition:value:range];
|
|
152
|
+
}];
|
|
119
153
|
} else {
|
|
120
|
-
return [OccurenceUtils detect:NSFontAttributeName
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
154
|
+
return [OccurenceUtils detect:NSFontAttributeName
|
|
155
|
+
withInput:[self typedInput]
|
|
156
|
+
atIndex:range.location
|
|
157
|
+
checkPrevious:YES
|
|
158
|
+
withCondition:^BOOL(id _Nullable value, NSRange range) {
|
|
159
|
+
return [self styleCondition:value:range];
|
|
160
|
+
}];
|
|
125
161
|
}
|
|
126
162
|
}
|
|
127
163
|
|
|
128
164
|
- (BOOL)anyOccurence:(NSRange)range {
|
|
129
|
-
return [OccurenceUtils any:NSFontAttributeName
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
165
|
+
return [OccurenceUtils any:NSFontAttributeName
|
|
166
|
+
withInput:[self typedInput]
|
|
167
|
+
inRange:range
|
|
168
|
+
withCondition:^BOOL(id _Nullable value, NSRange range) {
|
|
169
|
+
return [self styleCondition:value:range];
|
|
170
|
+
}];
|
|
134
171
|
}
|
|
135
172
|
|
|
136
173
|
- (NSArray<StylePair *> *_Nullable)findAllOccurences:(NSRange)range {
|
|
137
|
-
return [OccurenceUtils all:NSFontAttributeName
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
174
|
+
return [OccurenceUtils all:NSFontAttributeName
|
|
175
|
+
withInput:[self typedInput]
|
|
176
|
+
inRange:range
|
|
177
|
+
withCondition:^BOOL(id _Nullable value, NSRange range) {
|
|
178
|
+
return [self styleCondition:value:range];
|
|
179
|
+
}];
|
|
142
180
|
}
|
|
143
181
|
|
|
144
182
|
// used to make sure headings dont persist after a newline is placed
|
|
145
183
|
- (BOOL)handleNewlinesInRange:(NSRange)range replacementText:(NSString *)text {
|
|
146
184
|
// in a heading and a new text ends with a newline
|
|
147
|
-
if(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
) {
|
|
185
|
+
if ([self detectStyle:[self typedInput]->textView.selectedRange] &&
|
|
186
|
+
text.length > 0 &&
|
|
187
|
+
[[NSCharacterSet newlineCharacterSet]
|
|
188
|
+
characterIsMember:[text characterAtIndex:text.length - 1]]) {
|
|
152
189
|
// do the replacement manually
|
|
153
|
-
[TextInsertionUtils replaceText:text
|
|
190
|
+
[TextInsertionUtils replaceText:text
|
|
191
|
+
at:range
|
|
192
|
+
additionalAttributes:nullptr
|
|
193
|
+
input:[self typedInput]
|
|
194
|
+
withSelection:YES];
|
|
154
195
|
// remove the attribtues at the new selection
|
|
155
196
|
[self removeAttributes:[self typedInput]->textView.selectedRange];
|
|
156
197
|
return YES;
|
|
@@ -158,19 +199,23 @@
|
|
|
158
199
|
return NO;
|
|
159
200
|
}
|
|
160
201
|
|
|
161
|
-
// backspacing a line after a heading "into" a heading will not result in the
|
|
162
|
-
// so, we do it manually
|
|
202
|
+
// backspacing a line after a heading "into" a heading will not result in the
|
|
203
|
+
// text attaining heading attributes so, we do it manually
|
|
163
204
|
- (void)handleImproperHeadings {
|
|
164
|
-
NSArray *occurences = [self
|
|
165
|
-
|
|
205
|
+
NSArray *occurences = [self
|
|
206
|
+
findAllOccurences:NSMakeRange(0,
|
|
207
|
+
[self typedInput]
|
|
208
|
+
->textView.textStorage.string.length)];
|
|
209
|
+
for (StylePair *pair in occurences) {
|
|
166
210
|
NSRange occurenceRange = [pair.rangeValue rangeValue];
|
|
167
|
-
NSRange paragraphRange = [[self typedInput]->textView.textStorage.string
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
211
|
+
NSRange paragraphRange = [[self typedInput]->textView.textStorage.string
|
|
212
|
+
paragraphRangeForRange:occurenceRange];
|
|
213
|
+
if (!NSEqualRanges(occurenceRange, paragraphRange)) {
|
|
214
|
+
// we have a heading but it does not span its whole paragraph - let's fix
|
|
215
|
+
// it
|
|
216
|
+
[self addAttributes:paragraphRange withTypingAttr:NO];
|
|
171
217
|
}
|
|
172
218
|
}
|
|
173
219
|
}
|
|
174
220
|
|
|
175
221
|
@end
|
|
176
|
-
|
package/ios/styles/ImageStyle.mm
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
#import "StyleHeaders.h"
|
|
2
1
|
#import "EnrichedTextInputView.h"
|
|
2
|
+
#import "ImageAttachment.h"
|
|
3
|
+
#import "MediaAttachment.h"
|
|
3
4
|
#import "OccurenceUtils.h"
|
|
5
|
+
#import "StyleHeaders.h"
|
|
4
6
|
#import "TextInsertionUtils.h"
|
|
5
7
|
|
|
6
8
|
// custom NSAttributedStringKey to differentiate the image
|
|
@@ -10,9 +12,13 @@ static NSString *const ImageAttributeName = @"ImageAttributeName";
|
|
|
10
12
|
EnrichedTextInputView *_input;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
|
-
+ (StyleType)getStyleType {
|
|
15
|
+
+ (StyleType)getStyleType {
|
|
16
|
+
return Image;
|
|
17
|
+
}
|
|
14
18
|
|
|
15
|
-
+ (BOOL)isParagraphStyle {
|
|
19
|
+
+ (BOOL)isParagraphStyle {
|
|
20
|
+
return NO;
|
|
21
|
+
}
|
|
16
22
|
|
|
17
23
|
- (instancetype)initWithInput:(id)input {
|
|
18
24
|
self = [super init];
|
|
@@ -24,7 +30,7 @@ static NSString *const ImageAttributeName = @"ImageAttributeName";
|
|
|
24
30
|
// no-op for image
|
|
25
31
|
}
|
|
26
32
|
|
|
27
|
-
- (void)addAttributes:(NSRange)range {
|
|
33
|
+
- (void)addAttributes:(NSRange)range withTypingAttr:(BOOL)withTypingAttr {
|
|
28
34
|
// no-op for image
|
|
29
35
|
}
|
|
30
36
|
|
|
@@ -35,91 +41,104 @@ static NSString *const ImageAttributeName = @"ImageAttributeName";
|
|
|
35
41
|
- (void)removeAttributes:(NSRange)range {
|
|
36
42
|
[_input->textView.textStorage beginEditing];
|
|
37
43
|
[_input->textView.textStorage removeAttribute:ImageAttributeName range:range];
|
|
38
|
-
[_input->textView.textStorage removeAttribute:NSAttachmentAttributeName
|
|
44
|
+
[_input->textView.textStorage removeAttribute:NSAttachmentAttributeName
|
|
45
|
+
range:range];
|
|
39
46
|
[_input->textView.textStorage endEditing];
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
- (void)removeTypingAttributes {
|
|
43
|
-
NSMutableDictionary *currentAttributes =
|
|
50
|
+
NSMutableDictionary *currentAttributes =
|
|
51
|
+
[_input->textView.typingAttributes mutableCopy];
|
|
44
52
|
[currentAttributes removeObjectForKey:ImageAttributeName];
|
|
45
53
|
[currentAttributes removeObjectForKey:NSAttachmentAttributeName];
|
|
46
54
|
_input->textView.typingAttributes = currentAttributes;
|
|
47
55
|
}
|
|
48
56
|
|
|
49
|
-
- (BOOL)styleCondition:(id _Nullable)value
|
|
57
|
+
- (BOOL)styleCondition:(id _Nullable)value:(NSRange)range {
|
|
50
58
|
return [value isKindOfClass:[ImageData class]];
|
|
51
59
|
}
|
|
52
60
|
|
|
53
61
|
- (BOOL)anyOccurence:(NSRange)range {
|
|
54
|
-
return [OccurenceUtils any:ImageAttributeName
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
62
|
+
return [OccurenceUtils any:ImageAttributeName
|
|
63
|
+
withInput:_input
|
|
64
|
+
inRange:range
|
|
65
|
+
withCondition:^BOOL(id _Nullable value, NSRange range) {
|
|
66
|
+
return [self styleCondition:value:range];
|
|
67
|
+
}];
|
|
59
68
|
}
|
|
60
69
|
|
|
61
70
|
- (BOOL)detectStyle:(NSRange)range {
|
|
62
71
|
if (range.length >= 1) {
|
|
63
|
-
return [OccurenceUtils detect:ImageAttributeName
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
72
|
+
return [OccurenceUtils detect:ImageAttributeName
|
|
73
|
+
withInput:_input
|
|
74
|
+
inRange:range
|
|
75
|
+
withCondition:^BOOL(id _Nullable value, NSRange range) {
|
|
76
|
+
return [self styleCondition:value:range];
|
|
77
|
+
}];
|
|
68
78
|
} else {
|
|
69
|
-
return [OccurenceUtils detect:ImageAttributeName
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
return [OccurenceUtils detect:ImageAttributeName
|
|
80
|
+
withInput:_input
|
|
81
|
+
atIndex:range.location
|
|
82
|
+
checkPrevious:YES
|
|
83
|
+
withCondition:^BOOL(id _Nullable value, NSRange range) {
|
|
84
|
+
return [self styleCondition:value:range];
|
|
85
|
+
}];
|
|
74
86
|
}
|
|
75
87
|
}
|
|
76
88
|
|
|
77
|
-
- (NSArray<StylePair *> *
|
|
78
|
-
return [OccurenceUtils all:ImageAttributeName
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
89
|
+
- (NSArray<StylePair *> *_Nullable)findAllOccurences:(NSRange)range {
|
|
90
|
+
return [OccurenceUtils all:ImageAttributeName
|
|
91
|
+
withInput:_input
|
|
92
|
+
inRange:range
|
|
93
|
+
withCondition:^BOOL(id _Nullable value, NSRange range) {
|
|
94
|
+
return [self styleCondition:value:range];
|
|
95
|
+
}];
|
|
83
96
|
}
|
|
84
97
|
|
|
85
|
-
- (ImageData *)getImageDataAt:(NSUInteger)location
|
|
86
|
-
{
|
|
98
|
+
- (ImageData *)getImageDataAt:(NSUInteger)location {
|
|
87
99
|
NSRange imageRange = NSMakeRange(0, 0);
|
|
88
100
|
NSRange inputRange = NSMakeRange(0, _input->textView.textStorage.length);
|
|
89
|
-
|
|
101
|
+
|
|
90
102
|
// don't search at the very end of input
|
|
91
103
|
NSUInteger searchLocation = location;
|
|
92
|
-
if(searchLocation == _input->textView.textStorage.length) {
|
|
104
|
+
if (searchLocation == _input->textView.textStorage.length) {
|
|
93
105
|
return nullptr;
|
|
94
106
|
}
|
|
95
|
-
|
|
96
|
-
ImageData *imageData =
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
107
|
+
|
|
108
|
+
ImageData *imageData =
|
|
109
|
+
[_input->textView.textStorage attribute:ImageAttributeName
|
|
110
|
+
atIndex:searchLocation
|
|
111
|
+
longestEffectiveRange:&imageRange
|
|
112
|
+
inRange:inputRange];
|
|
113
|
+
|
|
103
114
|
return imageData;
|
|
104
115
|
}
|
|
105
116
|
|
|
106
|
-
- (void)addImageAtRange:(NSRange)range
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
117
|
+
- (void)addImageAtRange:(NSRange)range
|
|
118
|
+
imageData:(ImageData *)imageData
|
|
119
|
+
withSelection:(BOOL)withSelection {
|
|
120
|
+
if (!imageData)
|
|
121
|
+
return;
|
|
122
|
+
|
|
123
|
+
ImageAttachment *attachment =
|
|
124
|
+
[[ImageAttachment alloc] initWithImageData:imageData];
|
|
125
|
+
attachment.delegate = _input;
|
|
126
|
+
|
|
127
|
+
NSDictionary *attributes =
|
|
128
|
+
@{NSAttachmentAttributeName : attachment, ImageAttributeName : imageData};
|
|
129
|
+
|
|
115
130
|
// Use the Object Replacement Character for Image.
|
|
116
131
|
// This tells TextKit "something non-text goes here".
|
|
117
|
-
NSString *
|
|
118
|
-
|
|
132
|
+
NSString *placeholderChar = @"\uFFFC";
|
|
133
|
+
|
|
119
134
|
if (range.length == 0) {
|
|
120
|
-
[TextInsertionUtils insertText:
|
|
135
|
+
[TextInsertionUtils insertText:placeholderChar
|
|
136
|
+
at:range.location
|
|
137
|
+
additionalAttributes:attributes
|
|
138
|
+
input:_input
|
|
139
|
+
withSelection:withSelection];
|
|
121
140
|
} else {
|
|
122
|
-
[TextInsertionUtils replaceText:
|
|
141
|
+
[TextInsertionUtils replaceText:placeholderChar
|
|
123
142
|
at:range
|
|
124
143
|
additionalAttributes:attributes
|
|
125
144
|
input:_input
|
|
@@ -132,27 +151,10 @@ static NSString *const ImageAttributeName = @"ImageAttributeName";
|
|
|
132
151
|
data.uri = uri;
|
|
133
152
|
data.width = width;
|
|
134
153
|
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
154
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
NSData *imgData = [NSData dataWithContentsOfURL:url];
|
|
153
|
-
UIImage *image = [UIImage imageWithData:imgData];
|
|
154
|
-
|
|
155
|
-
return image;
|
|
155
|
+
[self addImageAtRange:_input->textView.selectedRange
|
|
156
|
+
imageData:data
|
|
157
|
+
withSelection:YES];
|
|
156
158
|
}
|
|
157
159
|
|
|
158
160
|
@end
|