Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions KILabel.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
Pod::Spec.new do |s|

s.name = "KILabel"
s.version = "1.0.1"
s.version = "1.0.2"
s.summary = "Replacement for UILabel for iOS 7 and 8 that provides automatic detection of links such as URLs, twitter style usernames and hashtags."

s.description = <<-DESC
Expand All @@ -22,7 +22,7 @@ Pod::Spec.new do |s|
s.screenshots = "https://raw.githubusercontent.com/Krelborn/KILabel/master/IKLabelDemoScreenshot.png"
s.license = { :type => "MIT", :file => "LICENSE" }

s.author = { "Matt Styles" => "matt@compiledcreations.com" }
s.author = { "Matt Styles" => "matt@compiledcreations.com", "Mark H. Granoff" => "mark@granoff.net" }
s.social_media_url = "http://twitter.com/Krelborn"

s.platform = :ios, "7.0"
Expand Down
30 changes: 28 additions & 2 deletions KILabel/Source/KILabel.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ typedef NS_ENUM(NSUInteger, KILinkType)
/**
* Usernames starting with "@" token
*/
KILinkTypeUserHandle,
KILinkTypeUserHandle = 0,

/**
* Hashtags starting with "#" token
Expand All @@ -46,6 +46,11 @@ typedef NS_ENUM(NSUInteger, KILinkType)
* URLs, http etc
*/
KILinkTypeURL,

/**
* Phone numbers
*/
KILinkTypePhoneNumber
};

/**
Expand Down Expand Up @@ -73,6 +78,11 @@ typedef NS_OPTIONS(NSUInteger, KILinkTypeOption)
*/
KILinkTypeOptionURL = 1 << KILinkTypeURL,

/**
* Specified to include KILinkTypePhoneNumber links
*/
KILinkTypeOptionPhoneNumber = 1 << KILinkTypePhoneNumber,

/**
* Convenience contstant to include all link types
*/
Expand Down Expand Up @@ -107,7 +117,7 @@ IB_DESIGNABLE
** ****************************************************************************************** **/

/**
* Enable/disable automatic detection of links, hashtags and usernames.
* Enable/disable automatic detection of links, hashtags, usernames, and phone numbers.
*/
@property (nonatomic, assign, getter = isAutomaticLinkDetectionEnabled) IBInspectable BOOL automaticLinkDetectionEnabled;

Expand All @@ -123,6 +133,17 @@ IB_DESIGNABLE
*/
@property (nullable, nonatomic, strong) NSSet *ignoredKeywords;

/**
* Ignore matches that do not already contain NSLinkAttributeName attributes.
*
* @discussion Affects detection using attributed strings only. Defaults to NO.
*
* When detecting links, do not select a match for highlighting unless it already contains an NSLinkAttributeName attribute.
* This is handy if you've pre-decorated an attributed string containing phone numbers, and you do NOT want the built-in
* phone number detector to include words like "Toll Free" or "Phone Number" or numbers you won't want called (like FAX numbers).
*/
@property (nonatomic, assign) BOOL ignoreMatchesWithoutLinkAttribute;

/** ****************************************************************************************** **
* @name Format & Appearance
** ****************************************************************************************** **/
Expand Down Expand Up @@ -176,6 +197,11 @@ IB_DESIGNABLE
*/
@property (nullable, nonatomic, copy) KILinkTapHandler urlLinkTapHandler;

/**
* Callback block for KILinkTypePhoneNumber link tap.
*/
@property (nullable, nonatomic, copy) KILinkTapHandler phoneNumberLinkTapHandler;

/** ****************************************************************************************** **
* @name Geometry
** ****************************************************************************************** **/
Expand Down
79 changes: 61 additions & 18 deletions KILabel/Source/KILabel.m
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ - (void)setupTextSystem
// Link Type Attributes. Default is empty (no attributes).
_linkTypeAttributes = [NSMutableDictionary dictionary];

// Highlight all matches for enabled link types
_ignoreMatchesWithoutLinkAttribute = NO;

// Don't underline URL links by default.
_systemURLStyle = NO;

Expand Down Expand Up @@ -388,6 +391,11 @@ - (NSArray *)getRangesForLinks:(NSAttributedString *)text
[rangesForLinks addObjectsFromArray:[self getRangesForURLs:self.attributedText]];
}

if (self.linkDetectionTypes & KILinkTypeOptionPhoneNumber)
{
[rangesForLinks addObjectsFromArray:[self getRangesForPhoneNumbers:self.attributedText]];
}

return rangesForLinks;
}

Expand Down Expand Up @@ -457,14 +465,13 @@ - (NSArray *)getRangesForHashtags:(NSString *)text
return rangesForHashtags;
}


