Add support for additional formatting
Italics, bold, strikethrough, monospace, and (un)ordered lists
This commit is contained in:
parent
d94a0050b7
commit
66bb1050a5
|
@ -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 */,
|
||||||
|
|
|
@ -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)
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue