react-native-enriched 0.2.0 → 0.3.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.
- package/README.md +16 -17
- package/android/build.gradle +77 -72
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +21 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +7 -0
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.cpp +156 -0
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.h +147 -0
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.cpp +10 -0
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.h +194 -0
- package/android/lint.gradle +70 -0
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputConnectionWrapper.kt +140 -0
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt +304 -83
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewLayoutManager.kt +3 -1
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +166 -51
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewPackage.kt +1 -3
- package/android/src/main/java/com/swmansion/enriched/MeasurementStore.kt +70 -21
- package/android/src/main/java/com/swmansion/enriched/events/MentionHandler.kt +21 -11
- package/android/src/main/java/com/swmansion/enriched/events/OnChangeHtmlEvent.kt +8 -9
- package/android/src/main/java/com/swmansion/enriched/events/OnChangeSelectionEvent.kt +10 -9
- package/android/src/main/java/com/swmansion/enriched/events/OnChangeStateDeprecatedEvent.kt +21 -0
- package/android/src/main/java/com/swmansion/enriched/events/OnChangeStateEvent.kt +9 -12
- package/android/src/main/java/com/swmansion/enriched/events/OnChangeTextEvent.kt +10 -10
- package/android/src/main/java/com/swmansion/enriched/events/OnInputBlurEvent.kt +7 -9
- package/android/src/main/java/com/swmansion/enriched/events/OnInputFocusEvent.kt +7 -9
- package/android/src/main/java/com/swmansion/enriched/events/OnInputKeyPressEvent.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/events/OnLinkDetectedEvent.kt +13 -11
- package/android/src/main/java/com/swmansion/enriched/events/OnMentionDetectedEvent.kt +10 -9
- package/android/src/main/java/com/swmansion/enriched/events/OnMentionEvent.kt +9 -8
- package/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt +32 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBlockQuoteSpan.kt +24 -5
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBoldSpan.kt +8 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedCodeBlockSpan.kt +10 -2
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH1Span.kt +8 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH2Span.kt +8 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH3Span.kt +8 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH4Span.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH5Span.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH6Span.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedImageSpan.kt +34 -17
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedInlineCodeSpan.kt +8 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedItalicSpan.kt +7 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedLinkSpan.kt +10 -4
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedMentionSpan.kt +14 -11
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedOrderedListSpan.kt +18 -11
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedSpans.kt +174 -72
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedStrikeThroughSpan.kt +7 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnderlineSpan.kt +7 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnorderedListSpan.kt +11 -5
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedBlockSpan.kt +3 -2
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedHeadingSpan.kt +1 -2
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedInlineSpan.kt +1 -2
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedParagraphSpan.kt +3 -2
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedZeroWidthSpaceSpan.kt +1 -2
- package/android/src/main/java/com/swmansion/enriched/spans/utils/ForceRedrawSpan.kt +2 -1
- package/android/src/main/java/com/swmansion/enriched/styles/HtmlStyle.kt +155 -20
- package/android/src/main/java/com/swmansion/enriched/styles/InlineStyles.kt +25 -8
- package/android/src/main/java/com/swmansion/enriched/styles/ListStyles.kt +60 -20
- package/android/src/main/java/com/swmansion/enriched/styles/ParagraphStyles.kt +161 -25
- package/android/src/main/java/com/swmansion/enriched/styles/ParametrizedStyles.kt +128 -52
- package/android/src/main/java/com/swmansion/enriched/utils/AsyncDrawable.kt +10 -7
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedConstants.kt +11 -0
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedEditableFactory.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java +136 -87
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSelection.kt +71 -42
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpanState.kt +183 -48
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpannable.kt +82 -0
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpannableStringBuilder.kt +15 -0
- package/android/src/main/java/com/swmansion/enriched/utils/Utils.kt +0 -70
- package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedSpanWatcher.kt +46 -14
- package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedTextWatcher.kt +34 -11
- package/android/src/main/new_arch/CMakeLists.txt +6 -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 +33 -14
- package/ios/EnrichedTextInputView.h +26 -14
- package/ios/EnrichedTextInputView.mm +1209 -586
- package/ios/config/InputConfig.h +24 -6
- package/ios/config/InputConfig.mm +154 -38
- package/ios/{utils → extensions}/ColorExtension.mm +7 -5
- package/ios/extensions/FontExtension.mm +106 -0
- package/ios/{utils → extensions}/LayoutManagerExtension.h +1 -1
- package/ios/extensions/LayoutManagerExtension.mm +396 -0
- package/ios/{utils → extensions}/StringExtension.mm +19 -16
- package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.cpp +156 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.h +147 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/Props.cpp +10 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/Props.h +194 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/RCTComponentViewHelpers.h +95 -0
- package/ios/inputParser/InputParser.h +5 -5
- package/ios/inputParser/InputParser.mm +864 -380
- package/ios/inputTextView/InputTextView.h +1 -1
- package/ios/inputTextView/InputTextView.mm +100 -59
- package/ios/{utils → interfaces}/BaseStyleProtocol.h +2 -2
- package/ios/interfaces/ImageAttachment.h +10 -0
- package/ios/interfaces/ImageAttachment.mm +36 -0
- package/ios/interfaces/LinkRegexConfig.h +19 -0
- package/ios/interfaces/LinkRegexConfig.mm +37 -0
- package/ios/interfaces/MediaAttachment.h +23 -0
- package/ios/interfaces/MediaAttachment.mm +31 -0
- package/ios/{utils → interfaces}/MentionParams.h +0 -1
- package/ios/{utils → interfaces}/MentionStyleProps.mm +27 -20
- package/ios/{utils → interfaces}/StyleHeaders.h +37 -15
- package/ios/{utils → interfaces}/StyleTypeEnum.h +3 -0
- 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 +110 -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/H4Style.mm +17 -0
- package/ios/styles/H5Style.mm +17 -0
- package/ios/styles/H6Style.mm +17 -0
- package/ios/styles/HeadingStyleBase.mm +148 -86
- package/ios/styles/ImageStyle.mm +75 -73
- package/ios/styles/InlineCodeStyle.mm +162 -88
- package/ios/styles/ItalicStyle.mm +76 -52
- package/ios/styles/LinkStyle.mm +411 -232
- 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/OccurenceUtils.h +42 -42
- package/ios/utils/OccurenceUtils.mm +142 -119
- package/ios/utils/ParagraphAttributesUtils.h +10 -2
- package/ios/utils/ParagraphAttributesUtils.mm +182 -71
- package/ios/utils/ParagraphsUtils.h +2 -1
- package/ios/utils/ParagraphsUtils.mm +41 -27
- 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 +61 -2
- package/lib/module/EnrichedTextInput.js.map +1 -1
- package/lib/module/EnrichedTextInputNativeComponent.ts +149 -12
- package/lib/module/{normalizeHtmlStyle.js → utils/normalizeHtmlStyle.js} +12 -0
- package/lib/module/utils/normalizeHtmlStyle.js.map +1 -0
- package/lib/module/utils/regexParser.js +46 -0
- package/lib/module/utils/regexParser.js.map +1 -0
- package/lib/typescript/src/EnrichedTextInput.d.ts +24 -14
- package/lib/typescript/src/EnrichedTextInput.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts +129 -12
- package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts +4 -0
- package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts.map +1 -0
- package/lib/typescript/src/utils/regexParser.d.ts +3 -0
- package/lib/typescript/src/utils/regexParser.d.ts.map +1 -0
- package/package.json +17 -6
- package/src/EnrichedTextInput.tsx +96 -13
- package/src/EnrichedTextInputNativeComponent.ts +149 -12
- package/src/index.tsx +2 -0
- package/src/{normalizeHtmlStyle.ts → utils/normalizeHtmlStyle.ts} +14 -2
- package/src/utils/regexParser.ts +56 -0
- package/ios/utils/FontExtension.mm +0 -91
- package/ios/utils/LayoutManagerExtension.mm +0 -286
- package/lib/module/normalizeHtmlStyle.js.map +0 -1
- package/lib/typescript/src/normalizeHtmlStyle.d.ts +0 -4
- package/lib/typescript/src/normalizeHtmlStyle.d.ts.map +0 -1
- package/ios/{utils → extensions}/ColorExtension.h +0 -0
- package/ios/{utils → extensions}/FontExtension.h +0 -0
- package/ios/{utils → extensions}/StringExtension.h +1 -1
- package/ios/{utils → interfaces}/ImageData.h +0 -0
- package/ios/{utils → interfaces}/ImageData.mm +0 -0
- package/ios/{utils → interfaces}/LinkData.h +0 -0
- package/ios/{utils → interfaces}/LinkData.mm +0 -0
- package/ios/{utils → interfaces}/MentionParams.mm +0 -0
- package/ios/{utils → interfaces}/MentionStyleProps.h +1 -1
- /package/ios/{utils → interfaces}/StylePair.h +0 -0
- /package/ios/{utils → interfaces}/StylePair.mm +0 -0
- /package/ios/{utils → interfaces}/TextDecorationLineEnum.h +0 -0
- /package/ios/{utils → interfaces}/TextDecorationLineEnum.mm +0 -0
|
@@ -1,24 +1,28 @@
|
|
|
1
|
-
#import "
|
|
1
|
+
#import "ColorExtension.h"
|
|
2
2
|
#import "EnrichedTextInputView.h"
|
|
3
3
|
#import "OccurenceUtils.h"
|
|
4
|
+
#import "StyleHeaders.h"
|
|
4
5
|
#import "TextInsertionUtils.h"
|
|
5
|
-
#import "WordsUtils.h"
|
|
6
6
|
#import "UIView+React.h"
|
|
7
|
-
#import "
|
|
7
|
+
#import "WordsUtils.h"
|
|
8
8
|
|
|
9
9
|
// custom NSAttributedStringKey to differentiate from links
|
|
10
10
|
static NSString *const MentionAttributeName = @"MentionAttributeName";
|
|
11
11
|
|
|
12
12
|
@implementation MentionStyle {
|
|
13
|
-
EnrichedTextInputView*_input;
|
|
13
|
+
EnrichedTextInputView *_input;
|
|
14
14
|
NSValue *_activeMentionRange;
|
|
15
15
|
NSString *_activeMentionIndicator;
|
|
16
16
|
BOOL _blockMentionEditing;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
+ (StyleType)getStyleType {
|
|
19
|
+
+ (StyleType)getStyleType {
|
|
20
|
+
return Mention;
|
|
21
|
+
}
|
|
20
22
|
|
|
21
|
-
+ (BOOL)isParagraphStyle {
|
|
23
|
+
+ (BOOL)isParagraphStyle {
|
|
24
|
+
return NO;
|
|
25
|
+
}
|
|
22
26
|
|
|
23
27
|
- (instancetype)initWithInput:(id)input {
|
|
24
28
|
self = [super init];
|
|
@@ -33,7 +37,7 @@ static NSString *const MentionAttributeName = @"MentionAttributeName";
|
|
|
33
37
|
// no-op for mentions
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
- (void)addAttributes:(NSRange)range {
|
|
40
|
+
- (void)addAttributes:(NSRange)range withTypingAttr:(BOOL)withTypingAttr {
|
|
37
41
|
// no-op for mentions
|
|
38
42
|
}
|
|
39
43
|
|
|
@@ -47,28 +51,43 @@ static NSString *const MentionAttributeName = @"MentionAttributeName";
|
|
|
47
51
|
|
|
48
52
|
NSArray<StylePair *> *mentions = [self findAllOccurences:range];
|
|
49
53
|
[_input->textView.textStorage beginEditing];
|
|
50
|
-
for(StylePair *pair in mentions) {
|
|
51
|
-
NSRange mentionRange =
|
|
52
|
-
|
|
53
|
-
[_input->textView.textStorage
|
|
54
|
-
|
|
55
|
-
[_input->textView.textStorage addAttribute:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
for (StylePair *pair in mentions) {
|
|
55
|
+
NSRange mentionRange =
|
|
56
|
+
[self getFullMentionRangeAt:[pair.rangeValue rangeValue].location];
|
|
57
|
+
[_input->textView.textStorage removeAttribute:MentionAttributeName
|
|
58
|
+
range:mentionRange];
|
|
59
|
+
[_input->textView.textStorage addAttribute:NSForegroundColorAttributeName
|
|
60
|
+
value:[_input->config primaryColor]
|
|
61
|
+
range:mentionRange];
|
|
62
|
+
[_input->textView.textStorage addAttribute:NSUnderlineColorAttributeName
|
|
63
|
+
value:[_input->config primaryColor]
|
|
64
|
+
range:mentionRange];
|
|
65
|
+
[_input->textView.textStorage addAttribute:NSStrikethroughColorAttributeName
|
|
66
|
+
value:[_input->config primaryColor]
|
|
67
|
+
range:mentionRange];
|
|
68
|
+
[_input->textView.textStorage removeAttribute:NSBackgroundColorAttributeName
|
|
69
|
+
range:mentionRange];
|
|
70
|
+
|
|
71
|
+
if ([self stylePropsWithParams:pair.styleValue].decorationLine ==
|
|
72
|
+
DecorationUnderline) {
|
|
73
|
+
[_input->textView.textStorage
|
|
74
|
+
removeAttribute:NSUnderlineStyleAttributeName
|
|
75
|
+
range:mentionRange];
|
|
60
76
|
someMentionHadUnderline = YES;
|
|
61
77
|
}
|
|
62
78
|
}
|
|
63
79
|
[_input->textView.textStorage endEditing];
|
|
64
|
-
|
|
80
|
+
|
|
65
81
|
// remove typing attributes as well
|
|
66
|
-
NSMutableDictionary *newTypingAttrs =
|
|
67
|
-
|
|
82
|
+
NSMutableDictionary *newTypingAttrs =
|
|
83
|
+
[_input->textView.typingAttributes mutableCopy];
|
|
84
|
+
newTypingAttrs[NSForegroundColorAttributeName] =
|
|
85
|
+
[_input->config primaryColor];
|
|
68
86
|
newTypingAttrs[NSUnderlineColorAttributeName] = [_input->config primaryColor];
|
|
69
|
-
newTypingAttrs[NSStrikethroughColorAttributeName] =
|
|
87
|
+
newTypingAttrs[NSStrikethroughColorAttributeName] =
|
|
88
|
+
[_input->config primaryColor];
|
|
70
89
|
[newTypingAttrs removeObjectForKey:NSBackgroundColorAttributeName];
|
|
71
|
-
if(someMentionHadUnderline) {
|
|
90
|
+
if (someMentionHadUnderline) {
|
|
72
91
|
[newTypingAttrs removeObjectForKey:NSUnderlineStyleAttributeName];
|
|
73
92
|
}
|
|
74
93
|
_input->textView.typingAttributes = newTypingAttrs;
|
|
@@ -76,165 +95,208 @@ static NSString *const MentionAttributeName = @"MentionAttributeName";
|
|
|
76
95
|
|
|
77
96
|
// used for conflicts, we have to remove the whole mention
|
|
78
97
|
- (void)removeTypingAttributes {
|
|
79
|
-
NSRange mentionRange =
|
|
98
|
+
NSRange mentionRange =
|
|
99
|
+
[self getFullMentionRangeAt:_input->textView.selectedRange.location];
|
|
80
100
|
[_input->textView.textStorage beginEditing];
|
|
81
|
-
[_input->textView.textStorage removeAttribute:MentionAttributeName
|
|
82
|
-
|
|
83
|
-
[_input->textView.textStorage addAttribute:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
101
|
+
[_input->textView.textStorage removeAttribute:MentionAttributeName
|
|
102
|
+
range:mentionRange];
|
|
103
|
+
[_input->textView.textStorage addAttribute:NSForegroundColorAttributeName
|
|
104
|
+
value:[_input->config primaryColor]
|
|
105
|
+
range:mentionRange];
|
|
106
|
+
[_input->textView.textStorage addAttribute:NSUnderlineColorAttributeName
|
|
107
|
+
value:[_input->config primaryColor]
|
|
108
|
+
range:mentionRange];
|
|
109
|
+
[_input->textView.textStorage addAttribute:NSStrikethroughColorAttributeName
|
|
110
|
+
value:[_input->config primaryColor]
|
|
111
|
+
range:mentionRange];
|
|
112
|
+
[_input->textView.textStorage removeAttribute:NSBackgroundColorAttributeName
|
|
113
|
+
range:mentionRange];
|
|
114
|
+
|
|
87
115
|
MentionParams *params = [self getMentionParamsAt:mentionRange.location];
|
|
88
|
-
if([self stylePropsWithParams:params].decorationLine ==
|
|
89
|
-
|
|
116
|
+
if ([self stylePropsWithParams:params].decorationLine ==
|
|
117
|
+
DecorationUnderline) {
|
|
118
|
+
[_input->textView.textStorage removeAttribute:NSUnderlineStyleAttributeName
|
|
119
|
+
range:mentionRange];
|
|
90
120
|
}
|
|
91
121
|
[_input->textView.textStorage endEditing];
|
|
92
|
-
|
|
122
|
+
|
|
93
123
|
// remove typing attributes as well
|
|
94
|
-
NSMutableDictionary *newTypingAttrs =
|
|
95
|
-
|
|
124
|
+
NSMutableDictionary *newTypingAttrs =
|
|
125
|
+
[_input->textView.typingAttributes mutableCopy];
|
|
126
|
+
newTypingAttrs[NSForegroundColorAttributeName] =
|
|
127
|
+
[_input->config primaryColor];
|
|
96
128
|
newTypingAttrs[NSUnderlineColorAttributeName] = [_input->config primaryColor];
|
|
97
|
-
newTypingAttrs[NSStrikethroughColorAttributeName] =
|
|
129
|
+
newTypingAttrs[NSStrikethroughColorAttributeName] =
|
|
130
|
+
[_input->config primaryColor];
|
|
98
131
|
[newTypingAttrs removeObjectForKey:NSBackgroundColorAttributeName];
|
|
99
|
-
if([self stylePropsWithParams:params].decorationLine ==
|
|
132
|
+
if ([self stylePropsWithParams:params].decorationLine ==
|
|
133
|
+
DecorationUnderline) {
|
|
100
134
|
[newTypingAttrs removeObjectForKey:NSUnderlineStyleAttributeName];
|
|
101
135
|
}
|
|
102
136
|
_input->textView.typingAttributes = newTypingAttrs;
|
|
103
137
|
}
|
|
104
138
|
|
|
105
|
-
- (BOOL)styleCondition:(id _Nullable)value :(NSRange)range {
|
|
139
|
+
- (BOOL)styleCondition:(id _Nullable)value range:(NSRange)range {
|
|
106
140
|
MentionParams *params = (MentionParams *)value;
|
|
107
141
|
return params != nullptr;
|
|
108
142
|
}
|
|
109
143
|
|
|
110
144
|
- (BOOL)detectStyle:(NSRange)range {
|
|
111
|
-
if(range.length >= 1) {
|
|
112
|
-
return [OccurenceUtils detect:MentionAttributeName
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
145
|
+
if (range.length >= 1) {
|
|
146
|
+
return [OccurenceUtils detect:MentionAttributeName
|
|
147
|
+
withInput:_input
|
|
148
|
+
inRange:range
|
|
149
|
+
withCondition:^BOOL(id _Nullable value, NSRange range) {
|
|
150
|
+
return [self styleCondition:value range:range];
|
|
151
|
+
}];
|
|
117
152
|
} else {
|
|
118
153
|
return [self getMentionParamsAt:range.location] != nullptr;
|
|
119
154
|
}
|
|
120
155
|
}
|
|
121
156
|
|
|
122
157
|
- (BOOL)anyOccurence:(NSRange)range {
|
|
123
|
-
return [OccurenceUtils any:MentionAttributeName
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
158
|
+
return [OccurenceUtils any:MentionAttributeName
|
|
159
|
+
withInput:_input
|
|
160
|
+
inRange:range
|
|
161
|
+
withCondition:^BOOL(id _Nullable value, NSRange range) {
|
|
162
|
+
return [self styleCondition:value range:range];
|
|
163
|
+
}];
|
|
128
164
|
}
|
|
129
165
|
|
|
130
166
|
- (NSArray<StylePair *> *_Nullable)findAllOccurences:(NSRange)range {
|
|
131
|
-
return [OccurenceUtils all:MentionAttributeName
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
167
|
+
return [OccurenceUtils all:MentionAttributeName
|
|
168
|
+
withInput:_input
|
|
169
|
+
inRange:range
|
|
170
|
+
withCondition:^BOOL(id _Nullable value, NSRange range) {
|
|
171
|
+
return [self styleCondition:value range:range];
|
|
172
|
+
}];
|
|
136
173
|
}
|
|
137
174
|
|
|
138
175
|
// MARK: - Public non-standard methods
|
|
139
176
|
|
|
140
|
-
- (void)addMention:(NSString *)indicator
|
|
141
|
-
|
|
177
|
+
- (void)addMention:(NSString *)indicator
|
|
178
|
+
text:(NSString *)text
|
|
179
|
+
attributes:(NSString *)attributes {
|
|
180
|
+
if (_activeMentionRange == nullptr) {
|
|
142
181
|
return;
|
|
143
182
|
}
|
|
144
|
-
|
|
145
|
-
// we block callbacks resulting from manageMentionEditing while we tamper with
|
|
183
|
+
|
|
184
|
+
// we block callbacks resulting from manageMentionEditing while we tamper with
|
|
185
|
+
// them here
|
|
146
186
|
_blockMentionEditing = YES;
|
|
147
|
-
|
|
187
|
+
|
|
148
188
|
MentionParams *params = [[MentionParams alloc] init];
|
|
149
189
|
params.text = text;
|
|
150
190
|
params.indicator = indicator;
|
|
151
191
|
params.attributes = attributes;
|
|
152
|
-
|
|
153
|
-
MentionStyleProps *styleProps =
|
|
154
|
-
|
|
192
|
+
|
|
193
|
+
MentionStyleProps *styleProps =
|
|
194
|
+
[_input->config mentionStylePropsForIndicator:indicator];
|
|
195
|
+
|
|
155
196
|
NSMutableDictionary *newAttrs = [@{
|
|
156
|
-
MentionAttributeName: params,
|
|
157
|
-
NSForegroundColorAttributeName: styleProps.color,
|
|
158
|
-
NSUnderlineColorAttributeName: styleProps.color,
|
|
159
|
-
NSStrikethroughColorAttributeName: styleProps.color,
|
|
160
|
-
NSBackgroundColorAttributeName
|
|
197
|
+
MentionAttributeName : params,
|
|
198
|
+
NSForegroundColorAttributeName : styleProps.color,
|
|
199
|
+
NSUnderlineColorAttributeName : styleProps.color,
|
|
200
|
+
NSStrikethroughColorAttributeName : styleProps.color,
|
|
201
|
+
NSBackgroundColorAttributeName :
|
|
202
|
+
[styleProps.backgroundColor colorWithAlphaIfNotTransparent:0.4],
|
|
161
203
|
} mutableCopy];
|
|
162
|
-
|
|
163
|
-
if(styleProps.decorationLine == DecorationUnderline) {
|
|
204
|
+
|
|
205
|
+
if (styleProps.decorationLine == DecorationUnderline) {
|
|
164
206
|
newAttrs[NSUnderlineStyleAttributeName] = @(NSUnderlineStyleSingle);
|
|
165
207
|
}
|
|
166
|
-
|
|
208
|
+
|
|
167
209
|
// add a single space after the mention
|
|
168
210
|
NSString *newText = [NSString stringWithFormat:@"%@ ", text];
|
|
169
211
|
NSRange rangeToBeReplaced = [_activeMentionRange rangeValue];
|
|
170
|
-
[TextInsertionUtils replaceText:newText
|
|
171
|
-
|
|
212
|
+
[TextInsertionUtils replaceText:newText
|
|
213
|
+
at:rangeToBeReplaced
|
|
214
|
+
additionalAttributes:nullptr
|
|
215
|
+
input:_input
|
|
216
|
+
withSelection:YES];
|
|
217
|
+
|
|
172
218
|
// THEN, add the attributes to not apply them on the space
|
|
173
|
-
[_input->textView.textStorage
|
|
174
|
-
|
|
219
|
+
[_input->textView.textStorage
|
|
220
|
+
addAttributes:newAttrs
|
|
221
|
+
range:NSMakeRange(rangeToBeReplaced.location, text.length)];
|
|
222
|
+
|
|
175
223
|
// mention editing should finish
|
|
176
224
|
[self removeActiveMentionRange];
|
|
177
|
-
|
|
225
|
+
|
|
178
226
|
// unlock editing
|
|
179
227
|
_blockMentionEditing = NO;
|
|
180
228
|
}
|
|
181
229
|
|
|
182
230
|
- (void)addMentionAtRange:(NSRange)range params:(MentionParams *)params {
|
|
183
231
|
_blockMentionEditing = YES;
|
|
184
|
-
|
|
185
|
-
MentionStyleProps *styleProps =
|
|
186
|
-
|
|
232
|
+
|
|
233
|
+
MentionStyleProps *styleProps =
|
|
234
|
+
[_input->config mentionStylePropsForIndicator:params.indicator];
|
|
235
|
+
|
|
187
236
|
NSMutableDictionary *newAttrs = [@{
|
|
188
|
-
MentionAttributeName: params,
|
|
189
|
-
NSForegroundColorAttributeName: styleProps.color,
|
|
190
|
-
NSUnderlineColorAttributeName: styleProps.color,
|
|
191
|
-
NSStrikethroughColorAttributeName: styleProps.color,
|
|
192
|
-
NSBackgroundColorAttributeName
|
|
237
|
+
MentionAttributeName : params,
|
|
238
|
+
NSForegroundColorAttributeName : styleProps.color,
|
|
239
|
+
NSUnderlineColorAttributeName : styleProps.color,
|
|
240
|
+
NSStrikethroughColorAttributeName : styleProps.color,
|
|
241
|
+
NSBackgroundColorAttributeName :
|
|
242
|
+
[styleProps.backgroundColor colorWithAlphaIfNotTransparent:0.4],
|
|
193
243
|
} mutableCopy];
|
|
194
|
-
|
|
195
|
-
if(styleProps.decorationLine == DecorationUnderline) {
|
|
244
|
+
|
|
245
|
+
if (styleProps.decorationLine == DecorationUnderline) {
|
|
196
246
|
newAttrs[NSUnderlineStyleAttributeName] = @(NSUnderlineStyleSingle);
|
|
197
247
|
}
|
|
198
|
-
|
|
248
|
+
|
|
199
249
|
[_input->textView.textStorage addAttributes:newAttrs range:range];
|
|
200
|
-
|
|
250
|
+
|
|
201
251
|
_blockMentionEditing = NO;
|
|
202
252
|
}
|
|
203
253
|
|
|
204
254
|
- (void)startMentionWithIndicator:(NSString *)indicator {
|
|
205
255
|
NSRange currentRange = _input->textView.selectedRange;
|
|
206
|
-
|
|
256
|
+
|
|
207
257
|
BOOL addSpaceBefore = NO;
|
|
208
258
|
BOOL addSpaceAfter = NO;
|
|
209
|
-
|
|
210
|
-
if(currentRange.location > 0) {
|
|
211
|
-
unichar charBefore = [_input->textView.textStorage.string
|
|
212
|
-
|
|
259
|
+
|
|
260
|
+
if (currentRange.location > 0) {
|
|
261
|
+
unichar charBefore = [_input->textView.textStorage.string
|
|
262
|
+
characterAtIndex:(currentRange.location - 1)];
|
|
263
|
+
if (![[NSCharacterSet whitespaceAndNewlineCharacterSet]
|
|
264
|
+
characterIsMember:charBefore]) {
|
|
213
265
|
addSpaceBefore = YES;
|
|
214
266
|
}
|
|
215
267
|
}
|
|
216
|
-
|
|
217
|
-
if(currentRange.location + currentRange.length <
|
|
218
|
-
|
|
219
|
-
|
|
268
|
+
|
|
269
|
+
if (currentRange.location + currentRange.length <
|
|
270
|
+
_input->textView.textStorage.string.length) {
|
|
271
|
+
unichar charAfter = [_input->textView.textStorage.string
|
|
272
|
+
characterAtIndex:(currentRange.location + currentRange.length)];
|
|
273
|
+
if (![[NSCharacterSet whitespaceAndNewlineCharacterSet]
|
|
274
|
+
characterIsMember:charAfter]) {
|
|
220
275
|
addSpaceAfter = YES;
|
|
221
276
|
}
|
|
222
277
|
}
|
|
223
|
-
|
|
224
|
-
NSString *finalString =
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
278
|
+
|
|
279
|
+
NSString *finalString =
|
|
280
|
+
[NSString stringWithFormat:@"%@%@%@", addSpaceBefore ? @" " : @"",
|
|
281
|
+
indicator, addSpaceAfter ? @" " : @""];
|
|
282
|
+
|
|
283
|
+
NSRange newSelect = NSMakeRange(
|
|
284
|
+
currentRange.location + finalString.length + (addSpaceAfter ? -1 : 0), 0);
|
|
285
|
+
|
|
286
|
+
if (currentRange.length == 0) {
|
|
287
|
+
[TextInsertionUtils insertText:finalString
|
|
288
|
+
at:currentRange.location
|
|
289
|
+
additionalAttributes:nullptr
|
|
290
|
+
input:_input
|
|
291
|
+
withSelection:NO];
|
|
234
292
|
} else {
|
|
235
|
-
[TextInsertionUtils replaceText:finalString
|
|
293
|
+
[TextInsertionUtils replaceText:finalString
|
|
294
|
+
at:currentRange
|
|
295
|
+
additionalAttributes:nullptr
|
|
296
|
+
input:_input
|
|
297
|
+
withSelection:NO];
|
|
236
298
|
}
|
|
237
|
-
|
|
299
|
+
|
|
238
300
|
[_input->textView reactFocus];
|
|
239
301
|
_input->textView.selectedRange = newSelect;
|
|
240
302
|
}
|
|
@@ -242,46 +304,53 @@ static NSString *const MentionAttributeName = @"MentionAttributeName";
|
|
|
242
304
|
// handles removing no longer valid mentions
|
|
243
305
|
- (void)handleExistingMentions {
|
|
244
306
|
// unfortunately whole text needs to be checked for them
|
|
245
|
-
// checking the modified words doesn't work because mention's text can have
|
|
246
|
-
|
|
247
|
-
|
|
307
|
+
// checking the modified words doesn't work because mention's text can have
|
|
308
|
+
// any number of spaces, which makes one mention any number of words long
|
|
309
|
+
|
|
310
|
+
NSRange wholeText =
|
|
311
|
+
NSMakeRange(0, _input->textView.textStorage.string.length);
|
|
248
312
|
// get menntions in ascending range.location order
|
|
249
|
-
NSArray<StylePair *> *mentions = [[self findAllOccurences:wholeText]
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
313
|
+
NSArray<StylePair *> *mentions = [[self findAllOccurences:wholeText]
|
|
314
|
+
sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1,
|
|
315
|
+
id _Nonnull obj2) {
|
|
316
|
+
NSRange range1 = [((StylePair *)obj1).rangeValue rangeValue];
|
|
317
|
+
NSRange range2 = [((StylePair *)obj2).rangeValue rangeValue];
|
|
318
|
+
if (range1.location < range2.location) {
|
|
319
|
+
return NSOrderedAscending;
|
|
320
|
+
} else {
|
|
321
|
+
return NSOrderedDescending;
|
|
322
|
+
}
|
|
323
|
+
}];
|
|
324
|
+
|
|
259
325
|
// set of ranges to have their mentions removed - aren't valid anymore
|
|
260
326
|
NSMutableSet<NSValue *> *rangesToRemove = [[NSMutableSet alloc] init];
|
|
261
|
-
|
|
262
|
-
for(NSInteger i = 0; i < mentions.count; i++) {
|
|
327
|
+
|
|
328
|
+
for (NSInteger i = 0; i < mentions.count; i++) {
|
|
263
329
|
StylePair *mention = mentions[i];
|
|
264
330
|
NSRange currentRange = [mention.rangeValue rangeValue];
|
|
265
331
|
NSString *currentText = ((MentionParams *)mention.styleValue).text;
|
|
266
|
-
// check locations with the previous mention if it exists - if they got
|
|
267
|
-
|
|
268
|
-
|
|
332
|
+
// check locations with the previous mention if it exists - if they got
|
|
333
|
+
// merged they need to be removed
|
|
334
|
+
if (i > 0) {
|
|
335
|
+
NSRange prevRange =
|
|
336
|
+
[((StylePair *)mentions[i - 1]).rangeValue rangeValue];
|
|
269
337
|
// mentions merged - both need to go out
|
|
270
|
-
if(prevRange.location + prevRange.length == currentRange.location) {
|
|
338
|
+
if (prevRange.location + prevRange.length == currentRange.location) {
|
|
271
339
|
[rangesToRemove addObject:[NSValue valueWithRange:prevRange]];
|
|
272
340
|
[rangesToRemove addObject:[NSValue valueWithRange:currentRange]];
|
|
273
341
|
continue;
|
|
274
342
|
}
|
|
275
343
|
}
|
|
276
|
-
|
|
344
|
+
|
|
277
345
|
// check for text, any modifications to it makes mention invalid
|
|
278
|
-
NSString *existingText =
|
|
279
|
-
|
|
346
|
+
NSString *existingText =
|
|
347
|
+
[_input->textView.textStorage.string substringWithRange:currentRange];
|
|
348
|
+
if (![existingText isEqualToString:currentText]) {
|
|
280
349
|
[rangesToRemove addObject:[NSValue valueWithRange:currentRange]];
|
|
281
350
|
}
|
|
282
351
|
}
|
|
283
|
-
|
|
284
|
-
for(NSValue *value in rangesToRemove) {
|
|
352
|
+
|
|
353
|
+
for (NSValue *value in rangesToRemove) {
|
|
285
354
|
[self removeAttributes:[value rangeValue]];
|
|
286
355
|
}
|
|
287
356
|
}
|
|
@@ -289,98 +358,124 @@ static NSString *const MentionAttributeName = @"MentionAttributeName";
|
|
|
289
358
|
// manages active mention range, which in turn emits proper onMention event
|
|
290
359
|
- (void)manageMentionEditing {
|
|
291
360
|
// no actions performed when block is active
|
|
292
|
-
if(_blockMentionEditing) {
|
|
361
|
+
if (_blockMentionEditing) {
|
|
293
362
|
return;
|
|
294
363
|
}
|
|
295
364
|
|
|
296
365
|
// we don't take longer selections into consideration
|
|
297
|
-
if(_input->textView.selectedRange.length > 0) {
|
|
366
|
+
if (_input->textView.selectedRange.length > 0) {
|
|
298
367
|
[self removeActiveMentionRange];
|
|
299
368
|
return;
|
|
300
369
|
}
|
|
301
|
-
|
|
370
|
+
|
|
302
371
|
// get the text (and its range) that could be an editable mention
|
|
303
372
|
NSArray *mentionCandidate = [self getMentionCandidate];
|
|
304
|
-
if(mentionCandidate == nullptr) {
|
|
373
|
+
if (mentionCandidate == nullptr) {
|
|
305
374
|
[self removeActiveMentionRange];
|
|
306
375
|
return;
|
|
307
376
|
}
|
|
308
377
|
NSString *candidateText = mentionCandidate[0];
|
|
309
378
|
NSRange candidateRange = [(NSValue *)mentionCandidate[1] rangeValue];
|
|
310
|
-
|
|
311
|
-
// get style classes that the mention shouldn't be recognized in, together
|
|
312
|
-
|
|
379
|
+
|
|
380
|
+
// get style classes that the mention shouldn't be recognized in, together
|
|
381
|
+
// with other mentions
|
|
382
|
+
NSArray *conflicts =
|
|
383
|
+
_input->conflictingStyles[@([MentionStyle getStyleType])];
|
|
313
384
|
NSArray *blocks = _input->blockingStyles[@([MentionStyle getStyleType])];
|
|
314
|
-
NSArray *allConflicts = [[conflicts arrayByAddingObjectsFromArray:blocks]
|
|
385
|
+
NSArray *allConflicts = [[conflicts arrayByAddingObjectsFromArray:blocks]
|
|
386
|
+
arrayByAddingObject:@([MentionStyle getStyleType])];
|
|
315
387
|
BOOL conflictingStyle = NO;
|
|
316
|
-
|
|
317
|
-
for(NSNumber *styleType in allConflicts) {
|
|
388
|
+
|
|
389
|
+
for (NSNumber *styleType in allConflicts) {
|
|
318
390
|
id<BaseStyleProtocol> styleClass = _input->stylesDict[styleType];
|
|
319
|
-
if(styleClass != nullptr && [styleClass anyOccurence:candidateRange]) {
|
|
391
|
+
if (styleClass != nullptr && [styleClass anyOccurence:candidateRange]) {
|
|
320
392
|
conflictingStyle = YES;
|
|
321
393
|
break;
|
|
322
394
|
}
|
|
323
395
|
}
|
|
324
|
-
|
|
396
|
+
|
|
325
397
|
// if any of the conflicting styles were present, don't edit the mention
|
|
326
|
-
if(conflictingStyle) {
|
|
398
|
+
if (conflictingStyle) {
|
|
327
399
|
[self removeActiveMentionRange];
|
|
328
400
|
return;
|
|
329
401
|
}
|
|
330
|
-
|
|
402
|
+
|
|
331
403
|
// everything checks out - we are indeed editing a mention
|
|
332
404
|
[self setActiveMentionRange:candidateRange text:candidateText];
|
|
333
405
|
}
|
|
334
406
|
|
|
335
407
|
// used to fix mentions' typing attributes
|
|
336
408
|
- (void)manageMentionTypingAttributes {
|
|
337
|
-
// same as with links, mentions' typing attributes need to be constantly
|
|
409
|
+
// same as with links, mentions' typing attributes need to be constantly
|
|
410
|
+
// removed whenever we are somewhere near
|
|
338
411
|
BOOL removeAttrs = NO;
|
|
339
412
|
MentionParams *params;
|
|
340
|
-
|
|
341
|
-
if(_input->textView.selectedRange.length == 0) {
|
|
413
|
+
|
|
414
|
+
if (_input->textView.selectedRange.length == 0) {
|
|
342
415
|
// check before
|
|
343
|
-
if(_input->textView.selectedRange.location >= 1) {
|
|
344
|
-
if([self detectStyle:NSMakeRange(
|
|
416
|
+
if (_input->textView.selectedRange.location >= 1) {
|
|
417
|
+
if ([self detectStyle:NSMakeRange(
|
|
418
|
+
_input->textView.selectedRange.location - 1,
|
|
419
|
+
1)]) {
|
|
345
420
|
removeAttrs = YES;
|
|
346
|
-
params = [self
|
|
421
|
+
params = [self
|
|
422
|
+
getMentionParamsAt:_input->textView.selectedRange.location - 1];
|
|
347
423
|
}
|
|
348
424
|
}
|
|
349
425
|
// check after
|
|
350
|
-
if(_input->textView.selectedRange.location <
|
|
351
|
-
|
|
426
|
+
if (_input->textView.selectedRange.location <
|
|
427
|
+
_input->textView.textStorage.length) {
|
|
428
|
+
if ([self detectStyle:NSMakeRange(_input->textView.selectedRange.location,
|
|
429
|
+
1)]) {
|
|
352
430
|
removeAttrs = YES;
|
|
353
|
-
params =
|
|
431
|
+
params =
|
|
432
|
+
[self getMentionParamsAt:_input->textView.selectedRange.location];
|
|
354
433
|
}
|
|
355
434
|
}
|
|
356
435
|
} else {
|
|
357
|
-
if([self anyOccurence:_input->textView.selectedRange]) {
|
|
436
|
+
if ([self anyOccurence:_input->textView.selectedRange]) {
|
|
358
437
|
removeAttrs = YES;
|
|
359
438
|
}
|
|
360
439
|
}
|
|
361
|
-
|
|
362
|
-
if(removeAttrs) {
|
|
363
|
-
NSMutableDictionary *newTypingAttrs =
|
|
364
|
-
|
|
365
|
-
newTypingAttrs[
|
|
366
|
-
|
|
440
|
+
|
|
441
|
+
if (removeAttrs) {
|
|
442
|
+
NSMutableDictionary *newTypingAttrs =
|
|
443
|
+
[_input->textView.typingAttributes mutableCopy];
|
|
444
|
+
newTypingAttrs[NSForegroundColorAttributeName] =
|
|
445
|
+
[_input->config primaryColor];
|
|
446
|
+
newTypingAttrs[NSUnderlineColorAttributeName] =
|
|
447
|
+
[_input->config primaryColor];
|
|
448
|
+
newTypingAttrs[NSStrikethroughColorAttributeName] =
|
|
449
|
+
[_input->config primaryColor];
|
|
367
450
|
[newTypingAttrs removeObjectForKey:NSBackgroundColorAttributeName];
|
|
368
|
-
if([self stylePropsWithParams:params].decorationLine ==
|
|
451
|
+
if ([self stylePropsWithParams:params].decorationLine ==
|
|
452
|
+
DecorationUnderline) {
|
|
369
453
|
[newTypingAttrs removeObjectForKey:NSUnderlineStyleAttributeName];
|
|
370
454
|
}
|
|
371
455
|
_input->textView.typingAttributes = newTypingAttrs;
|
|
372
456
|
}
|
|
373
457
|
}
|
|
374
458
|
|
|
375
|
-
// replacing whole input (that starts with a mention) with a manually typed
|
|
376
|
-
|
|
459
|
+
// replacing whole input (that starts with a mention) with a manually typed
|
|
460
|
+
// letter improperly applies mention's attributes to all the following text
|
|
461
|
+
- (BOOL)handleLeadingMentionReplacement:(NSRange)range
|
|
462
|
+
replacementText:(NSString *)text {
|
|
377
463
|
// whole textView range gets replaced with a single letter
|
|
378
|
-
if(_input->textView.textStorage.string.length > 0 &&
|
|
464
|
+
if (_input->textView.textStorage.string.length > 0 &&
|
|
465
|
+
NSEqualRanges(
|
|
466
|
+
range, NSMakeRange(0, _input->textView.textStorage.string.length)) &&
|
|
467
|
+
text.length == 1) {
|
|
379
468
|
// first character detection is enough for the removal to be done
|
|
380
|
-
if([self detectStyle:NSMakeRange(0, 1)]) {
|
|
381
|
-
[self
|
|
469
|
+
if ([self detectStyle:NSMakeRange(0, 1)]) {
|
|
470
|
+
[self
|
|
471
|
+
removeAttributes:NSMakeRange(
|
|
472
|
+
0, _input->textView.textStorage.string.length)];
|
|
382
473
|
// do the replacing manually
|
|
383
|
-
[TextInsertionUtils replaceText:text
|
|
474
|
+
[TextInsertionUtils replaceText:text
|
|
475
|
+
at:range
|
|
476
|
+
additionalAttributes:nullptr
|
|
477
|
+
input:_input
|
|
478
|
+
withSelection:YES];
|
|
384
479
|
return YES;
|
|
385
480
|
}
|
|
386
481
|
}
|
|
@@ -391,19 +486,18 @@ static NSString *const MentionAttributeName = @"MentionAttributeName";
|
|
|
391
486
|
- (MentionParams *)getMentionParamsAt:(NSUInteger)location {
|
|
392
487
|
NSRange mentionRange = NSMakeRange(0, 0);
|
|
393
488
|
NSRange inputRange = NSMakeRange(0, _input->textView.textStorage.length);
|
|
394
|
-
|
|
489
|
+
|
|
395
490
|
// don't search at the very end of input
|
|
396
491
|
NSUInteger searchLocation = location;
|
|
397
|
-
if(searchLocation == _input->textView.textStorage.length) {
|
|
492
|
+
if (searchLocation == _input->textView.textStorage.length) {
|
|
398
493
|
return nullptr;
|
|
399
494
|
}
|
|
400
|
-
|
|
401
|
-
MentionParams *value =
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
];
|
|
495
|
+
|
|
496
|
+
MentionParams *value =
|
|
497
|
+
[_input->textView.textStorage attribute:MentionAttributeName
|
|
498
|
+
atIndex:searchLocation
|
|
499
|
+
longestEffectiveRange:&mentionRange
|
|
500
|
+
inRange:inputRange];
|
|
407
501
|
return value;
|
|
408
502
|
}
|
|
409
503
|
|
|
@@ -415,23 +509,21 @@ static NSString *const MentionAttributeName = @"MentionAttributeName";
|
|
|
415
509
|
- (NSRange)getFullMentionRangeAt:(NSUInteger)location {
|
|
416
510
|
NSRange mentionRange = NSMakeRange(0, 0);
|
|
417
511
|
NSRange inputRange = NSMakeRange(0, _input->textView.textStorage.length);
|
|
418
|
-
|
|
512
|
+
|
|
419
513
|
// get the previous index if possible when at the very end of input
|
|
420
514
|
NSUInteger searchLocation = location;
|
|
421
|
-
if(searchLocation == _input->textView.textStorage.length) {
|
|
422
|
-
if(searchLocation == 0) {
|
|
515
|
+
if (searchLocation == _input->textView.textStorage.length) {
|
|
516
|
+
if (searchLocation == 0) {
|
|
423
517
|
return mentionRange;
|
|
424
518
|
} else {
|
|
425
519
|
searchLocation = searchLocation - 1;
|
|
426
520
|
}
|
|
427
521
|
}
|
|
428
|
-
|
|
429
|
-
[_input->textView.textStorage
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
inRange:inputRange
|
|
434
|
-
];
|
|
522
|
+
|
|
523
|
+
[_input->textView.textStorage attribute:MentionAttributeName
|
|
524
|
+
atIndex:searchLocation
|
|
525
|
+
longestEffectiveRange:&mentionRange
|
|
526
|
+
inRange:inputRange];
|
|
435
527
|
return mentionRange;
|
|
436
528
|
}
|
|
437
529
|
|
|
@@ -441,103 +533,125 @@ static NSString *const MentionAttributeName = @"MentionAttributeName";
|
|
|
441
533
|
return [_input->config mentionStylePropsForIndicator:params.indicator];
|
|
442
534
|
}
|
|
443
535
|
|
|
444
|
-
// finds if any word/words around current selection are eligible to be edited as
|
|
445
|
-
// since we allow for a single space inside an edited mention, we have
|
|
536
|
+
// finds if any word/words around current selection are eligible to be edited as
|
|
537
|
+
// mentions since we allow for a single space inside an edited mention, we have
|
|
538
|
+
// take both current and the previous word into account
|
|
446
539
|
- (NSArray *)getMentionCandidate {
|
|
447
540
|
NSDictionary *currentWord, *previousWord;
|
|
448
541
|
NSString *currentWordText, *previousWordText, *finalText;
|
|
449
542
|
NSValue *currentWordRange, *previousWordRange;
|
|
450
543
|
NSRange finalRange;
|
|
451
|
-
|
|
544
|
+
|
|
452
545
|
// word at the current selection
|
|
453
|
-
currentWord = [WordsUtils getCurrentWord:_input->textView.textStorage.string
|
|
454
|
-
|
|
546
|
+
currentWord = [WordsUtils getCurrentWord:_input->textView.textStorage.string
|
|
547
|
+
range:_input->textView.selectedRange];
|
|
548
|
+
if (currentWord != nullptr) {
|
|
455
549
|
currentWordText = (NSString *)[currentWord objectForKey:@"word"];
|
|
456
550
|
currentWordRange = (NSValue *)[currentWord objectForKey:@"range"];
|
|
457
551
|
}
|
|
458
|
-
|
|
459
|
-
if(currentWord != nullptr) {
|
|
552
|
+
|
|
553
|
+
if (currentWord != nullptr) {
|
|
460
554
|
// current word exists
|
|
461
555
|
unichar currentFirstChar = [currentWordText characterAtIndex:0];
|
|
462
|
-
|
|
463
|
-
if([[_input->config mentionIndicators]
|
|
464
|
-
|
|
556
|
+
|
|
557
|
+
if ([[_input->config mentionIndicators]
|
|
558
|
+
containsObject:@(currentFirstChar)]) {
|
|
559
|
+
// current word exists and has a mention indicator; no need to check for
|
|
560
|
+
// the previous word
|
|
465
561
|
finalText = currentWordText;
|
|
466
562
|
finalRange = [currentWordRange rangeValue];
|
|
467
563
|
} else {
|
|
468
|
-
// current word exists but no traces of mention indicator; get the
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
564
|
+
// current word exists but no traces of mention indicator; get the
|
|
565
|
+
// previous word
|
|
566
|
+
|
|
567
|
+
NSInteger previousWordSearchLocation =
|
|
568
|
+
[currentWordRange rangeValue].location - 1;
|
|
569
|
+
if (previousWordSearchLocation < 0) {
|
|
472
570
|
// previous word can't exist
|
|
473
571
|
return nullptr;
|
|
474
572
|
}
|
|
475
|
-
|
|
476
|
-
unichar separatorChar = [_input->textView.textStorage.string
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
573
|
+
|
|
574
|
+
unichar separatorChar = [_input->textView.textStorage.string
|
|
575
|
+
characterAtIndex:previousWordSearchLocation];
|
|
576
|
+
if (![[NSCharacterSet whitespaceCharacterSet]
|
|
577
|
+
characterIsMember:separatorChar]) {
|
|
578
|
+
// we want to check for the previous word ONLY if the separating
|
|
579
|
+
// character was a space newlines don't make it
|
|
480
580
|
return nullptr;
|
|
481
581
|
}
|
|
482
|
-
|
|
483
|
-
previousWord = [WordsUtils
|
|
484
|
-
|
|
485
|
-
|
|
582
|
+
|
|
583
|
+
previousWord = [WordsUtils
|
|
584
|
+
getCurrentWord:_input->textView.textStorage.string
|
|
585
|
+
range:NSMakeRange(previousWordSearchLocation, 0)];
|
|
586
|
+
|
|
587
|
+
if (previousWord != nullptr) {
|
|
486
588
|
// previous word exists; get its properties
|
|
487
589
|
previousWordText = (NSString *)[previousWord objectForKey:@"word"];
|
|
488
590
|
previousWordRange = (NSValue *)[previousWord objectForKey:@"range"];
|
|
489
|
-
|
|
591
|
+
|
|
490
592
|
// check for the mention indicators in the previous word
|
|
491
593
|
unichar previousFirstChar = [previousWordText characterAtIndex:0];
|
|
492
|
-
|
|
493
|
-
if([[_input->config mentionIndicators]
|
|
494
|
-
|
|
495
|
-
|
|
594
|
+
|
|
595
|
+
if ([[_input->config mentionIndicators]
|
|
596
|
+
containsObject:@(previousFirstChar)]) {
|
|
597
|
+
// previous word has a proper mention indicator: treat both words as
|
|
598
|
+
// an editable mention
|
|
599
|
+
finalText = [NSString
|
|
600
|
+
stringWithFormat:@"%@ %@", previousWordText, currentWordText];
|
|
496
601
|
// range length is both words' lengths + 1 for a space between them
|
|
497
|
-
finalRange =
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
602
|
+
finalRange =
|
|
603
|
+
NSMakeRange([previousWordRange rangeValue].location,
|
|
604
|
+
[previousWordRange rangeValue].length +
|
|
605
|
+
[currentWordRange rangeValue].length + 1);
|
|
501
606
|
} else {
|
|
502
607
|
// neither current nor previous words have a mention indicator
|
|
503
608
|
return nullptr;
|
|
504
609
|
}
|
|
505
610
|
} else {
|
|
506
|
-
// previous word doesn't exist and no mention indicators in the current
|
|
611
|
+
// previous word doesn't exist and no mention indicators in the current
|
|
612
|
+
// word
|
|
507
613
|
return nullptr;
|
|
508
614
|
}
|
|
509
615
|
}
|
|
510
616
|
} else {
|
|
511
617
|
// current word doesn't exist; try getting the previous one
|
|
512
|
-
|
|
513
|
-
NSInteger previousWordSearchLocation =
|
|
514
|
-
|
|
618
|
+
|
|
619
|
+
NSInteger previousWordSearchLocation =
|
|
620
|
+
_input->textView.selectedRange.location - 1;
|
|
621
|
+
if (previousWordSearchLocation < 0) {
|
|
515
622
|
// previous word can't exist
|
|
516
623
|
return nullptr;
|
|
517
624
|
}
|
|
518
|
-
|
|
519
|
-
unichar separatorChar = [_input->textView.textStorage.string
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
625
|
+
|
|
626
|
+
unichar separatorChar = [_input->textView.textStorage.string
|
|
627
|
+
characterAtIndex:previousWordSearchLocation];
|
|
628
|
+
if (![[NSCharacterSet whitespaceCharacterSet]
|
|
629
|
+
characterIsMember:separatorChar]) {
|
|
630
|
+
// we want to check for the previous word ONLY if the separating character
|
|
631
|
+
// was a space newlines don't make it
|
|
523
632
|
return nullptr;
|
|
524
633
|
}
|
|
525
|
-
|
|
526
|
-
previousWord =
|
|
527
|
-
|
|
528
|
-
|
|
634
|
+
|
|
635
|
+
previousWord =
|
|
636
|
+
[WordsUtils getCurrentWord:_input->textView.textStorage.string
|
|
637
|
+
range:NSMakeRange(previousWordSearchLocation, 0)];
|
|
638
|
+
|
|
639
|
+
if (previousWord != nullptr) {
|
|
529
640
|
// previous word exists; get its properties
|
|
530
641
|
previousWordText = (NSString *)[previousWord objectForKey:@"word"];
|
|
531
642
|
previousWordRange = (NSValue *)[previousWord objectForKey:@"range"];
|
|
532
|
-
|
|
643
|
+
|
|
533
644
|
// check for the mention indicators in the previous word
|
|
534
645
|
unichar previousFirstChar = [previousWordText characterAtIndex:0];
|
|
535
|
-
|
|
536
|
-
if([[_input->config mentionIndicators]
|
|
537
|
-
|
|
646
|
+
|
|
647
|
+
if ([[_input->config mentionIndicators]
|
|
648
|
+
containsObject:@(previousFirstChar)]) {
|
|
649
|
+
// previous word has a proper mention indicator; treat previous word + a
|
|
650
|
+
// space as a editable mention
|
|
538
651
|
finalText = [NSString stringWithFormat:@"%@ ", previousWordText];
|
|
539
652
|
// the range length is previous word length + 1 for a space
|
|
540
|
-
finalRange = NSMakeRange([previousWordRange rangeValue].location,
|
|
653
|
+
finalRange = NSMakeRange([previousWordRange rangeValue].location,
|
|
654
|
+
[previousWordRange rangeValue].length + 1);
|
|
541
655
|
} else {
|
|
542
656
|
// no current word, previous has no mention indicators
|
|
543
657
|
return nullptr;
|
|
@@ -547,22 +661,26 @@ static NSString *const MentionAttributeName = @"MentionAttributeName";
|
|
|
547
661
|
return nullptr;
|
|
548
662
|
}
|
|
549
663
|
}
|
|
550
|
-
|
|
551
|
-
return @[finalText, [NSValue valueWithRange:finalRange]];
|
|
664
|
+
|
|
665
|
+
return @[ finalText, [NSValue valueWithRange:finalRange] ];
|
|
552
666
|
}
|
|
553
667
|
|
|
554
|
-
// both used for setting the active mention range + indicator and fires proper
|
|
668
|
+
// both used for setting the active mention range + indicator and fires proper
|
|
669
|
+
// onMention event
|
|
555
670
|
- (void)setActiveMentionRange:(NSRange)range text:(NSString *)text {
|
|
556
|
-
NSString *indicatorString =
|
|
557
|
-
|
|
671
|
+
NSString *indicatorString =
|
|
672
|
+
[NSString stringWithFormat:@"%C", [text characterAtIndex:0]];
|
|
673
|
+
NSString *textString =
|
|
674
|
+
[text substringWithRange:NSMakeRange(1, text.length - 1)];
|
|
558
675
|
_activeMentionIndicator = indicatorString;
|
|
559
676
|
_activeMentionRange = [NSValue valueWithRange:range];
|
|
560
677
|
[_input emitOnMentionEvent:indicatorString text:textString];
|
|
561
678
|
}
|
|
562
679
|
|
|
563
|
-
// removes stored mention range + indicator, which means that we no longer edit
|
|
680
|
+
// removes stored mention range + indicator, which means that we no longer edit
|
|
681
|
+
// a mention and onMention event gets fired
|
|
564
682
|
- (void)removeActiveMentionRange {
|
|
565
|
-
if(_activeMentionIndicator != nullptr && _activeMentionRange != nullptr) {
|
|
683
|
+
if (_activeMentionIndicator != nullptr && _activeMentionRange != nullptr) {
|
|
566
684
|
NSString *indicatorCopy = [_activeMentionIndicator copy];
|
|
567
685
|
_activeMentionIndicator = nullptr;
|
|
568
686
|
_activeMentionRange = nullptr;
|
|
@@ -571,4 +689,3 @@ static NSString *const MentionAttributeName = @"MentionAttributeName";
|
|
|
571
689
|
}
|
|
572
690
|
|
|
573
691
|
@end
|
|
574
|
-
|