- (NSArray *)getRangesForURLs:(NSAttributedString *)text
- (NSArray *)_getRangesForDetectorType:(NSTextCheckingTypes)detectorType usingLinkType:(KILinkType)linkType forText:(NSAttributedString *)text
{
NSMutableArray *rangesForURLs = [[NSMutableArray alloc] init];;
NSMutableArray *ranges = [[NSMutableArray alloc] init];

// Use a data detector to find urls in the text
// Use a data detector to mathing text
NSError *error = nil;
NSDataDetector *detector = [[NSDataDetector alloc] initWithTypes:NSTextCheckingTypeLink error:&error];
NSDataDetector *detector = [[NSDataDetector alloc] initWithTypes:detectorType error:&error];

NSString *plainText = text.string;

Expand All @@ -478,23 +485,49 @@ - (NSArray *)getRangesForURLs:(NSAttributedString *)text
NSRange matchRange = [match range];

// If there's a link embedded in the attributes, use that instead of the raw text
NSString *realURL = [text attribute:NSLinkAttributeName atIndex:matchRange.location effectiveRange:nil];
if (realURL == nil)
realURL = [plainText substringWithRange:matchRange];
__block NSString *realText = nil;
__block NSRange realRange = matchRange;

if (_ignoreMatchesWithoutLinkAttribute) {
[text enumerateAttributesInRange:matchRange
options:0
usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
if (attrs[NSLinkAttributeName]) {
// this is the text to highlight
realText = attrs[NSLinkAttributeName];
realRange = range;
*stop = YES;
}
}];
}

if (realText == nil && !_ignoreMatchesWithoutLinkAttribute)
realText = [plainText substringWithRange:realRange];

if (![self ignoreMatch:realURL])
if (realText && ![self ignoreMatch:realText])
{
if ([match resultType] == NSTextCheckingTypeLink)
if ([match resultType] == detectorType)
{
[rangesForURLs addObject:@{KILabelLinkTypeKey : @(KILinkTypeURL),
KILabelRangeKey : [NSValue valueWithRange:matchRange],
KILabelLinkKey : realURL,
}];
[ranges addObject:@{KILabelLinkTypeKey : @(linkType),
KILabelRangeKey : [NSValue valueWithRange:realRange],
KILabelLinkKey : realText,
}];
}
}
}

return rangesForURLs;
return ranges;

}

- (NSArray *)getRangesForURLs:(NSAttributedString *)text
{
return [self _getRangesForDetectorType:NSTextCheckingTypeLink usingLinkType:KILinkTypeURL forText:text];
}

- (NSArray *)getRangesForPhoneNumbers:(NSAttributedString *)text
{
return [self _getRangesForDetectorType:NSTextCheckingTypePhoneNumber usingLinkType:KILinkTypePhoneNumber forText:text];
}

- (BOOL)ignoreMatch:(NSString*)string
Expand All @@ -512,12 +545,15 @@ - (NSAttributedString *)addLinkAttributesToAttributedString:(NSAttributedString
KILinkType linkType = [dictionary[KILabelLinkTypeKey] unsignedIntegerValue];

NSDictionary *attributes = [self attributesForLinkType:linkType];


// Remove any previously set NSLinkAttributeName so our attributes take hold
[attributedString removeAttribute:NSLinkAttributeName range:range];

// Use our tint color to hilight the link
[attributedString addAttributes:attributes range:range];

// Add an URL attribute if this is a URL
if (_systemURLStyle && ((KILinkType)[dictionary[KILabelLinkTypeKey] unsignedIntegerValue] == KILinkTypeURL))
// Add an URL attribute if this is a URL or phone number
if (_systemURLStyle && (linkType == KILinkTypeURL || linkType == KILinkTypePhoneNumber))
{
// Add a link attribute using the stored link
[attributedString addAttribute:NSLinkAttributeName value:dictionary[KILabelLinkKey] range:range];
Expand Down Expand Up @@ -721,6 +757,13 @@ - (void)receivedActionForLinkType:(KILinkType)linkType string:(NSString*)string
_urlLinkTapHandler(self, string, range);
}
break;

case KILinkTypePhoneNumber:
if (_phoneNumberLinkTapHandler)
{
_phoneNumberLinkTapHandler(self, string, range);
}
break;
}
}

Expand Down
37 changes: 34 additions & 3 deletions KILabelDemo/KILabelDemo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@
isa = PBXProject;
attributes = {
CLASSPREFIX = KI;
LastUpgradeCheck = 0510;
LastUpgradeCheck = 1010;
ORGANIZATIONNAME = "Matthew Styles";
TargetAttributes = {
C97DB30A183A56F00028EA5C = {
Expand Down Expand Up @@ -340,18 +340,32 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
Expand All @@ -364,7 +378,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
Expand All @@ -378,25 +392,38 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
Expand All @@ -410,6 +437,7 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "KILabelDemo/KILabelDemo-Prefix.pch";
INFOPLIST_FILE = "KILabelDemo/KILabelDemo-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "com.compiledcreations.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
Expand All @@ -423,6 +451,7 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "KILabelDemo/KILabelDemo-Prefix.pch";
INFOPLIST_FILE = "KILabelDemo/KILabelDemo-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "com.compiledcreations.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
Expand All @@ -444,6 +473,7 @@
"$(inherited)",
);
INFOPLIST_FILE = "KILabelDemoTests/KILabelDemoTests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "MatthewStyles.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUNDLE_LOADER)";
WRAPPER_EXTENSION = xctest;
Expand All @@ -462,6 +492,7 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "KILabelDemo/KILabelDemo-Prefix.pch";
INFOPLIST_FILE = "KILabelDemoTests/KILabelDemoTests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "MatthewStyles.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUNDLE_LOADER)";
WRAPPER_EXTENSION = xctest;
Expand Down
Loading