diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e60016913..9a3e684671 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ - [ASDisplayNode] Expose default Texture-set accessibility values as properties. [Jia Wern Lim](https://github.com/jiawernlim) [#1170](https://github.com/TextureGroup/Texture/pull/1170) - ASTableNode init method match checks from ASCollectionNode [Michael Schneider](https://github.com/maicki) [#1171] - Add NSLocking conformance to ASNodeController [Michael Schneider](https://github.com/maicki)[#1179] (https://github.com/TextureGroup/Texture/pull/1179) +- Don’t handle touches on additional attributed message if passthrough is enabled [Michael Schneider](https://github.com/maicki)[#1184] (https://github.com/TextureGroup/Texture/pull/1184) ## 2.7 - Fix pager node for interface coalescing. [Max Wang](https://github.com/wsdwsd0829) [#877](https://github.com/TextureGroup/Texture/pull/877) diff --git a/Source/ASTextNode.mm b/Source/ASTextNode.mm index accbea3ad5..c6a8ca10ad 100644 --- a/Source/ASTextNode.mm +++ b/Source/ASTextNode.mm @@ -973,9 +973,7 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI NSUInteger lastCharIndex = NSIntegerMax; BOOL linkCrossesVisibleRange = (lastCharIndex > range.location) && (lastCharIndex < NSMaxRange(range) - 1); - if (inAdditionalTruncationMessage) { - return YES; - } else if (range.length && !linkCrossesVisibleRange && linkAttributeValue != nil && linkAttributeName != nil) { + if (range.length > 0 && !linkCrossesVisibleRange && linkAttributeValue != nil && linkAttributeName != nil) { return YES; } else { return NO; @@ -1011,7 +1009,7 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI } NSRange truncationMessageRange = [self _additionalTruncationMessageRangeWithVisibleRange:visibleRange]; [self _setHighlightRange:truncationMessageRange forAttributeName:ASTextNodeTruncationTokenAttributeName value:nil animated:YES]; - } else if (range.length && !linkCrossesVisibleRange && linkAttributeValue != nil && linkAttributeName != nil) { + } else if (range.length > 0 && !linkCrossesVisibleRange && linkAttributeValue != nil && linkAttributeName != nil) { [self _setHighlightRange:range forAttributeName:linkAttributeName value:linkAttributeValue animated:YES]; } } diff --git a/Source/ASTextNode2.mm b/Source/ASTextNode2.mm index 6d894be82d..4a43278da9 100644 --- a/Source/ASTextNode2.mm +++ b/Source/ASTextNode2.mm @@ -572,20 +572,17 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; ASTextContainer *containerCopy = [_textContainer copy]; containerCopy.size = self.calculatedSize; ASTextLayout *layout = ASTextNodeCompatibleLayoutWithContainerAndText(containerCopy, _attributedText); - NSRange visibleRange = layout.visibleRange; - NSRange clampedRange = NSIntersectionRange(visibleRange, NSMakeRange(0, _attributedText.length)); - ASTextRange *range = [layout closestTextRangeAtPoint:point]; - - // For now, assume that a tap inside this text, but outside the text range is a tap on the - // truncation token. - if (![layout textRangeAtPoint:point]) { + if ([self _locked_pointInsideAdditionalTruncationMessage:point withLayout:layout]) { if (inAdditionalTruncationMessageOut != NULL) { *inAdditionalTruncationMessageOut = YES; } return nil; } + NSRange visibleRange = layout.visibleRange; + NSRange clampedRange = NSIntersectionRange(visibleRange, NSMakeRange(0, _attributedText.length)); + ASTextRange *range = [layout closestTextRangeAtPoint:point]; NSRange effectiveRange = NSMakeRange(0, 0); for (__strong NSString *attributeName in self.linkAttributeNames) { id value = [self.attributedText attribute:attributeName atIndex:range.start.offset longestEffectiveRange:&effectiveRange inRange:clampedRange]; @@ -617,6 +614,61 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; return nil; } +- (BOOL)_locked_pointInsideAdditionalTruncationMessage:(CGPoint)point withLayout:(ASTextLayout *)layout +{ + // Check if the range is within the additional truncation range + BOOL inAdditionalTruncationMessage = NO; + + CTLineRef truncatedCTLine = layout.truncatedLine.CTLine; + if (truncatedCTLine != NULL && _additionalTruncationMessage != nil) { + CFIndex stringIndexForPosition = CTLineGetStringIndexForPosition(truncatedCTLine, point); + if (stringIndexForPosition != kCFNotFound) { + CFIndex truncatedCTLineGlyphCount = CTLineGetGlyphCount(truncatedCTLine); + + CTLineRef truncationTokenLine = CTLineCreateWithAttributedString((CFAttributedStringRef)_truncationAttributedText); + CFIndex truncationTokenLineGlyphCount = truncationTokenLine ? CTLineGetGlyphCount(truncationTokenLine) : 0; + + CTLineRef additionalTruncationTokenLine = CTLineCreateWithAttributedString((CFAttributedStringRef)_additionalTruncationMessage); + CFIndex additionalTruncationTokenLineGlyphCount = additionalTruncationTokenLine ? CTLineGetGlyphCount(additionalTruncationTokenLine) : 0; + + switch (_textContainer.truncationType) { + case ASTextTruncationTypeStart: { + CFIndex composedTruncationTextLineGlyphCount = truncationTokenLineGlyphCount + additionalTruncationTokenLineGlyphCount; + if (stringIndexForPosition > truncationTokenLineGlyphCount && + stringIndexForPosition < composedTruncationTextLineGlyphCount) { + inAdditionalTruncationMessage = YES; + } + break; + } + case ASTextTruncationTypeMiddle: { + CFIndex composedTruncationTextLineGlyphCount = truncationTokenLineGlyphCount + additionalTruncationTokenLineGlyphCount; + CFIndex firstTruncatedTokenIndex = (truncatedCTLineGlyphCount - composedTruncationTextLineGlyphCount) / 2.0; + if ((firstTruncatedTokenIndex + truncationTokenLineGlyphCount) < stringIndexForPosition && + stringIndexForPosition < (firstTruncatedTokenIndex + composedTruncationTextLineGlyphCount)) { + inAdditionalTruncationMessage = YES; + } + break; + } + case ASTextTruncationTypeEnd: { + if (stringIndexForPosition > (truncatedCTLineGlyphCount - additionalTruncationTokenLineGlyphCount)) { + inAdditionalTruncationMessage = YES; + } + break; + } + default: + // For now, assume that a tap inside this text, but outside the text range is a tap on the + // truncation token. + if (![layout textRangeAtPoint:point]) { + inAdditionalTruncationMessage = YES; + } + break; + } + } + } + + return inAdditionalTruncationMessage; +} + #pragma mark - UIGestureRecognizerDelegate - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer @@ -789,9 +841,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; NSUInteger lastCharIndex = NSIntegerMax; BOOL linkCrossesVisibleRange = (lastCharIndex > range.location) && (lastCharIndex < NSMaxRange(range) - 1); - if (inAdditionalTruncationMessage) { - return YES; - } else if (range.length && !linkCrossesVisibleRange && linkAttributeValue != nil && linkAttributeName != nil) { + if (range.length > 0 && !linkCrossesVisibleRange && linkAttributeValue != nil && linkAttributeName != nil) { return YES; } else { return NO; @@ -832,7 +882,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; } NSRange truncationMessageRange = [self _additionalTruncationMessageRangeWithVisibleRange:visibleRange]; [self _setHighlightRange:truncationMessageRange forAttributeName:ASTextNodeTruncationTokenAttributeName value:nil animated:YES]; - } else if (range.length && !linkCrossesVisibleRange && linkAttributeValue != nil && linkAttributeName != nil) { + } else if (range.length > 0 && !linkCrossesVisibleRange && linkAttributeValue != nil && linkAttributeName != nil) { [self _setHighlightRange:range forAttributeName:linkAttributeName value:linkAttributeValue animated:YES]; } diff --git a/examples/Kittens/Sample/AppDelegate.m b/examples/Kittens/Sample/AppDelegate.m index d9465e0de7..2395642bd1 100644 --- a/examples/Kittens/Sample/AppDelegate.m +++ b/examples/Kittens/Sample/AppDelegate.m @@ -24,3 +24,14 @@ } @end + +@implementation ASConfiguration (UserProvided) + ++ (ASConfiguration *)textureConfiguration +{ + ASConfiguration *configuration = [ASConfiguration new]; + return configuration; + +} + +@end