From 56e89b18886f33753872e4cd47f5d5ef5b340b3c Mon Sep 17 00:00:00 2001 From: Nik Kov Date: Fri, 27 Jul 2018 16:43:47 +0300 Subject: [PATCH 1/3] Updated to Swift4 --- ActionLabel/ActionLabel.swift | 161 +++++++++++++++++----------------- 1 file changed, 79 insertions(+), 82 deletions(-) diff --git a/ActionLabel/ActionLabel.swift b/ActionLabel/ActionLabel.swift index cc74236..73a10c1 100644 --- a/ActionLabel/ActionLabel.swift +++ b/ActionLabel/ActionLabel.swift @@ -22,7 +22,7 @@ public enum ActionType { case None } -typealias ActionFilterPredicate = (String -> Bool) +typealias ActionFilterPredicate = ((String) -> Bool) struct ActionParser { @@ -40,31 +40,31 @@ struct ActionParser { switch type { case .Hashtag: - regex = try? NSRegularExpression(pattern: hashtagPattern, options: [.CaseInsensitive]) + regex = try? NSRegularExpression(pattern: hashtagPattern, options: [.caseInsensitive]) case .Mention: - regex = try? NSRegularExpression(pattern: mentionPattern, options: [.CaseInsensitive]) + regex = try? NSRegularExpression(pattern: mentionPattern, options: [.caseInsensitive]) case .URL: - regex = try? NSRegularExpression(pattern: linkPattern, options: [.CaseInsensitive]) + regex = try? NSRegularExpression(pattern: linkPattern, options: [.caseInsensitive]) case .None: break } guard let validRegex = regex else { return [] } - return validRegex.matchesInString(text, options: [], range: range) + return validRegex.matches(in: text, options: [], range: range) } } struct ActionBuilder { static func getElementsByType(type: ActionType, fromText text: String, range: NSRange, filterPredicate: ActionFilterPredicate? = nil) -> [(range: NSRange, element: ActionElement)] { - let parsedElements = ActionParser.getElementsByType(type, fromText: text, range: range) + let parsedElements = ActionParser.getElementsByType(type: type, fromText: text, range: range) let nsstring = text as NSString var elements: [(range: NSRange, element: ActionElement)] = [] for element in parsedElements where element.range.length > 2 { let range = NSRange(location: element.range.location + 1, length: element.range.length - 1) - var word = nsstring.substringWithRange(range) + var word = nsstring.substring(with: range) if word.hasPrefix("@") || word.hasPrefix("#") { - word.removeAtIndex(word.startIndex) + word.remove(at: word.startIndex) } var newElement: ActionElement? @@ -79,10 +79,9 @@ struct ActionBuilder { newElement = ActionElement.Mention(word) } case .URL: - let word = nsstring.substringWithRange(element.range) - .stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) + let word = nsstring.substring(with: element.range).trimmingCharacters(in: .whitespacesAndNewlines) newElement = ActionElement.URL(word) - + case .None: break } @@ -104,19 +103,19 @@ public protocol ActionLabelDelegate: class { // MARK: properties public weak var delegate: ActionLabelDelegate? - @IBInspectable public var mentionColor: UIColor = .blueColor() { + @IBInspectable public var mentionColor: UIColor = .blue { didSet { updateLabel(parseText: false) } } @IBInspectable public var mentionSelectedColor: UIColor? { didSet { updateLabel(parseText: false) } } - @IBInspectable public var hashtagColor: UIColor = .blueColor() { + @IBInspectable public var hashtagColor: UIColor = .blue { didSet { updateLabel(parseText: false) } } @IBInspectable public var hashtagSelectedColor: UIColor? { didSet { updateLabel(parseText: false) } } - @IBInspectable public var URLColor: UIColor = .blueColor() { + @IBInspectable public var URLColor: UIColor = .blue { didSet { updateLabel(parseText: false) } } @IBInspectable public var URLSelectedColor: UIColor? { @@ -127,24 +126,24 @@ public protocol ActionLabelDelegate: class { } // MARK: methods - public func mentionHandler(handler: (String) -> ()) { + public func mentionHandler(handler: @escaping (String) -> ()) { mentionHandler = handler } - public func hashtaghandler(handler: (String) -> ()) { + public func hashtaghandler(handler: @escaping (String) -> ()) { hashtagHandler = handler } - public func linkHandler(handler: (NSURL) -> ()) { + public func linkHandler(handler: @escaping (NSURL) -> ()) { linkHandler = handler } - public func filterMention(predicate: (String) -> Bool) { + public func filterMention(predicate: @escaping (String) -> Bool) { mentionFilterPredicate = predicate updateLabel() } - public func filterHashtag(predicate: (String) -> Bool) { + public func filterHashtag(predicate: @escaping (String) -> Bool) { hashtagFilterPredicate = predicate updateLabel() } @@ -196,72 +195,71 @@ public protocol ActionLabelDelegate: class { updateLabel() } - public override func drawTextInRect(rect: CGRect) { + public override func drawText(in rect: CGRect) { let range = NSRange(location: 0, length: textStorage.length) textContainer.size = rect.size let newOrigin = textOrigin(inRect: rect) - layoutManager.drawBackgroundForGlyphRange(range, atPoint: newOrigin) - layoutManager.drawGlyphsForGlyphRange(range, atPoint: newOrigin) + layoutManager.drawBackground(forGlyphRange: range, at: newOrigin) + layoutManager.drawGlyphs(forGlyphRange: range, at: newOrigin) } // MARK: - customization - public func customize(block: (label: ActionLabel) -> ()) -> ActionLabel{ + public func customize(block: (_ label: ActionLabel) -> ()) -> ActionLabel { _customizing = true - block(label: self) + block(self) _customizing = false updateLabel() return self } // MARK: - Auto layout - public override func intrinsicContentSize() -> CGSize { - let superSize = super.intrinsicContentSize() - textContainer.size = CGSize(width: superSize.width, height: CGFloat.max) - let size = layoutManager.usedRectForTextContainer(textContainer) + public override var intrinsicContentSize: CGSize { + let superSize = super.intrinsicContentSize + textContainer.size = CGSize(width: superSize.width, height: CGFloat.greatestFiniteMagnitude) + let size = layoutManager.usedRect(for: textContainer) return CGSize(width: size.width, height: ceil(size.height)) } // MARK: - touch events func onTouch(touch: UITouch) -> Bool { - let location = touch.locationInView(self) + let location = touch.location(in: self) var avoidSuperCall = false switch touch.phase { - case .Began, .Moved: - if let element = elementAtLocation(location) { + case .began, .moved: + if let element = elementAtLocation(location: location) { if element.range.location != selectedElement?.range.location || element.range.length != selectedElement?.range.length { - updateAttributesWhenSelected(false) + updateAttributesWhenSelected(isSelected: false) selectedElement = element - updateAttributesWhenSelected(true) + updateAttributesWhenSelected(isSelected: true) } avoidSuperCall = true } else { - updateAttributesWhenSelected(false) + updateAttributesWhenSelected(isSelected: false) selectedElement = nil } - case .Ended: + case .ended: guard let selectedElement = selectedElement else { return avoidSuperCall } switch selectedElement.element { - case .Mention(let userHandle): didTapMention(userHandle) - case .Hashtag(let hashtag): didTapHashtag(hashtag) - case .URL(let url): didTapStringURL(url) + case .Mention(let userHandle): didTapMention(username: userHandle) + case .Hashtag(let hashtag): didTapHashtag(hashtag: hashtag) + case .URL(let url): didTapStringURL(stringURL: url) case .None: () } - let when = dispatch_time(DISPATCH_TIME_NOW, Int64(0.25 * Double(NSEC_PER_SEC))) - dispatch_after(when, dispatch_get_main_queue()) { - self.updateAttributesWhenSelected(false) + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.25) { + self.updateAttributesWhenSelected(isSelected: false) self.selectedElement = nil } avoidSuperCall = true - case .Cancelled: - updateAttributesWhenSelected(false) + case .cancelled: + updateAttributesWhenSelected(isSelected: false) selectedElement = nil - case .Stationary: + default: break } @@ -287,7 +285,7 @@ public protocol ActionLabelDelegate: class { .Mention: [], .Hashtag: [], .URL: [], - ] + ] // MARK: - helper functions private func setupLabel() { @@ -296,27 +294,27 @@ public protocol ActionLabelDelegate: class { textContainer.lineFragmentPadding = 0 textContainer.lineBreakMode = lineBreakMode textContainer.maximumNumberOfLines = numberOfLines - userInteractionEnabled = true + isUserInteractionEnabled = true } - private func updateLabel(parseText parseText: Bool = true) { + private func updateLabel(parseText: Bool = true) { if _customizing { return } // clean up previous Action elements - guard let attributedText = attributedText where attributedText.length > 0 else { + guard let attributedText = attributedText, attributedText.length > 0 else { clearActionElements() textStorage.setAttributedString(NSAttributedString()) setNeedsDisplay() return } - let mutAttrString = addLineBreak(attributedText) + let mutAttrString = addLineBreak(attrString: attributedText) if parseText { clearActionElements() - parseTextAndExtractActionElements(mutAttrString) + parseTextAndExtractActionElements(attrString: mutAttrString) } - self.addLinkAttribute(mutAttrString) + self.addLinkAttribute(mutAttrString: mutAttrString) self.textStorage.setAttributedString(mutAttrString) self.setNeedsDisplay() } @@ -329,7 +327,7 @@ public protocol ActionLabelDelegate: class { } private func textOrigin(inRect rect: CGRect) -> CGPoint { - let usedRect = layoutManager.usedRectForTextContainer(textContainer) + let usedRect = layoutManager.usedRect(for: textContainer) heightCorrection = (rect.height - usedRect.height)/2 let glyphOriginY = heightCorrection > 0 ? rect.origin.y + heightCorrection : rect.origin.y return CGPoint(x: rect.origin.x, y: glyphOriginY) @@ -338,7 +336,7 @@ public protocol ActionLabelDelegate: class { /// add link attribute private func addLinkAttribute(mutAttrString: NSMutableAttributedString) { var range = NSRange(location: 0, length: 0) - var attributes = mutAttrString.attributesAtIndex(0, effectiveRange: &range) + var attributes = mutAttrString.attributes(at: 0, effectiveRange: &range) attributes[NSFontAttributeName] = font! attributes[NSForegroundColorAttributeName] = textColor @@ -368,16 +366,16 @@ public protocol ActionLabelDelegate: class { let textRange = NSRange(location: 0, length: textLength) //URLS - let urlElements = ActionBuilder.getElementsByType(.URL, fromText: textString, range: textRange) - ActionElements[.URL]?.appendContentsOf(urlElements) + let urlElements = ActionBuilder.getElementsByType(type: .URL, fromText: textString, range: textRange) + ActionElements[.URL]?.append(contentsOf: urlElements) //HASHTAGS - let hashtagElements = ActionBuilder.getElementsByType(.Hashtag, fromText: textString, range: textRange, filterPredicate: hashtagFilterPredicate) - ActionElements[.Hashtag]?.appendContentsOf(hashtagElements) + let hashtagElements = ActionBuilder.getElementsByType(type: .Hashtag, fromText: textString, range: textRange, filterPredicate: hashtagFilterPredicate) + ActionElements[.Hashtag]?.append(contentsOf: hashtagElements) //MENTIONS - let mentionElements = ActionBuilder.getElementsByType(.Mention, fromText: textString, range: textRange, filterPredicate: mentionFilterPredicate) - ActionElements[.Mention]?.appendContentsOf(mentionElements) + let mentionElements = ActionBuilder.getElementsByType(type: .Mention, fromText: textString, range: textRange, filterPredicate: mentionFilterPredicate) + ActionElements[.Mention]?.append(contentsOf: mentionElements) } @@ -386,10 +384,10 @@ public protocol ActionLabelDelegate: class { let mutAttrString = NSMutableAttributedString(attributedString: attrString) var range = NSRange(location: 0, length: 0) - var attributes = mutAttrString.attributesAtIndex(0, effectiveRange: &range) + var attributes = mutAttrString.attributes(at: 0, effectiveRange: &range) let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? NSMutableParagraphStyle ?? NSMutableParagraphStyle() - paragraphStyle.lineBreakMode = NSLineBreakMode.ByWordWrapping + paragraphStyle.lineBreakMode = NSLineBreakMode.byWordWrapping paragraphStyle.alignment = textAlignment paragraphStyle.lineSpacing = CGFloat(lineSpacing) @@ -404,7 +402,7 @@ public protocol ActionLabelDelegate: class { return } - var attributes = textStorage.attributesAtIndex(0, effectiveRange: nil) + var attributes = textStorage.attributes(at: 0, effectiveRange: nil) if isSelected { switch selectedElement.element { case .Mention(_): attributes[NSForegroundColorAttributeName] = mentionSelectedColor ?? mentionColor @@ -433,14 +431,14 @@ public protocol ActionLabelDelegate: class { var correctLocation = location correctLocation.y -= heightCorrection - let boundingRect = layoutManager.boundingRectForGlyphRange(NSRange(location: 0, length: textStorage.length), inTextContainer: textContainer) + let boundingRect = layoutManager.boundingRect(forGlyphRange: NSRange(location: 0, length: textStorage.length), in: textContainer) guard boundingRect.contains(correctLocation) else { return nil } - let index = layoutManager.glyphIndexForPoint(correctLocation, inTextContainer: textContainer) + let index = layoutManager.glyphIndex(for: correctLocation, in: textContainer) - for element in ActionElements.map({ $0.1 }).flatten() { + for element in ActionElements.flatMap({ $0.1 }) { if index >= element.range.location && index <= element.range.location + element.range.length { return element } @@ -451,34 +449,34 @@ public protocol ActionLabelDelegate: class { //MARK: - Handle UI Responder touches - public override func touchesBegan(touches: Set, withEvent event: UIEvent?) { + public override func touchesBegan(_ touches: Set, with event: UIEvent?) { guard let touch = touches.first else { return } - if onTouch(touch) { return } - super.touchesBegan(touches, withEvent: event) + if onTouch(touch: touch) { return } + super.touchesBegan(touches, with: event) } - public override func touchesMoved(touches: Set, withEvent event: UIEvent?) { + public override func touchesMoved(_ touches: Set, with event: UIEvent?) { guard let touch = touches.first else { return } - if onTouch(touch) { return } - super.touchesMoved(touches, withEvent: event) + if onTouch(touch: touch) { return } + super.touchesMoved(touches, with: event) } - public override func touchesCancelled(touches: Set?, withEvent event: UIEvent?) { - guard let touch = touches?.first else { return } - onTouch(touch) - super.touchesCancelled(touches, withEvent: event) + public override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + guard let touch = touches.first else { return } + onTouch(touch: touch) + super.touchesCancelled(touches, with: event) } - public override func touchesEnded(touches: Set, withEvent event: UIEvent?) { + public override func touchesEnded(_ touches: Set, with event: UIEvent?) { guard let touch = touches.first else { return } - if onTouch(touch) { return } - super.touchesEnded(touches, withEvent: event) + if onTouch(touch: touch) { return } + super.touchesEnded(touches, with: event) } //MARK: - ActionLabel handler private func didTapMention(username: String) { guard let mentionHandler = mentionHandler else { - delegate?.didSelectText(username, type: .Mention) + delegate?.didSelectText(text: username, type: .Mention) return } mentionHandler(username) @@ -486,7 +484,7 @@ public protocol ActionLabelDelegate: class { private func didTapHashtag(hashtag: String) { guard let hashtagHandler = hashtagHandler else { - delegate?.didSelectText(hashtag, type: .Hashtag) + delegate?.didSelectText(text: hashtag, type: .Hashtag) return } hashtagHandler(hashtag) @@ -494,7 +492,7 @@ public protocol ActionLabelDelegate: class { private func didTapStringURL(stringURL: String) { guard let urlHandler = linkHandler, let url = NSURL(string: stringURL) else { - delegate?.didSelectText(stringURL, type: .URL) + delegate?.didSelectText(text: stringURL, type: .URL) return } urlHandler(url) @@ -515,4 +513,3 @@ extension ActionLabel: UIGestureRecognizerDelegate { return true } } - From d040a3d2761a7ad4a0b05e2bc06b7e22b3ced2d6 Mon Sep 17 00:00:00 2001 From: Nik Kov Date: Fri, 27 Jul 2018 17:35:44 +0300 Subject: [PATCH 2/3] Fixes. Changes class and enum names. --- ActionLabel/ActionLabel.swift | 166 ++++++++++++++++++---------------- 1 file changed, 88 insertions(+), 78 deletions(-) diff --git a/ActionLabel/ActionLabel.swift b/ActionLabel/ActionLabel.swift index 73a10c1..e74aaeb 100644 --- a/ActionLabel/ActionLabel.swift +++ b/ActionLabel/ActionLabel.swift @@ -3,28 +3,29 @@ // ActionLabel // // Created by Carlos Alcala on 5/25/16. +// Updated by Nik Kov Ios on 07/2018. // Copyright © 2016 Carlos Alcala. All rights reserved. // import Foundation -enum ActionElement { - case Mention(String) - case Hashtag(String) - case URL(String) - case None +enum ALElement { + case mention(String) + case hashtag(String) + case url(String) + case none } -public enum ActionType { - case Mention - case Hashtag - case URL - case None +public enum ALActionType { + case mention + case hashtag + case url + case none } typealias ActionFilterPredicate = ((String) -> Bool) -struct ActionParser { +struct ALParser { static let linkPattern = "(^|[\\s.:;?\\-\\]<\\(])" + "((https?://|www\\.|pic\\.)[-\\w;/?:@&=+$\\|\\_.!~*\\|'()\\[\\]%#,☺]+[\\w/#](\\(\\))?)" + @@ -34,18 +35,18 @@ struct ActionParser { static let mentionPattern = "(?:^|\\s|$|[.])@[\\p{L}0-9_]*" - static func getElementsByType(type: ActionType, fromText text: String, range: NSRange) -> [NSTextCheckingResult] { + static func getElementsByType(type: ALActionType, fromText text: String, range: NSRange) -> [NSTextCheckingResult] { var regex:NSRegularExpression? switch type { - case .Hashtag: + case .hashtag: regex = try? NSRegularExpression(pattern: hashtagPattern, options: [.caseInsensitive]) - case .Mention: + case .mention: regex = try? NSRegularExpression(pattern: mentionPattern, options: [.caseInsensitive]) - case .URL: + case .url: regex = try? NSRegularExpression(pattern: linkPattern, options: [.caseInsensitive]) - case .None: break + case .none: break } guard let validRegex = regex else { return [] } @@ -53,12 +54,12 @@ struct ActionParser { } } -struct ActionBuilder { +struct ALBuilder { - static func getElementsByType(type: ActionType, fromText text: String, range: NSRange, filterPredicate: ActionFilterPredicate? = nil) -> [(range: NSRange, element: ActionElement)] { - let parsedElements = ActionParser.getElementsByType(type: type, fromText: text, range: range) + static func getElementsByType(type: ALActionType, fromText text: String, range: NSRange, filterPredicate: ActionFilterPredicate? = nil) -> [(range: NSRange, element: ALElement)] { + let parsedElements = ALParser.getElementsByType(type: type, fromText: text, range: range) let nsstring = text as NSString - var elements: [(range: NSRange, element: ActionElement)] = [] + var elements: [(range: NSRange, element: ALElement)] = [] for element in parsedElements where element.range.length > 2 { let range = NSRange(location: element.range.location + 1, length: element.range.length - 1) @@ -67,22 +68,22 @@ struct ActionBuilder { word.remove(at: word.startIndex) } - var newElement: ActionElement? + var newElement: ALElement? switch type { - case .Hashtag: + case .hashtag: if filterPredicate?(word) ?? true { - newElement = ActionElement.Hashtag(word) + newElement = ALElement.hashtag(word) } - case .Mention: + case .mention: if filterPredicate?(word) ?? true { - newElement = ActionElement.Mention(word) + newElement = ALElement.mention(word) } - case .URL: + case .url: let word = nsstring.substring(with: element.range).trimmingCharacters(in: .whitespacesAndNewlines) - newElement = ActionElement.URL(word) + newElement = ALElement.url(word) - case .None: break + case .none: break } if let validElement = newElement { @@ -95,7 +96,7 @@ struct ActionBuilder { } public protocol ActionLabelDelegate: class { - func didSelectText(text: String, type: ActionType) + func didSelectText(text: String, type: ALActionType) } @IBDesignable public class ActionLabel: UILabel { @@ -149,6 +150,7 @@ public protocol ActionLabelDelegate: class { } // MARK: - override UILabel properties + override public var text: String? { didSet { updateLabel() } } @@ -177,7 +179,8 @@ public protocol ActionLabelDelegate: class { didSet { textContainer.lineBreakMode = lineBreakMode } } - // MARK: - init functions + // MARK: - Init + override public init(frame: CGRect) { super.init(frame: frame) _customizing = false @@ -216,6 +219,7 @@ public protocol ActionLabelDelegate: class { } // MARK: - Auto layout + public override var intrinsicContentSize: CGSize { let superSize = super.intrinsicContentSize textContainer.size = CGSize(width: superSize.width, height: CGFloat.greatestFiniteMagnitude) @@ -223,7 +227,9 @@ public protocol ActionLabelDelegate: class { return CGSize(width: size.width, height: ceil(size.height)) } - // MARK: - touch events + // MARK: - Touch events + + @discardableResult func onTouch(touch: UITouch) -> Bool { let location = touch.location(in: self) var avoidSuperCall = false @@ -245,10 +251,10 @@ public protocol ActionLabelDelegate: class { guard let selectedElement = selectedElement else { return avoidSuperCall } switch selectedElement.element { - case .Mention(let userHandle): didTapMention(username: userHandle) - case .Hashtag(let hashtag): didTapHashtag(hashtag: hashtag) - case .URL(let url): didTapStringURL(stringURL: url) - case .None: () + case .mention(let userHandle): didTapMention(username: userHandle) + case .hashtag(let hashtag): didTapHashtag(hashtag: hashtag) + case .url(let url): didTapStringURL(stringURL: url) + case .none: () } DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.25) { @@ -266,7 +272,8 @@ public protocol ActionLabelDelegate: class { return avoidSuperCall } - // MARK: - private properties + // MARK: - Private properties + private var _customizing: Bool = true private var mentionHandler: ((String) -> ())? @@ -276,18 +283,19 @@ public protocol ActionLabelDelegate: class { private var mentionFilterPredicate: ((String) -> Bool)? private var hashtagFilterPredicate: ((String) -> Bool)? - private var selectedElement: (range: NSRange, element: ActionElement)? + private var selectedElement: (range: NSRange, element: ALElement)? private var heightCorrection: CGFloat = 0 private lazy var textStorage = NSTextStorage() private lazy var layoutManager = NSLayoutManager() private lazy var textContainer = NSTextContainer() - internal lazy var ActionElements: [ActionType: [(range: NSRange, element: ActionElement)]] = [ - .Mention: [], - .Hashtag: [], - .URL: [], + internal lazy var ActionElements: [ALActionType: [(range: NSRange, element: ALElement)]] = [ + .mention: [], + .hashtag: [], + .url: [], ] - // MARK: - helper functions + // MARK: - Helper functions + private func setupLabel() { textStorage.addLayoutManager(layoutManager) layoutManager.addTextContainer(textContainer) @@ -333,24 +341,24 @@ public protocol ActionLabelDelegate: class { return CGPoint(x: rect.origin.x, y: glyphOriginY) } - /// add link attribute + /// Adds link attribute private func addLinkAttribute(mutAttrString: NSMutableAttributedString) { var range = NSRange(location: 0, length: 0) var attributes = mutAttrString.attributes(at: 0, effectiveRange: &range) - attributes[NSFontAttributeName] = font! - attributes[NSForegroundColorAttributeName] = textColor + attributes[.font] = font! + attributes[.foregroundColor] = textColor mutAttrString.addAttributes(attributes, range: range) - attributes[NSForegroundColorAttributeName] = mentionColor + attributes[.foregroundColor] = mentionColor for (type, elements) in ActionElements { switch type { - case .Mention: attributes[NSForegroundColorAttributeName] = mentionColor - case .Hashtag: attributes[NSForegroundColorAttributeName] = hashtagColor - case .URL: attributes[NSForegroundColorAttributeName] = URLColor - case .None: () + case .mention: attributes[.foregroundColor] = mentionColor + case .hashtag: attributes[.foregroundColor] = hashtagColor + case .url: attributes[.foregroundColor] = URLColor + case .none: () } for element in elements { @@ -366,32 +374,32 @@ public protocol ActionLabelDelegate: class { let textRange = NSRange(location: 0, length: textLength) //URLS - let urlElements = ActionBuilder.getElementsByType(type: .URL, fromText: textString, range: textRange) - ActionElements[.URL]?.append(contentsOf: urlElements) + let urlElements = ALBuilder.getElementsByType(type: .url, fromText: textString, range: textRange) + ActionElements[.url]?.append(contentsOf: urlElements) //HASHTAGS - let hashtagElements = ActionBuilder.getElementsByType(type: .Hashtag, fromText: textString, range: textRange, filterPredicate: hashtagFilterPredicate) - ActionElements[.Hashtag]?.append(contentsOf: hashtagElements) + let hashtagElements = ALBuilder.getElementsByType(type: .hashtag, fromText: textString, range: textRange, filterPredicate: hashtagFilterPredicate) + ActionElements[.hashtag]?.append(contentsOf: hashtagElements) //MENTIONS - let mentionElements = ActionBuilder.getElementsByType(type: .Mention, fromText: textString, range: textRange, filterPredicate: mentionFilterPredicate) - ActionElements[.Mention]?.append(contentsOf: mentionElements) + let mentionElements = ALBuilder.getElementsByType(type: .mention, fromText: textString, range: textRange, filterPredicate: mentionFilterPredicate) + ActionElements[.mention]?.append(contentsOf: mentionElements) } - /// add line break mode + /// Adds line break mode private func addLineBreak(attrString: NSAttributedString) -> NSMutableAttributedString { let mutAttrString = NSMutableAttributedString(attributedString: attrString) var range = NSRange(location: 0, length: 0) var attributes = mutAttrString.attributes(at: 0, effectiveRange: &range) - let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? NSMutableParagraphStyle ?? NSMutableParagraphStyle() + let paragraphStyle = attributes[.paragraphStyle] as? NSMutableParagraphStyle ?? NSMutableParagraphStyle() paragraphStyle.lineBreakMode = NSLineBreakMode.byWordWrapping paragraphStyle.alignment = textAlignment paragraphStyle.lineSpacing = CGFloat(lineSpacing) - attributes[NSParagraphStyleAttributeName] = paragraphStyle + attributes[.paragraphStyle] = paragraphStyle mutAttrString.setAttributes(attributes, range: range) return mutAttrString @@ -405,17 +413,17 @@ public protocol ActionLabelDelegate: class { var attributes = textStorage.attributes(at: 0, effectiveRange: nil) if isSelected { switch selectedElement.element { - case .Mention(_): attributes[NSForegroundColorAttributeName] = mentionSelectedColor ?? mentionColor - case .Hashtag(_): attributes[NSForegroundColorAttributeName] = hashtagSelectedColor ?? hashtagColor - case .URL(_): attributes[NSForegroundColorAttributeName] = URLSelectedColor ?? URLColor - case .None: () + case .mention(_): attributes[.foregroundColor] = mentionSelectedColor ?? mentionColor + case .hashtag(_): attributes[.foregroundColor] = hashtagSelectedColor ?? hashtagColor + case .url(_): attributes[.foregroundColor] = URLSelectedColor ?? URLColor + case .none: () } } else { switch selectedElement.element { - case .Mention(_): attributes[NSForegroundColorAttributeName] = mentionColor - case .Hashtag(_): attributes[NSForegroundColorAttributeName] = hashtagColor - case .URL(_): attributes[NSForegroundColorAttributeName] = URLColor - case .None: () + case .mention(_): attributes[.foregroundColor] = mentionColor + case .hashtag(_): attributes[.foregroundColor] = hashtagColor + case .url(_): attributes[.foregroundColor] = URLColor + case .none: () } } @@ -424,7 +432,7 @@ public protocol ActionLabelDelegate: class { setNeedsDisplay() } - private func elementAtLocation(location: CGPoint) -> (range: NSRange, element: ActionElement)? { + private func elementAtLocation(location: CGPoint) -> (range: NSRange, element: ALElement)? { guard textStorage.length > 0 else { return nil } @@ -447,8 +455,8 @@ public protocol ActionLabelDelegate: class { return nil } + // MARK: - Handle UI Responder touches - //MARK: - Handle UI Responder touches public override func touchesBegan(_ touches: Set, with event: UIEvent?) { guard let touch = touches.first else { return } if onTouch(touch: touch) { return } @@ -473,10 +481,11 @@ public protocol ActionLabelDelegate: class { super.touchesEnded(touches, with: event) } - //MARK: - ActionLabel handler + // MARK: - ActionLabel handler + private func didTapMention(username: String) { guard let mentionHandler = mentionHandler else { - delegate?.didSelectText(text: username, type: .Mention) + delegate?.didSelectText(text: username, type: .mention) return } mentionHandler(username) @@ -484,7 +493,7 @@ public protocol ActionLabelDelegate: class { private func didTapHashtag(hashtag: String) { guard let hashtagHandler = hashtagHandler else { - delegate?.didSelectText(text: hashtag, type: .Hashtag) + delegate?.didSelectText(text: hashtag, type: .hashtag) return } hashtagHandler(hashtag) @@ -492,24 +501,25 @@ public protocol ActionLabelDelegate: class { private func didTapStringURL(stringURL: String) { guard let urlHandler = linkHandler, let url = NSURL(string: stringURL) else { - delegate?.didSelectText(text: stringURL, type: .URL) + delegate?.didSelectText(text: stringURL, type: .url) return } urlHandler(url) } } -extension ActionLabel: UIGestureRecognizerDelegate { - - public func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool { +// MARK: - Gestures + +extension ActionLabel { + public override func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true } - public func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOfGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool { + public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true } - public func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailByGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool { + public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true } } From 560fd2255d92f651e4ab5925afa869f1eb8a3a5f Mon Sep 17 00:00:00 2001 From: Nik Kov Date: Fri, 27 Jul 2018 18:03:29 +0300 Subject: [PATCH 3/3] Updated link regex --- ActionLabel/ActionLabel.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ActionLabel/ActionLabel.swift b/ActionLabel/ActionLabel.swift index e74aaeb..f53e575 100644 --- a/ActionLabel/ActionLabel.swift +++ b/ActionLabel/ActionLabel.swift @@ -27,9 +27,7 @@ typealias ActionFilterPredicate = ((String) -> Bool) struct ALParser { - static let linkPattern = "(^|[\\s.:;?\\-\\]<\\(])" + - "((https?://|www\\.|pic\\.)[-\\w;/?:@&=+$\\|\\_.!~*\\|'()\\[\\]%#,☺]+[\\w/#](\\(\\))?)" + - "(?=$|[\\s',\\|\\(\\).:;?\\-\\[\\]>\\)])" + static let linkPattern = "(^|\\s)((https?:\\/\\/)?[\\w-]+(\\.[\\w-]+)+\\.?(:\\d+)?(\\/\\S*)?)" static let hashtagPattern = "(?:^|\\s|$)#[\\p{L}0-9_]*"