From bafbeadf4b219a133b772b710bd12102bd2f51d2 Mon Sep 17 00:00:00 2001 From: Ruslana Kotova Date: Fri, 22 Mar 2019 22:46:29 +0500 Subject: [PATCH 01/10] Issue #312: Fixed intrinsicContentSize size calculation --- ActiveLabel/ActiveLabel.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ActiveLabel/ActiveLabel.swift b/ActiveLabel/ActiveLabel.swift index b064cb52..c3a49685 100644 --- a/ActiveLabel/ActiveLabel.swift +++ b/ActiveLabel/ActiveLabel.swift @@ -181,8 +181,7 @@ typealias ElementTuple = (range: NSRange, element: ActiveElement, type: ActiveTy // MARK: - Auto layout open override var intrinsicContentSize: CGSize { - let superSize = super.intrinsicContentSize - textContainer.size = CGSize(width: superSize.width, height: CGFloat.greatestFiniteMagnitude) + textContainer.size = CGSize(width: self.preferredMaxLayoutWidth, height: CGFloat.greatestFiniteMagnitude) let size = layoutManager.usedRect(for: textContainer) return CGSize(width: ceil(size.width), height: ceil(size.height)) } From 69e25cb31d09c753a2d2f1300efb1011cd2ac97b Mon Sep 17 00:00:00 2001 From: "mehul.modi" Date: Tue, 11 Feb 2020 19:32:17 +0530 Subject: [PATCH 02/10] added email support --- ActiveLabel/ActiveBuilder.swift | 2 ++ ActiveLabel/ActiveLabel.swift | 19 +++++++++++++++++++ ActiveLabel/ActiveType.swift | 6 ++++++ ActiveLabel/RegexParser.swift | 1 + 4 files changed, 28 insertions(+) diff --git a/ActiveLabel/ActiveBuilder.swift b/ActiveLabel/ActiveBuilder.swift index 40971c8f..ed4916d6 100644 --- a/ActiveLabel/ActiveBuilder.swift +++ b/ActiveLabel/ActiveBuilder.swift @@ -20,6 +20,8 @@ struct ActiveBuilder { return createElements(from: text, for: type, range: range, filterPredicate: filterPredicate) case .custom: return createElements(from: text, for: type, range: range, minLength: 1, filterPredicate: filterPredicate) + case .email: + return createElements(from: text, for: type, range: range, filterPredicate: filterPredicate) } } diff --git a/ActiveLabel/ActiveLabel.swift b/ActiveLabel/ActiveLabel.swift index 01861adf..4607c726 100644 --- a/ActiveLabel/ActiveLabel.swift +++ b/ActiveLabel/ActiveLabel.swift @@ -87,6 +87,10 @@ typealias ElementTuple = (range: NSRange, element: ActiveElement, type: ActiveTy customTapHandlers[type] = handler } + open func handleEmailTap(_ handler: @escaping (String) -> ()) { + emailTapHandler = handler + } + open func removeHandle(for type: ActiveType) { switch type { case .hashtag: @@ -97,6 +101,8 @@ typealias ElementTuple = (range: NSRange, element: ActiveElement, type: ActiveTy urlTapHandler = nil case .custom: customTapHandlers[type] = nil + case .email: + emailTapHandler = nil } } @@ -213,6 +219,7 @@ typealias ElementTuple = (range: NSRange, element: ActiveElement, type: ActiveTy case .hashtag(let hashtag): didTapHashtag(hashtag) case .url(let originalURL, _): didTapStringURL(originalURL) case .custom(let element): didTap(element, for: selectedElement.type) + case .email(let element): didTapStringEmail(element) } let when = DispatchTime.now() + Double(Int64(0.25 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) @@ -240,6 +247,7 @@ typealias ElementTuple = (range: NSRange, element: ActiveElement, type: ActiveTy internal var mentionTapHandler: ((String) -> ())? internal var hashtagTapHandler: ((String) -> ())? internal var urlTapHandler: ((URL) -> ())? + internal var emailTapHandler: ((String) -> ())? internal var customTapHandlers: [ActiveType : ((String) -> ())] = [:] fileprivate var mentionFilterPredicate: ((String) -> Bool)? @@ -321,6 +329,7 @@ typealias ElementTuple = (range: NSRange, element: ActiveElement, type: ActiveTy case .hashtag: attributes[NSAttributedString.Key.foregroundColor] = hashtagColor case .url: attributes[NSAttributedString.Key.foregroundColor] = URLColor case .custom: attributes[NSAttributedString.Key.foregroundColor] = customColor[type] ?? defaultCustomColor + case .email: attributes[NSAttributedString.Key.foregroundColor] = URLColor } if let highlightFont = hightlightFont { @@ -403,6 +412,7 @@ typealias ElementTuple = (range: NSRange, element: ActiveElement, type: ActiveTy case .custom: let possibleSelectedColor = customSelectedColor[selectedElement.type] ?? customColor[selectedElement.type] selectedColor = possibleSelectedColor ?? defaultCustomColor + case .email: selectedColor = URLSelectedColor ?? URLColor } attributes[NSAttributedString.Key.foregroundColor] = selectedColor } else { @@ -412,6 +422,7 @@ typealias ElementTuple = (range: NSRange, element: ActiveElement, type: ActiveTy case .hashtag: unselectedColor = hashtagColor case .url: unselectedColor = URLColor case .custom: unselectedColor = customColor[selectedElement.type] ?? defaultCustomColor + case .email: unselectedColor = URLColor } attributes[NSAttributedString.Key.foregroundColor] = unselectedColor } @@ -503,6 +514,14 @@ typealias ElementTuple = (range: NSRange, element: ActiveElement, type: ActiveTy urlHandler(url) } + fileprivate func didTapStringEmail(_ stringEmail: String) { + guard let emailHandler = emailTapHandler else { + delegate?.didSelect(stringEmail, type: .email) + return + } + emailHandler(stringEmail) + } + fileprivate func didTap(_ element: String, for type: ActiveType) { guard let elementHandler = customTapHandlers[type] else { delegate?.didSelect(element, type: type) diff --git a/ActiveLabel/ActiveType.swift b/ActiveLabel/ActiveType.swift index dc329544..55ee66fc 100644 --- a/ActiveLabel/ActiveType.swift +++ b/ActiveLabel/ActiveType.swift @@ -11,6 +11,7 @@ import Foundation enum ActiveElement { case mention(String) case hashtag(String) + case email(String) case url(original: String, trimmed: String) case custom(String) @@ -18,6 +19,7 @@ enum ActiveElement { switch activeType { case .mention: return mention(text) case .hashtag: return hashtag(text) + case .email: return email(text) case .url: return url(original: text, trimmed: text) case .custom: return custom(text) } @@ -28,6 +30,7 @@ public enum ActiveType { case mention case hashtag case url + case email case custom(pattern: String) var pattern: String { @@ -35,6 +38,7 @@ public enum ActiveType { case .mention: return RegexParser.mentionPattern case .hashtag: return RegexParser.hashtagPattern case .url: return RegexParser.urlPattern + case .email: return RegexParser.emailPattern case .custom(let regex): return regex } } @@ -46,6 +50,7 @@ extension ActiveType: Hashable, Equatable { case .mention: hasher.combine(-1) case .hashtag: hasher.combine(-2) case .url: hasher.combine(-3) + case .email: hasher.combine(-4) case .custom(let regex): hasher.combine(regex) } } @@ -56,6 +61,7 @@ public func ==(lhs: ActiveType, rhs: ActiveType) -> Bool { case (.mention, .mention): return true case (.hashtag, .hashtag): return true case (.url, .url): return true + case (.email, .email): return true case (.custom(let pattern1), .custom(let pattern2)): return pattern1 == pattern2 default: return false } diff --git a/ActiveLabel/RegexParser.swift b/ActiveLabel/RegexParser.swift index b0ad4a4b..fe9bd7ab 100644 --- a/ActiveLabel/RegexParser.swift +++ b/ActiveLabel/RegexParser.swift @@ -12,6 +12,7 @@ struct RegexParser { static let hashtagPattern = "(?:^|\\s|$)#[\\p{L}0-9_]*" static let mentionPattern = "(?:^|\\s|$|[.])@[\\p{L}0-9_]*" + static let emailPattern = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}" static let urlPattern = "(^|[\\s.:;?\\-\\]<\\(])" + "((https?://|www\\.|pic\\.)[-\\w;/?:@&=+$\\|\\_.!~*\\|'()\\[\\]%#,☺]+[\\w/#](\\(\\))?)" + "(?=$|[\\s',\\|\\(\\).:;?\\-\\[\\]>\\)])" From 2e3680c42aa981d87be71f50eb73da85e4aa9df0 Mon Sep 17 00:00:00 2001 From: "mehul.modi" Date: Tue, 11 Feb 2020 19:39:54 +0530 Subject: [PATCH 03/10] added email type to test cases --- ActiveLabelTests/ActiveTypeTests.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ActiveLabelTests/ActiveTypeTests.swift b/ActiveLabelTests/ActiveTypeTests.swift index d18ce7ac..55f1da8b 100644 --- a/ActiveLabelTests/ActiveTypeTests.swift +++ b/ActiveLabelTests/ActiveTypeTests.swift @@ -37,6 +37,7 @@ class ActiveTypeTests: XCTestCase { case .hashtag(let hashtag): return hashtag case .url(let url, _): return url case .custom(let element): return element + case .email(let element): return element } } @@ -47,6 +48,7 @@ class ActiveTypeTests: XCTestCase { case .hashtag: return .hashtag case .url: return .url case .custom: return customEmptyType + case .email: return .email } } From 6d1f638fafba6a40525a85061c1c85a41225b376 Mon Sep 17 00:00:00 2001 From: mehulmodihb <33020448+mehulmodihb@users.noreply.github.com> Date: Tue, 11 Feb 2020 20:00:55 +0530 Subject: [PATCH 04/10] Update README.md --- README.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 56f8c4ab..d76503a6 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # ActiveLabel.swift [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Build Status](https://travis-ci.org/optonaut/ActiveLabel.swift.svg)](https://travis-ci.org/optonaut/ActiveLabel.swift) -UILabel drop-in replacement supporting Hashtags (#), Mentions (@), URLs (http://) and custom regex patterns, written in Swift +UILabel drop-in replacement supporting Hashtags (#), Mentions (@), URLs (http://), Emails and custom regex patterns, written in Swift ## Features * Swift 5.0 (1.1.0) and 4.2 (1.0.1) -* Default support for **Hashtags, Mentions, Links** +* Default support for **Hashtags, Mentions, Links, Emails** * Support for **custom types** via regex * Ability to enable highlighting only for the desired types * Ability to trim urls @@ -44,7 +44,7 @@ import ActiveLabel let label = ActiveLabel() label.numberOfLines = 0 -label.enabledTypes = [.mention, .hashtag, .url] +label.enabledTypes = [.mention, .hashtag, .url, .email] label.text = "This is a post with #hashtags and a @userhandle." label.textColor = .black label.handleHashtagTap { hashtag in @@ -56,7 +56,7 @@ label.handleHashtagTap { hashtag in ```swift let customType = ActiveType.custom(pattern: "\\swith\\b") //Regex that looks for "with" -label.enabledTypes = [.mention, .hashtag, .url, customType] +label.enabledTypes = [.mention, .hashtag, .url, .email, customType] label.text = "This is a post with #hashtags and a @userhandle." label.customColor[customType] = UIColor.purple label.customSelectedColor[customType] = UIColor.green @@ -71,7 +71,7 @@ label.handleCustomTap(for: customType) { element in By default, an ActiveLabel instance has the following configuration ```swift -label.enabledTypes = [.mention, .hashtag, .url] +label.enabledTypes = [.mention, .hashtag, .url, .email] ``` But feel free to enable/disable to fit your requirements @@ -140,6 +140,12 @@ label.handleHashtagTap { hashtag in print("\(hashtag) tapped") } label.handleURLTap { url in UIApplication.shared.openURL(url) } ``` +##### `handleEmailTap: (String) -> ()` + +```swift +label.handleEmailTap { email in print("\(email) tapped") } +``` + ##### `handleCustomTap(for type: ActiveType, handler: (String) -> ())` ```swift From 6bbe600577857be3e331d48618c820640f5c6123 Mon Sep 17 00:00:00 2001 From: casperson Date: Thu, 26 Mar 2020 15:30:37 -0700 Subject: [PATCH 05/10] Added in missing cases for new UITouchPhases, iOS 13.4 --- .travis.yml | 2 +- ActiveLabel/ActiveLabel.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index eff32e98..5fe3d2c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: xcode10.2 +osx_image: xcode11.4 before_install: - gem install bundler - gem update bundler diff --git a/ActiveLabel/ActiveLabel.swift b/ActiveLabel/ActiveLabel.swift index 01861adf..d3e10629 100644 --- a/ActiveLabel/ActiveLabel.swift +++ b/ActiveLabel/ActiveLabel.swift @@ -193,7 +193,7 @@ typealias ElementTuple = (range: NSRange, element: ActiveElement, type: ActiveTy var avoidSuperCall = false switch touch.phase { - case .began, .moved: + case .began, .moved, .regionEntered, .regionMoved: if let element = element(at: location) { if element.range.location != selectedElement?.range.location || element.range.length != selectedElement?.range.length { updateAttributesWhenSelected(false) @@ -205,7 +205,7 @@ typealias ElementTuple = (range: NSRange, element: ActiveElement, type: ActiveTy updateAttributesWhenSelected(false) selectedElement = nil } - case .ended: + case .ended, .regionExited: guard let selectedElement = selectedElement else { return avoidSuperCall } switch selectedElement.element { From 4cdd88f1a300a0f6a33236bfe206bd6c851b57b7 Mon Sep 17 00:00:00 2001 From: Filipe Alvarenga Date: Sun, 28 Jun 2020 20:02:51 -0300 Subject: [PATCH 06/10] Adjust height to zero when there's no text set --- ActiveLabel/ActiveLabel.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ActiveLabel/ActiveLabel.swift b/ActiveLabel/ActiveLabel.swift index 01861adf..25f2bd00 100644 --- a/ActiveLabel/ActiveLabel.swift +++ b/ActiveLabel/ActiveLabel.swift @@ -181,6 +181,10 @@ typealias ElementTuple = (range: NSRange, element: ActiveElement, type: ActiveTy // MARK: - Auto layout open override var intrinsicContentSize: CGSize { + guard let text = text, !text.isEmpty else { + return .zero + } + let superSize = super.intrinsicContentSize textContainer.size = CGSize(width: superSize.width, height: CGFloat.greatestFiniteMagnitude) let size = layoutManager.usedRect(for: textContainer) From 85136b17ef48575c086b333eeb6d36d53e81042e Mon Sep 17 00:00:00 2001 From: Maziyar Panahi Date: Sun, 15 Nov 2020 17:08:16 +0100 Subject: [PATCH 07/10] [skip travis] Update travis to Xcode 12.2 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5fe3d2c6..3dccd3ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: xcode11.4 +osx_image: xcode12.2 before_install: - gem install bundler - gem update bundler From b3bfb455e3ab032d0edb42bb85bfb8c3ae329a40 Mon Sep 17 00:00:00 2001 From: Maziyar Panahi Date: Sun, 15 Nov 2020 17:08:29 +0100 Subject: [PATCH 08/10] Bump version to 1.1.5 --- ActiveLabel.podspec | 2 +- ActiveLabel.xcodeproj/project.pbxproj | 2 ++ ActiveLabel/Info.plist | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ActiveLabel.podspec b/ActiveLabel.podspec index 753e6a71..53a60f36 100644 --- a/ActiveLabel.podspec +++ b/ActiveLabel.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'ActiveLabel' - s.version = '1.1.0' + s.version = '1.1.5' s.author = { 'Optonaut' => 'hello@optonaut.co' } s.homepage = 'https://github.com/optonaut/ActiveLabel.swift' diff --git a/ActiveLabel.xcodeproj/project.pbxproj b/ActiveLabel.xcodeproj/project.pbxproj index 7c722bd8..311e4a1c 100644 --- a/ActiveLabel.xcodeproj/project.pbxproj +++ b/ActiveLabel.xcodeproj/project.pbxproj @@ -492,6 +492,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MARKETING_VERSION = 1.1.5; PRODUCT_BUNDLE_IDENTIFIER = optonaut.ActiveLabel; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -513,6 +514,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MARKETING_VERSION = 1.1.5; PRODUCT_BUNDLE_IDENTIFIER = optonaut.ActiveLabel; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; diff --git a/ActiveLabel/Info.plist b/ActiveLabel/Info.plist index a6f720ec..ca23c84f 100644 --- a/ActiveLabel/Info.plist +++ b/ActiveLabel/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.1 + $(MARKETING_VERSION) CFBundleSignature ???? CFBundleVersion From 726af7f08aa01c9e0b60096a33ff536b79a1ab4f Mon Sep 17 00:00:00 2001 From: Maziyar Panahi Date: Sun, 15 Nov 2020 17:10:42 +0100 Subject: [PATCH 09/10] Update README.md --- README.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d76503a6..3d9795f3 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ UILabel drop-in replacement supporting Hashtags (#), Mentions (@), URLs (http:// ## Features -* Swift 5.0 (1.1.0) and 4.2 (1.0.1) +* Swift 5.0 (1.1.0+) and 4.2 (1.0.1) * Default support for **Hashtags, Mentions, Links, Emails** * Support for **custom types** via regex * Ability to enable highlighting only for the desired types @@ -15,14 +15,13 @@ UILabel drop-in replacement supporting Hashtags (#), Mentions (@), URLs (http:// ![](ActiveLabelDemo/demo.gif) - ## Install (iOS 10+) ### Carthage Add the following to your `Cartfile` and follow [these instructions](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application) -``` +```sh github "optonaut/ActiveLabel.swift" ``` @@ -60,9 +59,8 @@ label.enabledTypes = [.mention, .hashtag, .url, .email, customType] label.text = "This is a post with #hashtags and a @userhandle." label.customColor[customType] = UIColor.purple label.customSelectedColor[customType] = UIColor.green - -label.handleCustomTap(for: customType) { element in - print("Custom type tapped: \(element)") +label.handleCustomTap(for: customType) { element in + print("Custom type tapped: \(element)") } ``` @@ -76,7 +74,6 @@ label.enabledTypes = [.mention, .hashtag, .url, .email] But feel free to enable/disable to fit your requirements - ## Batched customization When using ActiveLabel, it is recommended to use the `customize(block:)` method to customize it. The reason is that ActiveLabel is reacting to each property that you set. So if you set 3 properties, the textContainer is refreshed 3 times. From c3ad1cf51f7a306099212e448827d96ce3423fc8 Mon Sep 17 00:00:00 2001 From: Maziyar Panahi Date: Sun, 15 Nov 2020 17:15:57 +0100 Subject: [PATCH 10/10] Update ActiveLabel.podspec --- ActiveLabel.podspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ActiveLabel.podspec b/ActiveLabel.podspec index 53a60f36..56b7226a 100644 --- a/ActiveLabel.podspec +++ b/ActiveLabel.podspec @@ -12,8 +12,8 @@ Pod::Spec.new do |s| UILabel drop-in replacement supporting Hashtags (#), Mentions (@), URLs (http://) and custom regex patterns, written in Swift Features - * Up-to-date: Swift 5.0 and Xcode 10.2 - * Default support for Hashtags, Mentions, Links + * Swift 5.0 (1.1.0+) and 4.2 (1.0.1) + * Default support for **Hashtags, Mentions, Links, Emails** * Support for custom types via regex * Ability to enable highlighting only for the desired types * Ability to trim urls