diff --git a/Tusker/HTMLConverter.swift b/Tusker/HTMLConverter.swift
index d4911408..22504752 100644
--- a/Tusker/HTMLConverter.swift
+++ b/Tusker/HTMLConverter.swift
@@ -37,7 +37,12 @@ struct HTMLConverter {
mutAttrString.trimTrailingCharactersInSet(.whitespacesAndNewlines)
mutAttrString.collapseWhitespace()
- mutAttrString.addAttribute(.paragraphStyle, value: paragraphStyle, range: mutAttrString.fullRange)
+ // Wait until the end and then fill in the unset paragraph styles, to avoid clobbering the list style.
+ mutAttrString.enumerateAttribute(.paragraphStyle, in: mutAttrString.fullRange, options: .longestEffectiveRangeNotRequired) { value, range, stop in
+ if value == nil {
+ mutAttrString.addAttribute(.paragraphStyle, value: paragraphStyle, range: range)
+ }
+ }
return mutAttrString
} else {
@@ -56,6 +61,10 @@ struct HTMLConverter {
}
return NSAttributedString(string: text, attributes: [.font: font, .foregroundColor: color])
case let node as Element:
+ if node.tagName() == "ol" || node.tagName() == "ul" {
+ return attributedTextForList(node, usePreformattedText: usePreformattedText)
+ }
+
let attributed = NSMutableAttributedString(string: "", attributes: [.font: font, .foregroundColor: color])
for child in node.getChildNodes() {
var appendEllipsis = false
@@ -115,25 +124,6 @@ struct HTMLConverter {
case "pre":
attributed.append(NSAttributedString(string: "\n\n"))
attributed.addAttribute(.font, value: monospaceFont, range: attributed.fullRange)
- case "ol", "ul":
- attributed.append(NSAttributedString(string: "\n\n"))
- attributed.trimLeadingCharactersInSet(.whitespacesAndNewlines)
- 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
- // TODO: this probably breaks with dynamic type
- bullet = NSAttributedString(string: "\(index + 1).\t", attributes: [.font: monospaceFont, .foregroundColor: color])
- } else if parentTag == "ul" {
- bullet = NSAttributedString(string: "\u{2022}\t", attributes: [.font: font, .foregroundColor: color])
- } else {
- bullet = NSAttributedString()
- }
- attributed.insert(bullet, at: 0)
- attributed.append(NSAttributedString(string: "\n", attributes: [.font: font]))
default:
break
}
@@ -144,5 +134,37 @@ struct HTMLConverter {
}
}
+ private func attributedTextForList(_ element: Element, usePreformattedText: Bool) -> NSAttributedString {
+ let list = element.tagName() == "ol" ? OrderedNumberTextList(markerFormat: .decimal, options: 0) : NSTextList(markerFormat: .disc, options: 0)
+ let paragraphStyle = paragraphStyle.mutableCopy() as! NSMutableParagraphStyle
+ // I don't like that I can't just use paragraphStyle.textLists, because it makes the list markers
+ // not use the monospace digit font (it seems to just use whatever font attribute is set for the whole thing),
+ // and it doesn't right align the list markers.
+ // Unfortunately, doing it manually means the list markers are incldued in the selectable text.
+ paragraphStyle.headIndent = 32
+ paragraphStyle.firstLineHeadIndent = 0
+ // Use 2 tab stops, one for the list marker, the second for the content.
+ paragraphStyle.tabStops = [NSTextTab(textAlignment: .right, location: 28), NSTextTab(textAlignment: .natural, location: 32)]
+ let str = NSMutableAttributedString(string: "")
+ var item = 1
+ for child in element.children() where child.tagName() == "li" {
+ if let childStr = attributedTextForHTMLNode(child, usePreformattedText: usePreformattedText) {
+ str.append(NSAttributedString(string: "\t\(list.marker(forItemNumber: item))\t", attributes: [
+ .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .monospacedDigitSystemFont(ofSize: 17, weight: .regular)),
+ ]))
+ str.append(childStr)
+ str.append(NSAttributedString(string: "\n"))
+ item += 1
+ }
+ }
+ str.addAttribute(.paragraphStyle, value: paragraphStyle, range: str.fullRange)
+ return str
+ }
}
+
+private class OrderedNumberTextList: NSTextList {
+ override func marker(forItemNumber itemNumber: Int) -> String {
+ "\(super.marker(forItemNumber: itemNumber))."
+ }
+}