11#import " EnrichedTextInputView.h"
2+ #import " CheckboxHitTestUtils.h"
23#import " ColorExtension.h"
4+ #import " ContentHitTestUtils.h"
35#import " CoreText/CoreText.h"
6+ #import " DividerHitTestUtils.h"
47#import " EnrichedImageLoader.h"
58#import " LayoutManagerExtension.h"
69#import " ParagraphAttributesUtils.h"
@@ -1266,7 +1269,13 @@ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args {
12661269 [self toggleRegularStyle: [StrikethroughStyle getStyleType ]];
12671270 } else if ([commandName isEqualToString: @" setColor" ]) {
12681271 NSString *colorText = (NSString *)args[0 ];
1269- [self setColor: colorText];
1272+ UIColor *color = [UIColor colorFromString: colorText];
1273+ id <BaseStyleProtocol> baseStyle = stylesDict[@(Colored)];
1274+ if ([baseStyle isKindOfClass: [ColorStyle class ]]) {
1275+ ColorStyle *colorStyle = (ColorStyle *)baseStyle;
1276+ [colorStyle applyStyle: textView.selectedRange color: color];
1277+ }
1278+ [self anyTextMayHaveBeenModified ];
12701279 } else if ([commandName isEqualToString: @" removeColor" ]) {
12711280 [self removeColor ];
12721281 [self anyTextMayHaveBeenModified ];
@@ -1519,14 +1528,14 @@ - (void)requestHTML:(NSInteger)requestId {
15191528
15201529- (void )setColor : (NSString *)colorText {
15211530 UIColor *color = [UIColor colorFromString: colorText];
1522- ColorStyle *colorStyle = stylesDict[@(Colored)];
1531+ ColorStyle *colorStyle = (ColorStyle *) stylesDict[@(Colored)];
15231532
15241533 [colorStyle applyStyle: textView.selectedRange color: color];
15251534 [self anyTextMayHaveBeenModified ];
15261535}
15271536
15281537- (void )removeColor {
1529- ColorStyle *colorStyle = stylesDict[@(Colored)];
1538+ ColorStyle *colorStyle = (ColorStyle *) stylesDict[@(Colored)];
15301539 [colorStyle removeColorInSelectedRange ];
15311540 [self anyTextMayHaveBeenModified ];
15321541}
@@ -1733,7 +1742,8 @@ - (void)manageSelectionBasedChanges {
17331742- (void )handleWordModificationBasedChanges : (NSString *)word
17341743 inRange : (NSRange )range {
17351744 // manual links refreshing and automatic links detection handling
1736- LinkStyle *linkStyle = [stylesDict objectForKey: @([LinkStyle getStyleType ])];
1745+ LinkStyle *linkStyle =
1746+ (LinkStyle *)[stylesDict objectForKey: @([LinkStyle getStyleType ])];
17371747
17381748 if (linkStyle != nullptr ) {
17391749 // manual links need to be handled first because they can block automatic
@@ -1932,24 +1942,62 @@ - (void)textViewDidEndEditing:(UITextView *)textView {
19321942 }
19331943}
19341944
1945+ - (BOOL )isReadOnlyParagraphAtLocation : (NSUInteger )location {
1946+ NSTextStorage *storage = textView.textStorage ;
1947+ NSUInteger length = storage.length ;
1948+
1949+ if (length == 0 ) {
1950+ return NO ;
1951+ }
1952+ if (location >= length) {
1953+ location = length - 1 ;
1954+ }
1955+
1956+ id currentValue = [storage attribute: ReadOnlyParagraphKey
1957+ atIndex: location
1958+ effectiveRange: nil ];
1959+ if (currentValue) {
1960+ return YES ;
1961+ }
1962+
1963+ if (location > 0 ) {
1964+ id previousValue = [storage attribute: ReadOnlyParagraphKey
1965+ atIndex: location - 1
1966+ effectiveRange: nil ];
1967+ if (previousValue) {
1968+ return YES ;
1969+ }
1970+ }
1971+
1972+ return NO ;
1973+ }
1974+
19351975- (bool )textView : (UITextView *)textView
19361976 shouldChangeTextInRange : (NSRange )range
19371977 replacementText : (NSString *)text {
1978+ if (![text isEqualToString: @" \n " ] &&
1979+ [self isReadOnlyParagraphAtLocation: range.location]) {
1980+ if (text.length == 0 )
1981+ return YES ;
1982+ return NO ;
1983+ }
19381984 recentlyChangedRange = NSMakeRange (range.location , text.length );
19391985
19401986 UnorderedListStyle *uStyle = stylesDict[@([UnorderedListStyle getStyleType ])];
19411987 OrderedListStyle *oStyle = stylesDict[@([OrderedListStyle getStyleType ])];
19421988 BlockQuoteStyle *bqStyle = stylesDict[@([BlockQuoteStyle getStyleType ])];
19431989 CodeBlockStyle *cbStyle = stylesDict[@([CodeBlockStyle getStyleType ])];
1944- LinkStyle *linkStyle = stylesDict[@([LinkStyle getStyleType ])];
1945- MentionStyle *mentionStyle = stylesDict[@([MentionStyle getStyleType ])];
1990+ LinkStyle *linkStyle = (LinkStyle *)stylesDict[@([LinkStyle getStyleType ])];
1991+ MentionStyle *mentionStyle =
1992+ (MentionStyle *)stylesDict[@([MentionStyle getStyleType ])];
19461993 H1Style *h1Style = stylesDict[@([H1Style getStyleType ])];
19471994 H2Style *h2Style = stylesDict[@([H2Style getStyleType ])];
19481995 H3Style *h3Style = stylesDict[@([H3Style getStyleType ])];
19491996 H4Style *h4Style = stylesDict[@([H4Style getStyleType ])];
19501997 H5Style *h5Style = stylesDict[@([H5Style getStyleType ])];
19511998 H6Style *h6Style = stylesDict[@([H6Style getStyleType ])];
1952- CheckBoxStyle *checkBoxStyle = stylesDict[@([CheckBoxStyle getStyleType ])];
1999+ CheckBoxStyle *checkBoxStyle =
2000+ (CheckBoxStyle *)stylesDict[@([CheckBoxStyle getStyleType ])];
19532001
19542002 // some of the changes these checks do could interfere with later checks and
19552003 // cause a crash so here I rely on short circuiting evaluation of the logical
@@ -2055,8 +2103,6 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
20552103 return YES ;
20562104}
20572105
2058- #pragma mark - Checkbox Helpers
2059-
20602106- (CGPoint)adjustedPointForViewPoint : (CGPoint)pt {
20612107 CGPoint tvPoint = [self convertPoint: pt toView: textView];
20622108 tvPoint.x -= textView.textContainerInset .left ;
@@ -2078,55 +2124,45 @@ - (BOOL)getCharIndex:(NSUInteger *)charIndex forAdjustedPoint:(CGPoint)pt {
20782124 return YES ;
20792125}
20802126
2081- - (CGRect)checkboxRectForGlyphIndex : (NSUInteger )glyphIndex {
2082- NSRange effective = {0 , 0 };
2083- CGRect lineRect =
2084- [textView.layoutManager lineFragmentRectForGlyphAtIndex: glyphIndex
2085- effectiveRange: &effective];
2086-
2087- CGFloat w = [config checkBoxWidth ];
2088- CGFloat h = [config checkBoxHeight ];
2089- CGFloat ml = [config checkboxListMarginLeft ];
2090- CGFloat gap = [config checkboxListGapWidth ];
2091-
2092- return CGRectMake (ml + gap,
2093- lineRect.origin .y + (lineRect.size .height - h) / 2.0 , w, h);
2094- }
2095-
2096- - (CheckBoxStyle *)checkboxStyleForCharIndex : (NSUInteger )charIndex {
2097- CheckBoxStyle *check = stylesDict[@([CheckBoxStyle getStyleType ])];
2098- if (check && [check detectStyle: NSMakeRange (charIndex, 0 )]) {
2099- return check;
2100- }
2101- return nil ;
2102- }
2103-
21042127- (void )handleTap : (UITapGestureRecognizer *)gr {
21052128 if (gr.state != UIGestureRecognizerStateEnded)
21062129 return ;
21072130
21082131 CGPoint adjusted = [self adjustedPointForViewPoint: [gr locationInView: self ]];
2132+ NSInteger dividerCharIndex =
2133+ [DividerHitTestUtils hitTestDividerAtPoint: adjusted inInput: self ];
2134+ if (dividerCharIndex >= 0 ) {
2135+ NSUInteger newLocation = (NSUInteger )dividerCharIndex + 1 ;
2136+ if (newLocation > textView.textStorage .length ) {
2137+ newLocation = textView.textStorage .length ;
2138+ }
21092139
2110- NSUInteger charIndex;
2111- if (![self getCharIndex: &charIndex forAdjustedPoint: adjusted])
2140+ textView.selectedRange = NSMakeRange (newLocation, 0 );
21122141 return ;
2142+ }
21132143
2114- CheckBoxStyle *check = [self checkboxStyleForCharIndex: charIndex];
2115- if (!check)
2144+ NSInteger contentCharIndex =
2145+ [ContentHitTestUtils hitTestContentAtPoint: adjusted inInput: self ];
2146+ if (contentCharIndex >= 0 ) {
2147+ NSUInteger newLocation = (NSUInteger )contentCharIndex + 1 ;
2148+ if (newLocation > textView.textStorage .length ) {
2149+ newLocation = textView.textStorage .length ;
2150+ }
2151+ textView.selectedRange = NSMakeRange (newLocation, 0 );
21162152 return ;
2153+ }
21172154
2118- // Get glyphIndex separately for the rectangle
2119- NSUInteger glyphIndex =
2120- [textView.layoutManager glyphIndexForPoint: adjusted
2121- inTextContainer: textView.textContainer
2122- fractionOfDistanceThroughGlyph: nil ];
2123-
2124- CGRect checkboxRect = [self checkboxRectForGlyphIndex: glyphIndex];
2125- if (!CGRectContainsPoint (checkboxRect, adjusted))
2155+ NSInteger checkboxCharIndex =
2156+ [CheckboxHitTestUtils hitTestCheckboxAtPoint: adjusted inInput: self ];
2157+ if (checkboxCharIndex >= 0 ) {
2158+ CheckBoxStyle *check =
2159+ (CheckBoxStyle *)stylesDict[@([CheckBoxStyle getStyleType ])];
2160+ if (check) {
2161+ [check toggleCheckedAt: (NSUInteger )checkboxCharIndex];
2162+ [self anyTextMayHaveBeenModified ];
2163+ }
21262164 return ;
2127-
2128- [check toggleCheckedAt: charIndex];
2129- [self anyTextMayHaveBeenModified ];
2165+ }
21302166}
21312167
21322168- (UIView *)hitTest : (CGPoint)point withEvent : (UIEvent *)event {
@@ -2136,23 +2172,17 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
21362172
21372173 CGPoint adjusted = [self adjustedPointForViewPoint: point];
21382174
2139- NSUInteger charIndex;
2140- if (![self getCharIndex: &charIndex forAdjustedPoint: adjusted])
2141- return hit;
2142-
2143- CheckBoxStyle *check = [self checkboxStyleForCharIndex: charIndex];
2144- if (!check)
2145- return hit;
2146-
2147- NSUInteger glyphIndex =
2148- [textView.layoutManager glyphIndexForPoint: adjusted
2149- inTextContainer: textView.textContainer
2150- fractionOfDistanceThroughGlyph: nil ];
2175+ if ([DividerHitTestUtils hitTestDividerAtPoint: adjusted inInput: self ] >= 0 ) {
2176+ return self;
2177+ }
21512178
2152- CGRect checkboxRect = [self checkboxRectForGlyphIndex: glyphIndex];
2179+ if ([ContentHitTestUtils hitTestContentAtPoint: adjusted inInput: self ] >= 0 ) {
2180+ return self;
2181+ }
21532182
2154- if (CGRectContainsPoint (checkboxRect, adjusted)) {
2155- return self; // intercept touch
2183+ if ([CheckboxHitTestUtils hitTestCheckboxAtPoint: adjusted
2184+ inInput: self ] >= 0 ) {
2185+ return self;
21562186 }
21572187
21582188 return hit;
0 commit comments