Add support for additional formatting

Italics, bold, strikethrough, monospace, and (un)ordered lists
This commit is contained in:
Shadowfacts 2019-04-04 21:45:48 -04:00
parent d94a0050b7
commit 66bb1050a5
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
3 changed files with 54 additions and 14 deletions

View File

@ -71,7 +71,7 @@
D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2421217AA7E1005076CC /* UserActivityManager.swift */; }; D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2421217AA7E1005076CC /* UserActivityManager.swift */; };
D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */; }; D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */; };
D62D2426217ABF63005076CC /* UserActivityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2425217ABF63005076CC /* UserActivityType.swift */; }; D62D2426217ABF63005076CC /* UserActivityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2425217ABF63005076CC /* UserActivityType.swift */; };
D6333B372137838300CE884A /* AttributedString+Trim.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B362137838300CE884A /* AttributedString+Trim.swift */; }; D6333B372137838300CE884A /* AttributedString+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B362137838300CE884A /* AttributedString+Helpers.swift */; };
D6333B772138D94E00CE884A /* ComposeMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B762138D94E00CE884A /* ComposeMediaView.swift */; }; D6333B772138D94E00CE884A /* ComposeMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B762138D94E00CE884A /* ComposeMediaView.swift */; };
D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */; }; D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */; };
D641C773213CAA25004B4513 /* NotificationsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D641C772213CAA25004B4513 /* NotificationsTableViewController.swift */; }; D641C773213CAA25004B4513 /* NotificationsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D641C772213CAA25004B4513 /* NotificationsTableViewController.swift */; };
@ -298,7 +298,7 @@
D62D2421217AA7E1005076CC /* UserActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityManager.swift; sourceTree = "<group>"; }; D62D2421217AA7E1005076CC /* UserActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityManager.swift; sourceTree = "<group>"; };
D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSUserActivity+Extensions.swift"; sourceTree = "<group>"; }; D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSUserActivity+Extensions.swift"; sourceTree = "<group>"; };
D62D2425217ABF63005076CC /* UserActivityType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityType.swift; sourceTree = "<group>"; }; D62D2425217ABF63005076CC /* UserActivityType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityType.swift; sourceTree = "<group>"; };
D6333B362137838300CE884A /* AttributedString+Trim.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Trim.swift"; sourceTree = "<group>"; }; D6333B362137838300CE884A /* AttributedString+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Helpers.swift"; sourceTree = "<group>"; };
D6333B762138D94E00CE884A /* ComposeMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeMediaView.swift; sourceTree = "<group>"; }; D6333B762138D94E00CE884A /* ComposeMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeMediaView.swift; sourceTree = "<group>"; };
D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+TimeAgo.swift"; sourceTree = "<group>"; }; D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+TimeAgo.swift"; sourceTree = "<group>"; };
D641C772213CAA25004B4513 /* NotificationsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsTableViewController.swift; sourceTree = "<group>"; }; D641C772213CAA25004B4513 /* NotificationsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsTableViewController.swift; sourceTree = "<group>"; };
@ -769,7 +769,7 @@
D667E5F72135C3040057A976 /* Mastodon+Equatable.swift */, D667E5F72135C3040057A976 /* Mastodon+Equatable.swift */,
D663626B21361C6700C9CBA2 /* Account+Preferences.swift */, D663626B21361C6700C9CBA2 /* Account+Preferences.swift */,
D66362742137068A00C9CBA2 /* Visibility+Helpers.swift */, D66362742137068A00C9CBA2 /* Visibility+Helpers.swift */,
D6333B362137838300CE884A /* AttributedString+Trim.swift */, D6333B362137838300CE884A /* AttributedString+Helpers.swift */,
D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */, D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */,
D67C57AE21E28EAD00C3118B /* Array+Uniques.swift */, D67C57AE21E28EAD00C3118B /* Array+Uniques.swift */,
); );
@ -1388,7 +1388,7 @@
04496BD721625361001F1B23 /* ContentLabel.swift in Sources */, 04496BD721625361001F1B23 /* ContentLabel.swift in Sources */,
D663626C21361C6700C9CBA2 /* Account+Preferences.swift in Sources */, D663626C21361C6700C9CBA2 /* Account+Preferences.swift in Sources */,
D6C693CA2161253F007D6A6D /* SilentActionPermissionsTableViewController.swift in Sources */, D6C693CA2161253F007D6A6D /* SilentActionPermissionsTableViewController.swift in Sources */,
D6333B372137838300CE884A /* AttributedString+Trim.swift in Sources */, D6333B372137838300CE884A /* AttributedString+Helpers.swift in Sources */,
D6B8DB342182A59300424AF7 /* UIAlertController+Visibility.swift in Sources */, D6B8DB342182A59300424AF7 /* UIAlertController+Visibility.swift in Sources */,
D67C57AD21E265FC00C3118B /* LargeAccountDetailView.swift in Sources */, D67C57AD21E265FC00C3118B /* LargeAccountDetailView.swift in Sources */,
D641C777213CAA9E004B4513 /* ActionNotificationTableViewCell.swift in Sources */, D641C777213CAA9E004B4513 /* ActionNotificationTableViewCell.swift in Sources */,

