Merge pull request #1570 from maicki/FixASTextNodeAttributedStringInconsitency

[ASTextNode] Fix API ASTextNode API inconsistencies
This commit is contained in:
appleguy
2016-05-10 13:44:56 -07:00
3 changed files with 103 additions and 55 deletions

View File

@@ -34,19 +34,19 @@ typedef NS_ENUM(NSUInteger, ASTextNodeHighlightStyle) {
@interface ASTextNode : ASControlNode
/**
@abstract The attributed string to show.
@abstract The styled text displayed by the node.
@discussion Defaults to nil, no text is shown.
For inline image attachments, add an attribute of key NSAttachmentAttributeName, with a value of an NSTextAttachment.
*/
@property (nullable, nonatomic, copy) NSAttributedString *attributedString;
@property (nullable, nonatomic, copy) NSAttributedString *attributedText;
#pragma mark - Truncation
/**
@abstract The attributedString to use when the text must be truncated.
@abstract The attributedText to use when the text must be truncated.
@discussion Defaults to a localized ellipsis character.
*/
@property (nullable, nonatomic, copy) NSAttributedString *truncationAttributedString;
@property (nullable, nonatomic, copy) NSAttributedString *truncationAttributedText;
/**
@summary The second attributed string appended for truncation.
@@ -270,4 +270,28 @@ typedef NS_ENUM(NSUInteger, ASTextNodeHighlightStyle) {
@end
/**
* @abstract Text node deprecated properties
*/
@interface ASTextNode (Deprecated)
/**
The attributedString and attributedText properties are equivalent, but attributedText is now the standard API
name in order to match UILabel and ASEditableTextNode.
@see attributedText
*/
@property (nullable, nonatomic, copy) NSAttributedString *attributedString;
/**
The truncationAttributedString and truncationAttributedText properties are equivalent, but attributedText is now the
standard API name in order to match UILabel and ASEditableTextNode.
@see truncationAttributedText
*/
@property (nullable, nonatomic, copy) NSAttributedString *truncationAttributedString;
@end
NS_ASSUME_NONNULL_END

View File

@@ -67,7 +67,7 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation
NSArray *_exclusionPaths;
NSAttributedString *_composedTruncationString;
NSAttributedString *_composedTruncationText;
NSString *_highlightedLinkAttributeName;
id _highlightedLinkAttributeValue;
@@ -105,7 +105,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
self.needsDisplayOnBoundsChange = YES;
_truncationMode = NSLineBreakByWordWrapping;
_composedTruncationString = DefaultTruncationAttributedString();
_composedTruncationText = DefaultTruncationAttributedString();
// The common case is for a text node to be non-opaque and blended over some background.
self.opaque = NO;
@@ -158,8 +158,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
- (NSString *)description
{
NSString *plainString = [[_attributedString string] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSString *truncationString = [_composedTruncationString string];
NSString *plainString = [[_attributedText string] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSString *truncationString = [_composedTruncationText string];
if (plainString.length > 50)
plainString = [[plainString substringToIndex:50] stringByAppendingString:@"\u2026"];
return [NSString stringWithFormat:@"<%@: %p; text = \"%@\"; truncation string = \"%@\"; frame = %@; renderer = %p>", self.class, self, plainString, truncationString, self.nodeLoaded ? NSStringFromCGRect(self.layer.frame) : nil, _renderer];
@@ -237,8 +237,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
- (ASTextKitAttributes)_rendererAttributes
{
return {
.attributedString = _attributedString,
.truncationAttributedString = _composedTruncationString,
.attributedString = _attributedText,
.truncationAttributedString = _composedTruncationText,
.lineBreakMode = _truncationMode,
.maximumNumberOfLines = _maximumNumberOfLines,
.exclusionPaths = _exclusionPaths,
@@ -340,10 +340,10 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
[self setNeedsDisplay];
CGSize size = [[self _renderer] size];
if (self.attributedString.length > 0) {
if (_attributedText.length > 0) {
CGFloat screenScale = ASScreenScale();
self.ascender = round([[_attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale;
self.descender = round([[_attributedString attribute:NSFontAttributeName atIndex:_attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale;
self.ascender = round([[_attributedText attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale;
self.descender = round([[_attributedText attribute:NSFontAttributeName atIndex:_attributedText.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale;
if (_renderer.currentScaleFactor > 0 && _renderer.currentScaleFactor < 1.0) {
// while not perfect, this is a good estimate of what the ascender of the scaled font will be.
self.ascender *= _renderer.currentScaleFactor;
@@ -355,28 +355,28 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
#pragma mark - Modifying User Text
- (void)setAttributedString:(NSAttributedString *)attributedString
- (void)setAttributedText:(NSAttributedString *)attributedText
{
if (attributedString == nil) {
attributedString = [[NSAttributedString alloc] initWithString:@"" attributes:nil];
if (attributedText == nil) {
attributedText = [[NSAttributedString alloc] initWithString:@"" attributes:nil];
}
if (ASObjectIsEqual(attributedString, _attributedString)) {
if (ASObjectIsEqual(attributedText, _attributedText)) {
return;
}
_attributedString = ASCleanseAttributedStringOfCoreTextAttributes(attributedString);
_attributedText = ASCleanseAttributedStringOfCoreTextAttributes(attributedText);
if (_attributedString.length > 0) {
if (_attributedText.length > 0) {
CGFloat screenScale = ASScreenScale();
self.ascender = round([[_attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale;
self.descender = round([[_attributedString attribute:NSFontAttributeName atIndex:_attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale;
self.ascender = round([[_attributedText attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale;
self.descender = round([[_attributedText attribute:NSFontAttributeName atIndex:_attributedText.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale;
}
// Sync the truncation string with attributes from the updated _attributedString
// Without this, the size calculation of the text with truncation applied will
// not take into account the attributes of attributedString in the last line
[self _updateComposedTruncationString];
// not take into account the attributes of attributedText in the last line
[self _updateComposedTruncationText];
// We need an entirely new renderer
[self _invalidateRenderer];
@@ -386,10 +386,10 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
[self setNeedsDisplay];
self.accessibilityLabel = _attributedString.string;
self.accessibilityLabel = _attributedText.string;
// We're an accessibility element by default if there is a string.
self.isAccessibilityElement = _attributedString.length != 0;
self.isAccessibilityElement = _attributedText.length != 0;
}
#pragma mark - Text Layout
@@ -470,7 +470,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
{
ASTextKitRenderer *renderer = [self _renderer];
NSRange visibleRange = renderer.visibleRanges[0];
NSAttributedString *attributedString = _attributedString;
NSAttributedString *attributedString = _attributedText;
NSRange clampedRange = NSIntersectionRange(visibleRange, NSMakeRange(0, attributedString.length));
// Check in a 9-point region around the actual touch point so we make sure
@@ -1023,14 +1023,14 @@ static NSAttributedString *DefaultTruncationAttributedString()
return defaultTruncationAttributedString;
}
- (void)setTruncationAttributedString:(NSAttributedString *)truncationAttributedString
- (void)setTruncationAttributedText:(NSAttributedString *)truncationAttributedText
{
if (ASObjectIsEqual(_truncationAttributedString, truncationAttributedString)) {
if (ASObjectIsEqual(_truncationAttributedText, truncationAttributedText)) {
return;
}
_truncationAttributedString = [truncationAttributedString copy];
[self _invalidateTruncationString];
_truncationAttributedText = [truncationAttributedText copy];
[self _invalidateTruncationText];
}
- (void)setAdditionalTruncationMessage:(NSAttributedString *)additionalTruncationMessage
@@ -1040,7 +1040,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
}
_additionalTruncationMessage = [additionalTruncationMessage copy];
[self _invalidateTruncationString];
[self _invalidateTruncationText];
}
- (void)setTruncationMode:(NSLineBreakMode)truncationMode
@@ -1055,7 +1055,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
- (BOOL)isTruncated
{
NSRange visibleRange = [self _renderer].visibleRanges[0];
return visibleRange.length < _attributedString.length;
return visibleRange.length < _attributedText.length;
}
- (void)setPointSizeScaleFactors:(NSArray *)pointSizeScaleFactors
@@ -1082,14 +1082,14 @@ static NSAttributedString *DefaultTruncationAttributedString()
#pragma mark - Truncation Message
- (void)_updateComposedTruncationString
- (void)_updateComposedTruncationText
{
_composedTruncationString = [self _prepareTruncationStringForDrawing:[self _composedTruncationString]];
_composedTruncationText = [self _prepareTruncationStringForDrawing:[self _composedTruncationText]];
}
- (void)_invalidateTruncationString
- (void)_invalidateTruncationText
{
[self _updateComposedTruncationString];
[self _updateComposedTruncationText];
[self _invalidateRenderer];
[self setNeedsDisplay];
}
@@ -1111,7 +1111,7 @@ static NSAttributedString *DefaultTruncationAttributedString()
NSUInteger additionalTruncationMessageLength = _additionalTruncationMessage.length;
// We get the location of the truncation token, then add the length of the
// truncation attributed string +1 for the space between.
NSRange range = NSMakeRange(truncationTokenIndex + _truncationAttributedString.length + 1, additionalTruncationMessageLength);
NSRange range = NSMakeRange(truncationTokenIndex + _truncationAttributedText.length + 1, additionalTruncationMessageLength);
return range;
}
@@ -1120,24 +1120,24 @@ static NSAttributedString *DefaultTruncationAttributedString()
* additional truncation message and a truncation attributed string, they will
* be properly composed.
*/
- (NSAttributedString *)_composedTruncationString
- (NSAttributedString *)_composedTruncationText
{
//If we have neither return the default
if (!_additionalTruncationMessage && !_truncationAttributedString) {
return _composedTruncationString;
if (!_additionalTruncationMessage && !_truncationAttributedText) {
return _composedTruncationText;
}
// Short circuit if we only have one or the other.
if (!_additionalTruncationMessage) {
return _truncationAttributedString;
return _truncationAttributedText;
}
if (!_truncationAttributedString) {
if (!_truncationAttributedText) {
return _additionalTruncationMessage;
}
// If we've reached this point, both _additionalTruncationMessage and
// _truncationAttributedString are present. Compose them.
NSMutableAttributedString *newComposedTruncationString = [[NSMutableAttributedString alloc] initWithAttributedString:_truncationAttributedString];
NSMutableAttributedString *newComposedTruncationString = [[NSMutableAttributedString alloc] initWithAttributedString:_truncationAttributedText];
[newComposedTruncationString replaceCharactersInRange:NSMakeRange(newComposedTruncationString.length, 0) withString:@" "];
[newComposedTruncationString appendAttributedString:_additionalTruncationMessage];
return newComposedTruncationString;
@@ -1153,9 +1153,9 @@ static NSAttributedString *DefaultTruncationAttributedString()
truncationString = ASCleanseAttributedStringOfCoreTextAttributes(truncationString);
NSMutableAttributedString *truncationMutableString = [truncationString mutableCopy];
// Grab the attributes from the full string
if (_attributedString.length > 0) {
NSAttributedString *originalString = _attributedString;
NSInteger originalStringLength = _attributedString.length;
if (_attributedText.length > 0) {
NSAttributedString *originalString = _truncationAttributedText;
NSInteger originalStringLength = _truncationAttributedText.length;
// Add any of the original string's attributes to the truncation string,
// but don't overwrite any of the truncation string's attributes
NSDictionary *originalStringAttributes = [originalString attributesAtIndex:originalStringLength-1 effectiveRange:NULL];
@@ -1170,3 +1170,27 @@ static NSAttributedString *DefaultTruncationAttributedString()
}
@end
@implementation ASTextNode (Deprecated)
- (void)setAttributedString:(NSAttributedString *)attributedString
{
self.attributedText = attributedString;
}
- (NSAttributedString *)attributedString
{
return self.attributedText;
}
- (void)setTruncationAttributedString:(NSAttributedString *)truncationAttributedString
{
self.truncationAttributedText = truncationAttributedString;
}
- (NSAttributedString *)truncationAttributedString
{
return self.truncationAttributedText;
}
@end

View File

@@ -44,7 +44,7 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta)
@interface ASTextNodeTests : XCTestCase
@property (nonatomic, readwrite, strong) ASTextNode *textNode;
@property (nonatomic, readwrite, copy) NSAttributedString *attributedString;
@property (nonatomic, readwrite, copy) NSAttributedString *attributedText;
@end
@@ -80,8 +80,8 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta)
[mas addAttribute:NSParagraphStyleAttributeName value:lastLinePara
range:NSMakeRange(mas.length - 1, 1)];
_attributedString = mas;
_textNode.attributedString = _attributedString;
_attributedText = mas;
_textNode.attributedText = _attributedText;
}
#pragma mark - ASTextNode
@@ -97,8 +97,8 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta)
- (void)testSettingTruncationMessage
{
NSAttributedString *truncation = [[NSAttributedString alloc] initWithString:@"..." attributes:nil];
_textNode.truncationAttributedString = truncation;
XCTAssertTrue([_textNode.truncationAttributedString isEqualToAttributedString:truncation], @"Failed to set truncation message");
_textNode.truncationAttributedText = truncation;
XCTAssertTrue([_textNode.truncationAttributedText isEqualToAttributedString:truncation], @"Failed to set truncation message");
}
- (void)testSettingAdditionalTruncationMessage
@@ -142,11 +142,11 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta)
- (void)testAccessibility
{
_textNode.attributedString = _attributedString;
_textNode.attributedText = _attributedText;
XCTAssertTrue(_textNode.isAccessibilityElement, @"Should be an accessibility element");
XCTAssertTrue(_textNode.accessibilityTraits == UIAccessibilityTraitStaticText, @"Should have static text accessibility trait, instead has %llu", _textNode.accessibilityTraits);
XCTAssertTrue([_textNode.accessibilityLabel isEqualToString:_attributedString.string], @"Accessibility label is incorrectly set to \n%@\n when it should be \n%@\n", _textNode.accessibilityLabel, _attributedString.string);
XCTAssertTrue([_textNode.accessibilityLabel isEqualToString:_attributedText.string], @"Accessibility label is incorrectly set to \n%@\n when it should be \n%@\n", _textNode.accessibilityLabel, _attributedText.string);
}
- (void)testLinkAttribute
@@ -156,7 +156,7 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta)
NSString *linkString = @"Link";
NSRange linkRange = NSMakeRange(0, linkString.length);
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:linkString attributes:@{ linkAttributeName : linkAttributeValue}];
_textNode.attributedString = attributedString;
_textNode.attributedText = attributedString;
_textNode.linkAttributeNames = @[linkAttributeName];
ASTextNodeTestDelegate *delegate = [ASTextNodeTestDelegate new];
@@ -178,7 +178,7 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta)
NSString *linkString = @"Link notalink";
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:linkString];
[attributedString addAttribute:linkAttributeName value:linkAttributeValue range:NSMakeRange(0, 4)];
_textNode.attributedString = attributedString;
_textNode.attributedText = attributedString;
_textNode.linkAttributeNames = @[linkAttributeName];
ASTextNodeTestDelegate *delegate = [ASTextNodeTestDelegate new];