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"
@@ -1262,7 +1265,13 @@ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args {
12621265 [self toggleRegularStyle: [StrikethroughStyle getStyleType ]];
12631266 } else if ([commandName isEqualToString: @" setColor" ]) {
12641267 NSString *colorText = (NSString *)args[0 ];
1265- [self setColor: colorText];
1268+ UIColor *color = [UIColor colorFromString: colorText];
1269+ id <BaseStyleProtocol> baseStyle = stylesDict[@(Colored)];
1270+ if ([baseStyle isKindOfClass: [ColorStyle class ]]) {
1271+ ColorStyle *colorStyle = (ColorStyle *)baseStyle;
1272+ [colorStyle applyStyle: textView.selectedRange color: color];
1273+ }
1274+ [self anyTextMayHaveBeenModified ];
12661275 } else if ([commandName isEqualToString: @" removeColor" ]) {
12671276 [self removeColor ];
12681277 [self anyTextMayHaveBeenModified ];
@@ -1478,14 +1487,14 @@ - (void)requestHTML:(NSInteger)requestId {
14781487
14791488- (void )setColor : (NSString *)colorText {
14801489 UIColor *color = [UIColor colorFromString: colorText];
1481- ColorStyle *colorStyle = stylesDict[@(Colored)];
1490+ ColorStyle *colorStyle = (ColorStyle *) stylesDict[@(Colored)];
14821491
14831492 [colorStyle applyStyle: textView.selectedRange color: color];
14841493 [self anyTextMayHaveBeenModified ];
14851494}
14861495
14871496- (void )removeColor {
1488- ColorStyle *colorStyle = stylesDict[@(Colored)];
1497+ ColorStyle *colorStyle = (ColorStyle *) stylesDict[@(Colored)];
14891498 [colorStyle removeColorInSelectedRange ];
14901499 [self anyTextMayHaveBeenModified ];
14911500}
@@ -1692,7 +1701,8 @@ - (void)manageSelectionBasedChanges {
16921701- (void )handleWordModificationBasedChanges : (NSString *)word
16931702 inRange : (NSRange )range {
16941703 // manual links refreshing and automatic links detection handling
1695- LinkStyle *linkStyle = [stylesDict objectForKey: @([LinkStyle getStyleType ])];
1704+ LinkStyle *linkStyle =
1705+ (LinkStyle *)[stylesDict objectForKey: @([LinkStyle getStyleType ])];
16961706
16971707 if (linkStyle != nullptr ) {
16981708 // manual links need to be handled first because they can block automatic
@@ -1891,24 +1901,62 @@ - (void)textViewDidEndEditing:(UITextView *)textView {
18911901 }
18921902}
18931903
1904+ - (BOOL )isReadOnlyParagraphAtLocation : (NSUInteger )location {
1905+ NSTextStorage *storage = textView.textStorage ;
1906+ NSUInteger length = storage.length ;
1907+
1908+ if (length == 0 ) {
1909+ return NO ;
1910+ }
1911+ if (location >= length) {
1912+ location = length - 1 ;
1913+ }
1914+
1915+ id currentValue = [storage attribute: ReadOnlyParagraphKey
1916+ atIndex: location
1917+ effectiveRange: nil ];
1918+ if (currentValue) {
1919+ return YES ;
1920+ }
1921+
1922+ if (location > 0 ) {
1923+ id previousValue = [storage attribute: ReadOnlyParagraphKey
1924+ atIndex: location - 1
1925+ effectiveRange: nil ];
1926+ if (previousValue) {
1927+ return YES ;
1928+ }
1929+ }
1930+
1931+ return NO ;
1932+ }
1933+
18941934- (bool )textView : (UITextView *)textView
18951935 shouldChangeTextInRange : (NSRange )range
18961936 replacementText : (NSString *)text {
1937+ if (![text isEqualToString: @" \n " ] &&
1938+ [self isReadOnlyParagraphAtLocation: range.location]) {
1939+ if (text.length == 0 )
1940+ return YES ;
1941+ return NO ;
1942+ }
18971943 recentlyChangedRange = NSMakeRange (range.location , text.length );
18981944
18991945 UnorderedListStyle *uStyle = stylesDict[@([UnorderedListStyle getStyleType ])];
19001946 OrderedListStyle *oStyle = stylesDict[@([OrderedListStyle getStyleType ])];
19011947 BlockQuoteStyle *bqStyle = stylesDict[@([BlockQuoteStyle getStyleType ])];
19021948 CodeBlockStyle *cbStyle = stylesDict[@([CodeBlockStyle getStyleType ])];
1903- LinkStyle *linkStyle = stylesDict[@([LinkStyle getStyleType ])];
1904- MentionStyle *mentionStyle = stylesDict[@([MentionStyle getStyleType ])];
1949+ LinkStyle *linkStyle = (LinkStyle *)stylesDict[@([LinkStyle getStyleType ])];
1950+ MentionStyle *mentionStyle =
1951+ (MentionStyle *)stylesDict[@([MentionStyle getStyleType ])];
19051952 H1Style *h1Style = stylesDict[@([H1Style getStyleType ])];
19061953 H2Style *h2Style = stylesDict[@([H2Style getStyleType ])];
19071954 H3Style *h3Style = stylesDict[@([H3Style getStyleType ])];
19081955 H4Style *h4Style = stylesDict[@([H4Style getStyleType ])];
19091956 H5Style *h5Style = stylesDict[@([H5Style getStyleType ])];
19101957 H6Style *h6Style = stylesDict[@([H6Style getStyleType ])];
1911- CheckBoxStyle *checkBoxStyle = stylesDict[@([CheckBoxStyle getStyleType ])];
1958+ CheckBoxStyle *checkBoxStyle =
1959+ (CheckBoxStyle *)stylesDict[@([CheckBoxStyle getStyleType ])];
19121960
19131961 // some of the changes these checks do could interfere with later checks and
19141962 // cause a crash so here I rely on short circuiting evaluation of the logical
@@ -2014,8 +2062,6 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
20142062 return YES ;
20152063}
20162064
2017- #pragma mark - Checkbox Helpers
2018-
20192065- (CGPoint)adjustedPointForViewPoint : (CGPoint)pt {
20202066 CGPoint tvPoint = [self convertPoint: pt toView: textView];
20212067 tvPoint.x -= textView.textContainerInset .left ;
@@ -2037,55 +2083,45 @@ - (BOOL)getCharIndex:(NSUInteger *)charIndex forAdjustedPoint:(CGPoint)pt {
20372083 return YES ;
20382084}
20392085
2040- - (CGRect)checkboxRectForGlyphIndex : (NSUInteger )glyphIndex {
2041- NSRange effective = {0 , 0 };
2042- CGRect lineRect =
2043- [textView.layoutManager lineFragmentRectForGlyphAtIndex: glyphIndex
2044- effectiveRange: &effective];
2045-
2046- CGFloat w = [config checkBoxWidth ];
2047- CGFloat h = [config checkBoxHeight ];
2048- CGFloat ml = [config checkboxListMarginLeft ];
2049- CGFloat gap = [config checkboxListGapWidth ];
2050-
2051- return CGRectMake (ml + gap,
2052- lineRect.origin .y + (lineRect.size .height - h) / 2.0 , w, h);
2053- }
2054-
2055- - (CheckBoxStyle *)checkboxStyleForCharIndex : (NSUInteger )charIndex {
2056- CheckBoxStyle *check = stylesDict[@([CheckBoxStyle getStyleType ])];
2057- if (check && [check detectStyle: NSMakeRange (charIndex, 0 )]) {
2058- return check;
2059- }
2060- return nil ;
2061- }
2062-
20632086- (void )handleTap : (UITapGestureRecognizer *)gr {
20642087 if (gr.state != UIGestureRecognizerStateEnded)
20652088 return ;
20662089
20672090 CGPoint adjusted = [self adjustedPointForViewPoint: [gr locationInView: self ]];
2091+ NSInteger dividerCharIndex =
2092+ [DividerHitTestUtils hitTestDividerAtPoint: adjusted inInput: self ];
2093+ if (dividerCharIndex >= 0 ) {
2094+ NSUInteger newLocation = (NSUInteger )dividerCharIndex + 1 ;
2095+ if (newLocation > textView.textStorage .length ) {
2096+ newLocation = textView.textStorage .length ;
2097+ }
20682098
2069- NSUInteger charIndex;
2070- if (![self getCharIndex: &charIndex forAdjustedPoint: adjusted])
2099+ textView.selectedRange = NSMakeRange (newLocation, 0 );
20712100 return ;
2101+ }
20722102
2073- CheckBoxStyle *check = [self checkboxStyleForCharIndex: charIndex];
2074- if (!check)
2103+ NSInteger contentCharIndex =
2104+ [ContentHitTestUtils hitTestContentAtPoint: adjusted inInput: self ];
2105+ if (contentCharIndex >= 0 ) {
2106+ NSUInteger newLocation = (NSUInteger )contentCharIndex + 1 ;
2107+ if (newLocation > textView.textStorage .length ) {
2108+ newLocation = textView.textStorage .length ;
2109+ }
2110+ textView.selectedRange = NSMakeRange (newLocation, 0 );
20752111 return ;
2112+ }
20762113
2077- // Get glyphIndex separately for the rectangle
2078- NSUInteger glyphIndex =
2079- [textView.layoutManager glyphIndexForPoint: adjusted
2080- inTextContainer: textView.textContainer
2081- fractionOfDistanceThroughGlyph: nil ];
2082-
2083- CGRect checkboxRect = [self checkboxRectForGlyphIndex: glyphIndex];
2084- if (!CGRectContainsPoint (checkboxRect, adjusted))
2114+ NSInteger checkboxCharIndex =
2115+ [CheckboxHitTestUtils hitTestCheckboxAtPoint: adjusted inInput: self ];
2116+ if (checkboxCharIndex >= 0 ) {
2117+ CheckBoxStyle *check =
2118+ (CheckBoxStyle *)stylesDict[@([CheckBoxStyle getStyleType ])];
2119+ if (check) {
2120+ [check toggleCheckedAt: (NSUInteger )checkboxCharIndex];
2121+ [self anyTextMayHaveBeenModified ];
2122+ }
20852123 return ;
2086-
2087- [check toggleCheckedAt: charIndex];
2088- [self anyTextMayHaveBeenModified ];
2124+ }
20892125}
20902126
20912127- (UIView *)hitTest : (CGPoint)point withEvent : (UIEvent *)event {
@@ -2095,23 +2131,17 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
20952131
20962132 CGPoint adjusted = [self adjustedPointForViewPoint: point];
20972133
2098- NSUInteger charIndex;
2099- if (![self getCharIndex: &charIndex forAdjustedPoint: adjusted])
2100- return hit;
2101-
2102- CheckBoxStyle *check = [self checkboxStyleForCharIndex: charIndex];
2103- if (!check)
2104- return hit;
2105-
2106- NSUInteger glyphIndex =
2107- [textView.layoutManager glyphIndexForPoint: adjusted
2108- inTextContainer: textView.textContainer
2109- fractionOfDistanceThroughGlyph: nil ];
2134+ if ([DividerHitTestUtils hitTestDividerAtPoint: adjusted inInput: self ] >= 0 ) {
2135+ return self;
2136+ }
21102137
2111- CGRect checkboxRect = [self checkboxRectForGlyphIndex: glyphIndex];
2138+ if ([ContentHitTestUtils hitTestContentAtPoint: adjusted inInput: self ] >= 0 ) {
2139+ return self;
2140+ }
21122141
2113- if (CGRectContainsPoint (checkboxRect, adjusted)) {
2114- return self; // intercept touch
2142+ if ([CheckboxHitTestUtils hitTestCheckboxAtPoint: adjusted
2143+ inInput: self ] >= 0 ) {
2144+ return self;
21152145 }
21162146
21172147 return hit;
0 commit comments