mobile-ios/CovidSafe/NSMutableString + Extensions.swift

140 lines
6.1 KiB
Swift
Raw Permalink Normal View History

2020-05-08 07:49:14 +00:00
// Copyright © 2020 Australian Government All rights reserved.
import UIKit
public extension NSMutableAttributedString {
2020-07-21 05:42:48 +00:00
2020-11-29 21:04:39 +00:00
enum ElementType {
case Link,
Bold
}
2020-07-21 05:42:48 +00:00
func parseHTMLLinks() {
2020-11-29 21:04:39 +00:00
let regexLinkStartElementString = #"\<a(.*?)\>"#
let regexLinkEndElementTextString = #"\<\/a\>"#
while canParseOccurence(elementStartRegex: regexLinkStartElementString, elementEndRegex: regexLinkEndElementTextString) {
parseHtmlOccurence(elementStartRegex: regexLinkStartElementString, elementEndRegex: regexLinkEndElementTextString, elementType: .Link)
2020-07-21 05:42:48 +00:00
}
}
2020-11-29 21:04:39 +00:00
func parseBoldTags() {
let regexBoldStartElementString = #"\<b(.*?)\>"#
let regexBoldEndElementTextString = #"\<\/b\>"#
while canParseOccurence(elementStartRegex: regexBoldStartElementString, elementEndRegex: regexBoldEndElementTextString) {
parseHtmlOccurence(elementStartRegex: regexBoldStartElementString, elementEndRegex: regexBoldEndElementTextString, elementType: .Bold)
}
}
func canParseOccurence(elementStartRegex: String, elementEndRegex: String) -> Bool {
guard string.range(of: elementStartRegex, options: .regularExpression) != nil else {
2020-07-21 05:42:48 +00:00
return false
}
2020-11-29 21:04:39 +00:00
guard string.range(of: elementEndRegex, options: .regularExpression) != nil else {
2020-07-21 05:42:48 +00:00
return false
}
return true
}
2020-11-29 21:04:39 +00:00
fileprivate func parseHtmlOccurence(elementStartRegex: String, elementEndRegex: String, elementType: ElementType) {
guard let strStartElementRange = string.range(of: elementStartRegex, options: .regularExpression) else {
2020-07-21 05:42:48 +00:00
return
}
2020-11-29 21:04:39 +00:00
guard let strEndElementRange = string.range(of: elementEndRegex, options: .regularExpression) else {
2020-07-21 05:42:48 +00:00
return
}
let convertedStartRange = NSRange(strStartElementRange, in: string)
let convertedEndRange = NSRange(strEndElementRange, in: string)
let nsStartElementRange = NSRange(location: convertedStartRange.location, length: convertedStartRange.upperBound - convertedStartRange.lowerBound)
let nsEndElementRange = NSRange(location: convertedEndRange.location, length: convertedEndRange.upperBound - convertedEndRange.lowerBound)
2020-11-29 21:04:39 +00:00
switch elementType {
case .Link:
//get the url string
var urlString = ""
let startElementStr = String(string[strStartElementRange])
if let urlRange = startElementStr.range(of: #"\"(.*?)\""#, options: .regularExpression) {
let urlMatch = startElementStr[urlRange]
urlString = String(urlMatch)
let start = urlString.index(after: urlString.startIndex)
//ofset by 2 to as the quotes are escaped with \
let end = urlString.index(urlString.endIndex, offsetBy: -2)
urlString = String(urlString[start...end])
}
//remove html marking from text
replaceCharacters(in: nsEndElementRange, with: "*")
replaceCharacters(in: nsStartElementRange, with: "*")
addLink(enclosedIn: "*", urlString: urlString)
case .Bold:
//remove bold marking from text
replaceCharacters(in: nsEndElementRange, with: "#")
replaceCharacters(in: nsStartElementRange, with: "#")
addBold(enclosedIn: "#")
}
2020-07-21 05:42:48 +00:00
}
2020-05-08 07:49:14 +00:00
@discardableResult
func addLink(enclosedIn marker: String, urlString: String) -> Bool {
guard !marker.isEmpty else { return false }
2020-07-03 04:26:13 +00:00
let regexString = marker == "*" ? #"\*(.*?)\*"# : "\(marker)(.*?)\(marker)"
guard let strRange = string.range(of: regexString, options: .regularExpression) else {
return false
}
let convertedRange = NSRange(strRange, in: string)
2020-05-08 07:49:14 +00:00
2020-07-03 04:26:13 +00:00
let matchingString = string[strRange]
let enclosedString = matchingString.replacingOccurrences(of: marker, with: "")
let nsBeginRange = NSRange(location: convertedRange.location, length: marker.count)
let nsEndRange = NSRange(location: convertedRange.upperBound - marker.count, length: marker.count)
// first replace end, otherwise the range will change
2020-05-08 07:49:14 +00:00
replaceCharacters(in: nsEndRange, with: "")
2020-07-03 04:26:13 +00:00
replaceCharacters(in: nsBeginRange, with: "")
let linkRange = NSRange(location: convertedRange.location, length: enclosedString.count)
2020-05-08 07:49:14 +00:00
let attributes: [NSAttributedString.Key: Any] = [
.link: urlString,
.underlineStyle: NSUnderlineStyle.single.rawValue,
.underlineColor: UIColor.covidSafeColor
]
addAttributes(attributes, range: linkRange)
return true
}
2020-11-29 21:04:39 +00:00
@discardableResult
func addBold(enclosedIn marker: String) -> Bool {
guard !marker.isEmpty else { return false }
let regexString = "\(marker)(.*?)\(marker)"
guard let strRange = string.range(of: regexString, options: .regularExpression) else {
return false
}
let convertedRange = NSRange(strRange, in: string)
let matchingString = string[strRange]
let enclosedString = matchingString.replacingOccurrences(of: marker, with: "")
let nsBeginRange = NSRange(location: convertedRange.location, length: marker.count)
let nsEndRange = NSRange(location: convertedRange.upperBound - marker.count, length: marker.count)
// first replace end, otherwise the range will change
replaceCharacters(in: nsEndRange, with: "")
replaceCharacters(in: nsBeginRange, with: "")
let linkRange = NSRange(location: convertedRange.location, length: enclosedString.count)
// for now only supporting body. Need to get the UIFont from the current string.
let attributes: [NSAttributedString.Key: Any] = [
.font: UIFont.preferredFont(for: .body, weight: .semibold)
]
addAttributes(attributes, range: linkRange)
return true
}
2020-05-08 07:49:14 +00:00
}