View File

@ -10,15 +10,22 @@ import Foundation
extension NSMutableAttributedString { extension NSMutableAttributedString {
func trimTrailingCharactersInSet(_ charSet: CharacterSet) { var fullRange: NSRange {
return NSRange(location: 0, length: self.length)
}
func trimLeadingCharactersInSet(_ charSet: CharacterSet) {
var range = (string as NSString).rangeOfCharacter(from: charSet) var range = (string as NSString).rangeOfCharacter(from: charSet)
// while range.length != 0 && range.location == 0 { while range.length != 0 && range.location == 0 {
// replaceCharacters(in: range, with: "") replaceCharacters(in: range, with: "")
// range = (string as NSString).rangeOfCharacter(from: charSet) range = (string as NSString).rangeOfCharacter(from: charSet)
// } }
}
func trimTrailingCharactersInSet(_ charSet: CharacterSet) {
var range = (string as NSString).rangeOfCharacter(from: charSet, options: .backwards)
range = (string as NSString).rangeOfCharacter(from: charSet, options: .backwards)
while range.length != 0 && range.length + range.location == length { while range.length != 0 && range.length + range.location == length {
replaceCharacters(in: range, with: "") replaceCharacters(in: range, with: "")
range = (string as NSString).rangeOfCharacter(from: charSet, options: .backwards) range = (string as NSString).rangeOfCharacter(from: charSet, options: .backwards)

View File

@ -89,8 +89,6 @@ class ContentLabel: LinkLabel {
// this would get trimmed and cause range out of bounds crashes // this would get trimmed and cause range out of bounds crashes
mutAttrString.trimTrailingCharactersInSet(.whitespacesAndNewlines) mutAttrString.trimTrailingCharactersInSet(.whitespacesAndNewlines)
mutAttrString.addAttribute(.font, value: font!, range: NSRange(location: 0, length: mutAttrString.length))
self.links = [] self.links = []
let linkAttributes: [NSAttributedString.Key: Any] = [ let linkAttributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor.blue, .foregroundColor: UIColor.blue,
@ -125,11 +123,46 @@ class ContentLabel: LinkLabel {
case "a": case "a":
if let link = try? node.attr("href"), if let link = try? node.attr("href"),
let url = URL(string: link) { let url = URL(string: link) {
let linkRange = NSRange(location: 0, length: attributed.length) links[attributed.fullRange] = url
links[linkRange] = url
} }
case "p": case "p":
attributed.append(NSAttributedString(string: "\n\n")) attributed.append(NSAttributedString(string: "\n\n"))
case "em", "i":
attributed.addAttribute(.font, value: UIFont.italicSystemFont(ofSize: font!.pointSize), range: attributed.fullRange)
case "strong", "b":
attributed.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: font!.pointSize), range: attributed.fullRange)
case "del":
attributed.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: attributed.fullRange)
case "code":
attributed.addAttribute(.font, value: UIFont(name: "Menlo", size: font!.pointSize)!, range: attributed.fullRange)
case "pre":
attributed.addAttribute(.font, value: UIFont(name: "Menlo", size: font!.pointSize)!, range: attributed.fullRange)
attributed.append(NSAttributedString(string: "\n\n"))
case "ol", "ul":
attributed.trimLeadingCharactersInSet(.whitespacesAndNewlines)
attributed.append(NSAttributedString(string: "\n"))
break
case "li":
let parentEl = node.parent()!
let parentTag = parentEl.tagName()
let bullet: NSAttributedString
if parentTag == "ol" {
let index = (try? node.elementSiblingIndex()) ?? 0
// we use the monospace digit font so that the periods of all the list items line up
bullet = NSAttributedString(string: "\(index + 1).\t", attributes: [.font: UIFont.monospacedDigitSystemFont(ofSize: font!.pointSize, weight: .regular)])
} else if parentTag == "ul" {
bullet = NSAttributedString(string: "\u{2022}\t")
} else {
bullet = NSAttributedString(string: "")
}
// inserting bullets at the beginning of the string shifts all the links down, so we adjust the link ranges
for (range, url) in links {
let newRange = NSRange(location: range.location + bullet.length - 1, length: range.length)
links[newRange] = url
links.removeValue(forKey: range)
}
attributed.insert(bullet, at: 0)
attributed.append(NSAttributedString(string: "\n"))
default: default:
break break
} }