react-native-enriched 0.1.6 → 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 +4 -14
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +4 -1
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +2 -1
- 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/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.h +0 -45
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt +111 -2
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +9 -3
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewPackage.kt +2 -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 +42 -1
- 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 +135 -9
- 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 +13 -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/spans/utils/ForceRedrawSpan.kt +13 -0
- package/android/src/main/java/com/swmansion/enriched/styles/HtmlStyle.kt +80 -9
- package/android/src/main/java/com/swmansion/enriched/styles/InlineStyles.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/styles/ParagraphStyles.kt +188 -5
- package/android/src/main/java/com/swmansion/enriched/styles/ParametrizedStyles.kt +57 -30
- package/android/src/main/java/com/swmansion/enriched/utils/AsyncDrawable.kt +91 -0
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java +24 -13
- package/android/src/main/java/com/swmansion/enriched/utils/ResourceManager.kt +26 -0
- package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedSpanWatcher.kt +3 -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/android/src/main/res/drawable/broken_image.xml +10 -0
- package/ios/EnrichedTextInputView.h +27 -12
- package/ios/EnrichedTextInputView.mm +906 -547
- 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 +12 -6
- package/ios/config/InputConfig.mm +71 -33
- package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.cpp +10 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.h +7 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/Props.h +0 -45
- package/ios/generated/RNEnrichedTextInputViewSpec/RCTComponentViewHelpers.h +41 -4
- package/ios/inputParser/InputParser.h +5 -5
- package/ios/inputParser/InputParser.mm +867 -333
- 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 -24
- package/ios/internals/EnrichedTextInputViewShadowNode.mm +64 -47
- package/ios/internals/EnrichedTextInputViewState.h +3 -1
- package/ios/styles/BlockQuoteStyle.mm +192 -142
- package/ios/styles/BoldStyle.mm +96 -62
- package/ios/styles/CodeBlockStyle.mm +304 -0
- package/ios/styles/H1Style.mm +10 -3
- package/ios/styles/H2Style.mm +10 -3
- package/ios/styles/H3Style.mm +10 -3
- package/ios/styles/HeadingStyleBase.mm +129 -84
- package/ios/styles/ImageStyle.mm +160 -0
- package/ios/styles/InlineCodeStyle.mm +149 -84
- package/ios/styles/ItalicStyle.mm +77 -51
- package/ios/styles/LinkStyle.mm +353 -224
- package/ios/styles/MentionStyle.mm +434 -220
- package/ios/styles/OrderedListStyle.mm +172 -105
- package/ios/styles/StrikethroughStyle.mm +53 -34
- package/ios/styles/UnderlineStyle.mm +69 -45
- package/ios/styles/UnorderedListStyle.mm +170 -105
- package/ios/utils/BaseStyleProtocol.h +3 -2
- package/ios/utils/ColorExtension.mm +7 -5
- package/ios/utils/FontExtension.mm +42 -27
- package/ios/utils/ImageData.h +10 -0
- package/ios/utils/ImageData.mm +4 -0
- package/ios/utils/LayoutManagerExtension.h +1 -1
- package/ios/utils/LayoutManagerExtension.mm +334 -109
- 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 -38
- package/ios/utils/OccurenceUtils.mm +177 -107
- package/ios/utils/ParagraphAttributesUtils.h +6 -1
- package/ios/utils/ParagraphAttributesUtils.mm +152 -41
- 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 +35 -11
- 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 +153 -75
- package/lib/module/EnrichedTextInput.js +41 -3
- package/lib/module/EnrichedTextInput.js.map +1 -1
- package/lib/module/EnrichedTextInputNativeComponent.ts +17 -5
- package/lib/module/normalizeHtmlStyle.js +0 -4
- package/lib/module/normalizeHtmlStyle.js.map +1 -1
- package/lib/typescript/src/EnrichedTextInput.d.ts +2 -5
- package/lib/typescript/src/EnrichedTextInput.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts +7 -5
- package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/normalizeHtmlStyle.d.ts.map +1 -1
- package/package.json +8 -1
- package/src/EnrichedTextInput.tsx +48 -7
- package/src/EnrichedTextInputNativeComponent.ts +17 -5
- package/src/normalizeHtmlStyle.ts +0 -4
|
@@ -4,16 +4,19 @@
|
|
|
4
4
|
@implementation UIFont (FontExtension)
|
|
5
5
|
|
|
6
6
|
- (BOOL)isBold {
|
|
7
|
-
return (self.fontDescriptor.symbolicTraits & UIFontDescriptorTraitBold) ==
|
|
7
|
+
return (self.fontDescriptor.symbolicTraits & UIFontDescriptorTraitBold) ==
|
|
8
|
+
UIFontDescriptorTraitBold;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
- (UIFont *)setBold {
|
|
11
|
-
if([self isBold]) {
|
|
12
|
+
if ([self isBold]) {
|
|
12
13
|
return self;
|
|
13
14
|
}
|
|
14
|
-
UIFontDescriptorSymbolicTraits newTraits =
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
UIFontDescriptorSymbolicTraits newTraits =
|
|
16
|
+
(self.fontDescriptor.symbolicTraits | UIFontDescriptorTraitBold);
|
|
17
|
+
UIFontDescriptor *fontDescriptor =
|
|
18
|
+
[self.fontDescriptor fontDescriptorWithSymbolicTraits:newTraits];
|
|
19
|
+
if (fontDescriptor != nullptr) {
|
|
17
20
|
return [UIFont fontWithDescriptor:fontDescriptor size:0];
|
|
18
21
|
} else {
|
|
19
22
|
RCTLogWarn(@"[EnrichedTextInput]: Couldn't apply bold trait to the font.");
|
|
@@ -22,68 +25,80 @@
|
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
- (UIFont *)removeBold {
|
|
25
|
-
if(![self isBold]) {
|
|
28
|
+
if (![self isBold]) {
|
|
26
29
|
return self;
|
|
27
30
|
}
|
|
28
|
-
UIFontDescriptorSymbolicTraits newTraits =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
UIFontDescriptorSymbolicTraits newTraits =
|
|
32
|
+
(self.fontDescriptor.symbolicTraits ^ UIFontDescriptorTraitBold);
|
|
33
|
+
UIFontDescriptor *fontDescriptor =
|
|
34
|
+
[self.fontDescriptor fontDescriptorWithSymbolicTraits:newTraits];
|
|
35
|
+
if (fontDescriptor != nullptr) {
|
|
31
36
|
return [UIFont fontWithDescriptor:fontDescriptor size:0];
|
|
32
37
|
} else {
|
|
33
|
-
RCTLogWarn(
|
|
38
|
+
RCTLogWarn(
|
|
39
|
+
@"[EnrichedTextInput]: Couldn't remove bold trait from the font.");
|
|
34
40
|
return self;
|
|
35
41
|
}
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
- (BOOL)isItalic {
|
|
39
|
-
return (self.fontDescriptor.symbolicTraits & UIFontDescriptorTraitItalic) ==
|
|
45
|
+
return (self.fontDescriptor.symbolicTraits & UIFontDescriptorTraitItalic) ==
|
|
46
|
+
UIFontDescriptorTraitItalic;
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
- (UIFont *)setItalic {
|
|
43
|
-
if([self isItalic]) {
|
|
50
|
+
if ([self isItalic]) {
|
|
44
51
|
return self;
|
|
45
52
|
}
|
|
46
|
-
UIFontDescriptorSymbolicTraits newTraits =
|
|
47
|
-
|
|
48
|
-
|
|
53
|
+
UIFontDescriptorSymbolicTraits newTraits =
|
|
54
|
+
(self.fontDescriptor.symbolicTraits | UIFontDescriptorTraitItalic);
|
|
55
|
+
UIFontDescriptor *fontDescriptor =
|
|
56
|
+
[self.fontDescriptor fontDescriptorWithSymbolicTraits:newTraits];
|
|
57
|
+
if (fontDescriptor != nullptr) {
|
|
49
58
|
return [UIFont fontWithDescriptor:fontDescriptor size:0];
|
|
50
59
|
} else {
|
|
51
|
-
RCTLogWarn(
|
|
60
|
+
RCTLogWarn(
|
|
61
|
+
@"[EnrichedTextInput]: Couldn't apply italic trait to the font.");
|
|
52
62
|
return self;
|
|
53
63
|
}
|
|
54
64
|
}
|
|
55
65
|
|
|
56
66
|
- (UIFont *)removeItalic {
|
|
57
|
-
if(![self isItalic]) {
|
|
67
|
+
if (![self isItalic]) {
|
|
58
68
|
return self;
|
|
59
69
|
}
|
|
60
|
-
UIFontDescriptorSymbolicTraits newTraits =
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
UIFontDescriptorSymbolicTraits newTraits =
|
|
71
|
+
(self.fontDescriptor.symbolicTraits ^ UIFontDescriptorTraitItalic);
|
|
72
|
+
UIFontDescriptor *fontDescriptor =
|
|
73
|
+
[self.fontDescriptor fontDescriptorWithSymbolicTraits:newTraits];
|
|
74
|
+
if (fontDescriptor != nullptr) {
|
|
63
75
|
return [UIFont fontWithDescriptor:fontDescriptor size:0];
|
|
64
76
|
} else {
|
|
65
|
-
RCTLogWarn(
|
|
77
|
+
RCTLogWarn(
|
|
78
|
+
@"[EnrichedTextInput]: Couldn't remove italic trait from the font.");
|
|
66
79
|
return self;
|
|
67
80
|
}
|
|
68
81
|
}
|
|
69
82
|
|
|
70
83
|
- (UIFont *)withFontTraits:(UIFont *)from {
|
|
71
|
-
UIFont*
|
|
72
|
-
if([from isBold]) {
|
|
84
|
+
UIFont *newFont = self;
|
|
85
|
+
if ([from isBold]) {
|
|
73
86
|
newFont = [newFont setBold];
|
|
74
87
|
}
|
|
75
|
-
if([from isItalic]) {
|
|
88
|
+
if ([from isItalic]) {
|
|
76
89
|
newFont = [newFont setItalic];
|
|
77
90
|
}
|
|
78
91
|
return newFont;
|
|
79
92
|
}
|
|
80
93
|
|
|
81
94
|
- (UIFont *)setSize:(CGFloat)size {
|
|
82
|
-
UIFontDescriptor *newFontDescriptor =
|
|
83
|
-
|
|
95
|
+
UIFontDescriptor *newFontDescriptor =
|
|
96
|
+
[self.fontDescriptor fontDescriptorWithSize:size];
|
|
97
|
+
if (newFontDescriptor != nullptr) {
|
|
84
98
|
return [UIFont fontWithDescriptor:newFontDescriptor size:0];
|
|
85
99
|
} else {
|
|
86
|
-
RCTLogWarn(
|
|
100
|
+
RCTLogWarn(
|
|
101
|
+
@"[EnrichedTextInput]: Couldn't apply heading style to the font.");
|
|
87
102
|
return self;
|
|
88
103
|
}
|
|
89
104
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#import "LayoutManagerExtension.h"
|
|
2
|
-
#import
|
|
2
|
+
#import "ColorExtension.h"
|
|
3
3
|
#import "EnrichedTextInputView.h"
|
|
4
|
-
#import "StyleHeaders.h"
|
|
5
4
|
#import "ParagraphsUtils.h"
|
|
5
|
+
#import "StyleHeaders.h"
|
|
6
|
+
#import <objc/runtime.h>
|
|
6
7
|
|
|
7
8
|
@implementation NSLayoutManager (LayoutManagerExtension)
|
|
8
9
|
|
|
@@ -13,12 +14,8 @@ static void const *kInputKey = &kInputKey;
|
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
- (void)setInput:(id)value {
|
|
16
|
-
objc_setAssociatedObject(
|
|
17
|
-
|
|
18
|
-
kInputKey,
|
|
19
|
-
value,
|
|
20
|
-
OBJC_ASSOCIATION_RETAIN_NONATOMIC
|
|
21
|
-
);
|
|
17
|
+
objc_setAssociatedObject(self, kInputKey, value,
|
|
18
|
+
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
22
19
|
}
|
|
23
20
|
|
|
24
21
|
+ (void)load {
|
|
@@ -29,128 +26,356 @@ static void const *kInputKey = &kInputKey;
|
|
|
29
26
|
SEL swizzledSelector = @selector(my_drawBackgroundForGlyphRange:atPoint:);
|
|
30
27
|
Method originalMethod = class_getInstanceMethod(myClass, originalSelector);
|
|
31
28
|
Method swizzledMethod = class_getInstanceMethod(myClass, swizzledSelector);
|
|
32
|
-
|
|
33
|
-
BOOL didAddMethod = class_addMethod(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if(didAddMethod) {
|
|
29
|
+
|
|
30
|
+
BOOL didAddMethod = class_addMethod(
|
|
31
|
+
myClass, originalSelector, method_getImplementation(swizzledMethod),
|
|
32
|
+
method_getTypeEncoding(swizzledMethod));
|
|
33
|
+
|
|
34
|
+
if (didAddMethod) {
|
|
39
35
|
class_replaceMethod(myClass, swizzledSelector,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
);
|
|
36
|
+
method_getImplementation(originalMethod),
|
|
37
|
+
method_getTypeEncoding(originalMethod));
|
|
43
38
|
} else {
|
|
44
39
|
method_exchangeImplementations(originalMethod, swizzledMethod);
|
|
45
40
|
}
|
|
46
41
|
});
|
|
47
42
|
}
|
|
48
43
|
|
|
49
|
-
- (void)my_drawBackgroundForGlyphRange:(NSRange)glyphRange
|
|
44
|
+
- (void)my_drawBackgroundForGlyphRange:(NSRange)glyphRange
|
|
45
|
+
atPoint:(CGPoint)origin {
|
|
50
46
|
[self my_drawBackgroundForGlyphRange:glyphRange atPoint:origin];
|
|
51
|
-
|
|
47
|
+
|
|
52
48
|
EnrichedTextInputView *typedInput = (EnrichedTextInputView *)self.input;
|
|
53
|
-
if(typedInput == nullptr) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
49
|
+
if (typedInput == nullptr) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
NSRange visibleCharRange = [self characterRangeForGlyphRange:glyphRange
|
|
54
|
+
actualGlyphRange:NULL];
|
|
55
|
+
|
|
56
|
+
[self drawBlockQuotes:typedInput
|
|
57
|
+
origin:origin
|
|
58
|
+
visibleCharRange:visibleCharRange];
|
|
59
|
+
[self drawLists:typedInput origin:origin visibleCharRange:visibleCharRange];
|
|
60
|
+
[self drawCodeBlocks:typedInput
|
|
61
|
+
origin:origin
|
|
62
|
+
visibleCharRange:visibleCharRange];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
- (void)drawCodeBlocks:(EnrichedTextInputView *)typedInput
|
|
66
|
+
origin:(CGPoint)origin
|
|
67
|
+
visibleCharRange:(NSRange)visibleCharRange {
|
|
68
|
+
CodeBlockStyle *codeBlockStyle =
|
|
69
|
+
typedInput->stylesDict[@([CodeBlockStyle getStyleType])];
|
|
70
|
+
if (codeBlockStyle == nullptr) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
NSArray<StylePair *> *allCodeBlocks =
|
|
75
|
+
[codeBlockStyle findAllOccurences:visibleCharRange];
|
|
76
|
+
NSArray<StylePair *> *mergedCodeBlocks =
|
|
77
|
+
[self mergeContiguousStylePairs:allCodeBlocks];
|
|
78
|
+
UIColor *bgColor = [[typedInput->config codeBlockBgColor]
|
|
79
|
+
colorWithAlphaIfNotTransparent:0.4];
|
|
80
|
+
CGFloat radius = [typedInput->config codeBlockBorderRadius];
|
|
81
|
+
[bgColor setFill];
|
|
82
|
+
|
|
83
|
+
for (StylePair *pair in mergedCodeBlocks) {
|
|
84
|
+
NSRange blockCharacterRange = [pair.rangeValue rangeValue];
|
|
85
|
+
if (blockCharacterRange.length == 0)
|
|
86
|
+
continue;
|
|
87
|
+
|
|
88
|
+
NSArray *paragraphs =
|
|
89
|
+
[ParagraphsUtils getSeparateParagraphsRangesIn:typedInput->textView
|
|
90
|
+
range:blockCharacterRange];
|
|
91
|
+
if (paragraphs.count == 0)
|
|
92
|
+
continue;
|
|
93
|
+
|
|
94
|
+
NSRange firstParagraphRange =
|
|
95
|
+
[((NSValue *)[paragraphs firstObject]) rangeValue];
|
|
96
|
+
NSRange lastParagraphRange =
|
|
97
|
+
[((NSValue *)[paragraphs lastObject]) rangeValue];
|
|
98
|
+
|
|
99
|
+
for (NSValue *paragraphValue in paragraphs) {
|
|
100
|
+
NSRange paragraphCharacterRange = [paragraphValue rangeValue];
|
|
101
|
+
|
|
102
|
+
BOOL isFirstParagraph =
|
|
103
|
+
NSEqualRanges(paragraphCharacterRange, firstParagraphRange);
|
|
104
|
+
BOOL isLastParagraph =
|
|
105
|
+
NSEqualRanges(paragraphCharacterRange, lastParagraphRange);
|
|
106
|
+
|
|
107
|
+
NSRange paragraphGlyphRange =
|
|
108
|
+
[self glyphRangeForCharacterRange:paragraphCharacterRange
|
|
109
|
+
actualCharacterRange:NULL];
|
|
110
|
+
|
|
111
|
+
__block BOOL isFirstLineOfParagraph = YES;
|
|
112
|
+
|
|
113
|
+
[self
|
|
114
|
+
enumerateLineFragmentsForGlyphRange:paragraphGlyphRange
|
|
115
|
+
usingBlock:^(
|
|
116
|
+
CGRect rect, CGRect usedRect,
|
|
117
|
+
NSTextContainer *_Nonnull textContainer,
|
|
118
|
+
NSRange glyphRange,
|
|
119
|
+
BOOL *_Nonnull stop) {
|
|
120
|
+
CGRect lineBgRect = rect;
|
|
121
|
+
lineBgRect.origin.x = origin.x;
|
|
122
|
+
lineBgRect.origin.y += origin.y;
|
|
123
|
+
lineBgRect.size.width =
|
|
124
|
+
textContainer.size.width;
|
|
125
|
+
|
|
126
|
+
UIRectCorner cornersForThisLine = 0;
|
|
127
|
+
|
|
128
|
+
if (isFirstParagraph &&
|
|
129
|
+
isFirstLineOfParagraph) {
|
|
130
|
+
cornersForThisLine =
|
|
131
|
+
UIRectCornerTopLeft |
|
|
132
|
+
UIRectCornerTopRight;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
BOOL isLastLineOfParagraph =
|
|
136
|
+
(NSMaxRange(glyphRange) >=
|
|
137
|
+
NSMaxRange(paragraphGlyphRange));
|
|
138
|
+
|
|
139
|
+
if (isLastParagraph &&
|
|
140
|
+
isLastLineOfParagraph) {
|
|
141
|
+
cornersForThisLine =
|
|
142
|
+
cornersForThisLine |
|
|
143
|
+
UIRectCornerBottomLeft |
|
|
144
|
+
UIRectCornerBottomRight;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
UIBezierPath *path = [UIBezierPath
|
|
148
|
+
bezierPathWithRoundedRect:lineBgRect
|
|
149
|
+
byRoundingCorners:
|
|
150
|
+
cornersForThisLine
|
|
151
|
+
cornerRadii:CGSizeMake(
|
|
152
|
+
radius,
|
|
153
|
+
radius)];
|
|
154
|
+
[path fill];
|
|
155
|
+
|
|
156
|
+
isFirstLineOfParagraph = NO;
|
|
157
|
+
}];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
- (NSArray<StylePair *> *)mergeContiguousStylePairs:
|
|
163
|
+
(NSArray<StylePair *> *)pairs {
|
|
164
|
+
if (pairs.count == 0) {
|
|
165
|
+
return @[];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
NSMutableArray<StylePair *> *mergedPairs = [[NSMutableArray alloc] init];
|
|
169
|
+
StylePair *currentPair = pairs[0];
|
|
170
|
+
NSRange currentRange = [currentPair.rangeValue rangeValue];
|
|
171
|
+
for (NSUInteger i = 1; i < pairs.count; i++) {
|
|
172
|
+
StylePair *nextPair = pairs[i];
|
|
173
|
+
NSRange nextRange = [nextPair.rangeValue rangeValue];
|
|
174
|
+
|
|
175
|
+
// The Gap Check:
|
|
176
|
+
// NSMaxRange(currentRange) is where the current block ends.
|
|
177
|
+
// nextRange.location is where the next block starts.
|
|
178
|
+
if (NSMaxRange(currentRange) == nextRange.location) {
|
|
179
|
+
// They touch perfectly (no gap). Merge them.
|
|
180
|
+
currentRange.length += nextRange.length;
|
|
181
|
+
} else {
|
|
182
|
+
// There is a gap (indices don't match).
|
|
183
|
+
// 1. Save the finished block.
|
|
184
|
+
StylePair *mergedPair = [[StylePair alloc] init];
|
|
185
|
+
mergedPair.rangeValue = [NSValue valueWithRange:currentRange];
|
|
186
|
+
mergedPair.styleValue = currentPair.styleValue;
|
|
187
|
+
[mergedPairs addObject:mergedPair];
|
|
188
|
+
|
|
189
|
+
// 2. Start a brand new block.
|
|
190
|
+
currentPair = nextPair;
|
|
191
|
+
currentRange = nextRange;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Add the final block
|
|
196
|
+
StylePair *lastPair = [[StylePair alloc] init];
|
|
197
|
+
lastPair.rangeValue = [NSValue valueWithRange:currentRange];
|
|
198
|
+
lastPair.styleValue = currentPair.styleValue;
|
|
199
|
+
[mergedPairs addObject:lastPair];
|
|
200
|
+
|
|
201
|
+
return mergedPairs;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
- (void)drawBlockQuotes:(EnrichedTextInputView *)typedInput
|
|
205
|
+
origin:(CGPoint)origin
|
|
206
|
+
visibleCharRange:(NSRange)visibleCharRange {
|
|
207
|
+
BlockQuoteStyle *bqStyle =
|
|
208
|
+
typedInput->stylesDict[@([BlockQuoteStyle getStyleType])];
|
|
209
|
+
if (bqStyle == nullptr) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
NSArray *allBlockquotes = [bqStyle findAllOccurences:visibleCharRange];
|
|
214
|
+
|
|
215
|
+
for (StylePair *pair in allBlockquotes) {
|
|
216
|
+
NSRange paragraphRange = [typedInput->textView.textStorage.string
|
|
217
|
+
paragraphRangeForRange:[pair.rangeValue rangeValue]];
|
|
218
|
+
NSRange paragraphGlyphRange =
|
|
219
|
+
[self glyphRangeForCharacterRange:paragraphRange
|
|
220
|
+
actualCharacterRange:nullptr];
|
|
221
|
+
[self
|
|
222
|
+
enumerateLineFragmentsForGlyphRange:paragraphGlyphRange
|
|
223
|
+
usingBlock:^(
|
|
224
|
+
CGRect rect, CGRect usedRect,
|
|
225
|
+
NSTextContainer *_Nonnull textContainer,
|
|
226
|
+
NSRange glyphRange, BOOL *_Nonnull stop) {
|
|
227
|
+
CGFloat paddingLeft = origin.x;
|
|
228
|
+
CGFloat paddingTop = origin.y;
|
|
229
|
+
CGFloat x = paddingLeft;
|
|
230
|
+
CGFloat y = paddingTop + rect.origin.y;
|
|
231
|
+
CGFloat width =
|
|
232
|
+
[typedInput
|
|
233
|
+
->config blockquoteBorderWidth];
|
|
234
|
+
CGFloat height = rect.size.height;
|
|
235
|
+
|
|
236
|
+
CGRect lineRect =
|
|
237
|
+
CGRectMake(x, y, width, height);
|
|
238
|
+
[[typedInput->config blockquoteBorderColor]
|
|
239
|
+
setFill];
|
|
240
|
+
UIRectFill(lineRect);
|
|
241
|
+
}];
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
- (void)drawLists:(EnrichedTextInputView *)typedInput
|
|
246
|
+
origin:(CGPoint)origin
|
|
247
|
+
visibleCharRange:(NSRange)visibleCharRange {
|
|
248
|
+
UnorderedListStyle *ulStyle =
|
|
249
|
+
typedInput->stylesDict[@([UnorderedListStyle getStyleType])];
|
|
250
|
+
OrderedListStyle *olStyle =
|
|
251
|
+
typedInput->stylesDict[@([OrderedListStyle getStyleType])];
|
|
252
|
+
if (ulStyle == nullptr || olStyle == nullptr) {
|
|
253
|
+
return;
|
|
80
254
|
}
|
|
81
|
-
|
|
82
|
-
UnorderedListStyle *ulStyle = typedInput->stylesDict[@([UnorderedListStyle getStyleType])];
|
|
83
|
-
OrderedListStyle *olStyle = typedInput->stylesDict[@([OrderedListStyle getStyleType])];
|
|
84
|
-
if(ulStyle == nullptr || olStyle == nullptr) { return; }
|
|
85
|
-
|
|
86
|
-
// also not the most performant but we redraw all the lists
|
|
255
|
+
|
|
87
256
|
NSMutableArray *allLists = [[NSMutableArray alloc] init];
|
|
88
|
-
[allLists addObjectsFromArray:[ulStyle findAllOccurences:
|
|
89
|
-
[allLists addObjectsFromArray:[olStyle findAllOccurences:
|
|
90
|
-
|
|
91
|
-
for(StylePair *pair in allLists) {
|
|
257
|
+
[allLists addObjectsFromArray:[ulStyle findAllOccurences:visibleCharRange]];
|
|
258
|
+
[allLists addObjectsFromArray:[olStyle findAllOccurences:visibleCharRange]];
|
|
259
|
+
|
|
260
|
+
for (StylePair *pair in allLists) {
|
|
92
261
|
NSParagraphStyle *pStyle = (NSParagraphStyle *)pair.styleValue;
|
|
93
262
|
NSDictionary *markerAttributes = @{
|
|
94
|
-
NSFontAttributeName: [typedInput->config orderedListMarkerFont],
|
|
95
|
-
NSForegroundColorAttributeName:
|
|
263
|
+
NSFontAttributeName : [typedInput->config orderedListMarkerFont],
|
|
264
|
+
NSForegroundColorAttributeName :
|
|
265
|
+
[typedInput->config orderedListMarkerColor]
|
|
96
266
|
};
|
|
97
|
-
|
|
98
|
-
NSArray *paragraphs = [ParagraphsUtils
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
267
|
+
|
|
268
|
+
NSArray *paragraphs = [ParagraphsUtils
|
|
269
|
+
getSeparateParagraphsRangesIn:typedInput->textView
|
|
270
|
+
range:[pair.rangeValue rangeValue]];
|
|
271
|
+
|
|
272
|
+
for (NSValue *paragraph in paragraphs) {
|
|
273
|
+
NSRange paragraphGlyphRange =
|
|
274
|
+
[self glyphRangeForCharacterRange:[paragraph rangeValue]
|
|
275
|
+
actualCharacterRange:nullptr];
|
|
276
|
+
|
|
277
|
+
[self
|
|
278
|
+
enumerateLineFragmentsForGlyphRange:paragraphGlyphRange
|
|
279
|
+
usingBlock:^(CGRect rect, CGRect usedRect,
|
|
280
|
+
NSTextContainer *container,
|
|
281
|
+
NSRange lineGlyphRange,
|
|
282
|
+
BOOL *stop) {
|
|
283
|
+
NSString *marker = [self
|
|
284
|
+
markerForList:pStyle.textLists
|
|
285
|
+
.firstObject
|
|
286
|
+
charIndex:
|
|
287
|
+
[self
|
|
288
|
+
characterIndexForGlyphAtIndex:
|
|
289
|
+
lineGlyphRange
|
|
290
|
+
.location]
|
|
291
|
+
input:typedInput];
|
|
292
|
+
|
|
293
|
+
if (pStyle.textLists.firstObject
|
|
294
|
+
.markerFormat ==
|
|
295
|
+
NSTextListMarkerDecimal) {
|
|
296
|
+
CGFloat gapWidth =
|
|
297
|
+
[typedInput->config
|
|
298
|
+
orderedListGapWidth];
|
|
299
|
+
CGFloat markerWidth =
|
|
300
|
+
[marker sizeWithAttributes:
|
|
301
|
+
markerAttributes]
|
|
302
|
+
.width;
|
|
303
|
+
CGFloat markerX = usedRect.origin.x -
|
|
304
|
+
gapWidth -
|
|
305
|
+
markerWidth / 2;
|
|
306
|
+
|
|
307
|
+
[marker drawAtPoint:CGPointMake(
|
|
308
|
+
markerX,
|
|
309
|
+
usedRect.origin
|
|
310
|
+
.y +
|
|
311
|
+
origin.y)
|
|
312
|
+
withAttributes:markerAttributes];
|
|
313
|
+
} else {
|
|
314
|
+
CGFloat gapWidth =
|
|
315
|
+
[typedInput->config
|
|
316
|
+
unorderedListGapWidth];
|
|
317
|
+
CGFloat bulletSize =
|
|
318
|
+
[typedInput->config
|
|
319
|
+
unorderedListBulletSize];
|
|
320
|
+
CGFloat bulletX = usedRect.origin.x -
|
|
321
|
+
gapWidth -
|
|
322
|
+
bulletSize / 2;
|
|
323
|
+
CGFloat centerY =
|
|
324
|
+
CGRectGetMidY(usedRect);
|
|
325
|
+
|
|
326
|
+
CGContextRef context =
|
|
327
|
+
UIGraphicsGetCurrentContext();
|
|
328
|
+
CGContextSaveGState(context);
|
|
329
|
+
{
|
|
330
|
+
[[typedInput->config
|
|
331
|
+
unorderedListBulletColor]
|
|
332
|
+
setFill];
|
|
333
|
+
CGContextAddArc(
|
|
334
|
+
context, bulletX, centerY,
|
|
335
|
+
bulletSize / 2, 0, 2 * M_PI, YES);
|
|
336
|
+
CGContextFillPath(context);
|
|
337
|
+
}
|
|
338
|
+
CGContextRestoreGState(context);
|
|
339
|
+
}
|
|
340
|
+
// only first line of a list gets its
|
|
341
|
+
// marker drawn
|
|
342
|
+
*stop = YES;
|
|
343
|
+
}];
|
|
131
344
|
}
|
|
132
345
|
}
|
|
133
346
|
}
|
|
134
347
|
|
|
135
|
-
- (NSString *)markerForList:(NSTextList *)list
|
|
136
|
-
|
|
348
|
+
- (NSString *)markerForList:(NSTextList *)list
|
|
349
|
+
charIndex:(NSUInteger)index
|
|
350
|
+
input:(EnrichedTextInputView *)input {
|
|
351
|
+
if (list.markerFormat == NSTextListMarkerDecimal) {
|
|
137
352
|
NSString *fullText = input->textView.textStorage.string;
|
|
138
353
|
NSInteger itemNumber = 1;
|
|
139
|
-
|
|
140
|
-
NSRange currentParagraph =
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
354
|
+
|
|
355
|
+
NSRange currentParagraph =
|
|
356
|
+
[fullText paragraphRangeForRange:NSMakeRange(index, 0)];
|
|
357
|
+
if (currentParagraph.location > 0) {
|
|
358
|
+
OrderedListStyle *olStyle =
|
|
359
|
+
input->stylesDict[@([OrderedListStyle getStyleType])];
|
|
360
|
+
|
|
144
361
|
NSInteger prevParagraphsCount = 0;
|
|
145
|
-
NSInteger recentParagraphLocation =
|
|
146
|
-
|
|
362
|
+
NSInteger recentParagraphLocation =
|
|
363
|
+
[fullText
|
|
364
|
+
paragraphRangeForRange:NSMakeRange(currentParagraph.location - 1,
|
|
365
|
+
0)]
|
|
366
|
+
.location;
|
|
367
|
+
|
|
147
368
|
// seek for previous lists
|
|
148
|
-
while(true) {
|
|
149
|
-
if([olStyle detectStyle:NSMakeRange(recentParagraphLocation, 0)]) {
|
|
369
|
+
while (true) {
|
|
370
|
+
if ([olStyle detectStyle:NSMakeRange(recentParagraphLocation, 0)]) {
|
|
150
371
|
prevParagraphsCount += 1;
|
|
151
|
-
|
|
152
|
-
if(recentParagraphLocation > 0) {
|
|
153
|
-
recentParagraphLocation =
|
|
372
|
+
|
|
373
|
+
if (recentParagraphLocation > 0) {
|
|
374
|
+
recentParagraphLocation =
|
|
375
|
+
[fullText
|
|
376
|
+
paragraphRangeForRange:NSMakeRange(
|
|
377
|
+
recentParagraphLocation - 1, 0)]
|
|
378
|
+
.location;
|
|
154
379
|
} else {
|
|
155
380
|
break;
|
|
156
381
|
}
|
|
@@ -158,10 +383,10 @@ static void const *kInputKey = &kInputKey;
|
|
|
158
383
|
break;
|
|
159
384
|
}
|
|
160
385
|
}
|
|
161
|
-
|
|
386
|
+
|
|
162
387
|
itemNumber = prevParagraphsCount + 1;
|
|
163
388
|
}
|
|
164
|
-
|
|
389
|
+
|
|
165
390
|
return [NSString stringWithFormat:@"%ld.", (long)(itemNumber)];
|
|
166
391
|
} else {
|
|
167
392
|
return @"•";
|