mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Add support for ordered and unordered lists.
This commit is contained in:
@@ -71,7 +71,8 @@ struct AttributedStringBuilderV2: AttributedStringBuilderProtocol {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let mutableAttributedString = attributedString(from: body, preserveFormatting: false)
|
var listIndex = 1
|
||||||
|
let mutableAttributedString = attributedString(from: body, preserveFormatting: false, listTag: nil, listIndex: &listIndex, indentLevel: 0)
|
||||||
detectPhishingAttempts(mutableAttributedString)
|
detectPhishingAttempts(mutableAttributedString)
|
||||||
addLinksAndMentions(mutableAttributedString)
|
addLinksAndMentions(mutableAttributedString)
|
||||||
addMatrixEntityPermalinkAttributesTo(mutableAttributedString)
|
addMatrixEntityPermalinkAttributesTo(mutableAttributedString)
|
||||||
@@ -84,7 +85,10 @@ struct AttributedStringBuilderV2: AttributedStringBuilderProtocol {
|
|||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
func attributedString(from element: Element, preserveFormatting: Bool) -> NSMutableAttributedString {
|
func attributedString(from element: Element, preserveFormatting: Bool,
|
||||||
|
listTag: String?,
|
||||||
|
listIndex: inout Int,
|
||||||
|
indentLevel: Int) -> NSMutableAttributedString {
|
||||||
let result = NSMutableAttributedString()
|
let result = NSMutableAttributedString()
|
||||||
|
|
||||||
for node in element.getChildNodes() {
|
for node in element.getChildNodes() {
|
||||||
@@ -108,54 +112,55 @@ struct AttributedStringBuilderV2: AttributedStringBuilderProtocol {
|
|||||||
|
|
||||||
let tag = childElement.tagName().lowercased()
|
let tag = childElement.tagName().lowercased()
|
||||||
var content = NSMutableAttributedString()
|
var content = NSMutableAttributedString()
|
||||||
|
var childIndex = 1
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case "h1", "h2", "h3", "h4", "h5", "h6":
|
case "h1", "h2", "h3", "h4", "h5", "h6":
|
||||||
let level = Int(String(tag.dropFirst())) ?? 1
|
let level = Int(String(tag.dropFirst())) ?? 1
|
||||||
let size: CGFloat = UIFont.systemFontSize + CGFloat(6 - level) * 2
|
let size: CGFloat = UIFont.systemFontSize + CGFloat(6 - level) * 2
|
||||||
content = attributedString(from: childElement, preserveFormatting: preserveFormatting)
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
|
||||||
content.setFontPreservingSymbolicTraits(UIFont.boldSystemFont(ofSize: size))
|
content.setFontPreservingSymbolicTraits(UIFont.boldSystemFont(ofSize: size))
|
||||||
|
|
||||||
case "p", "div":
|
case "p", "div":
|
||||||
content = attributedString(from: childElement, preserveFormatting: preserveFormatting)
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
|
||||||
content.append(NSAttributedString(string: "\n"))
|
content.append(NSAttributedString(string: "\n"))
|
||||||
|
|
||||||
case "br":
|
case "br":
|
||||||
content = NSMutableAttributedString(string: "\n")
|
content = NSMutableAttributedString(string: "\n")
|
||||||
|
|
||||||
case "b", "strong":
|
case "b", "strong":
|
||||||
content = attributedString(from: childElement, preserveFormatting: preserveFormatting)
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
|
||||||
content.setFontPreservingSymbolicTraits(UIFont.boldSystemFont(ofSize: UIFont.systemFontSize))
|
content.setFontPreservingSymbolicTraits(UIFont.boldSystemFont(ofSize: UIFont.systemFontSize))
|
||||||
|
|
||||||
case "i", "em":
|
case "i", "em":
|
||||||
content = attributedString(from: childElement, preserveFormatting: preserveFormatting)
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
|
||||||
content.setFontPreservingSymbolicTraits(UIFont.italicSystemFont(ofSize: UIFont.systemFontSize))
|
content.setFontPreservingSymbolicTraits(UIFont.italicSystemFont(ofSize: UIFont.systemFontSize))
|
||||||
|
|
||||||
case "u":
|
case "u":
|
||||||
content = attributedString(from: childElement, preserveFormatting: preserveFormatting)
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
|
||||||
content.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: content.length))
|
content.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: content.length))
|
||||||
|
|
||||||
case "s", "del":
|
case "s", "del":
|
||||||
content = attributedString(from: childElement, preserveFormatting: preserveFormatting)
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
|
||||||
content.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: content.length))
|
content.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: content.length))
|
||||||
|
|
||||||
case "sup":
|
case "sup":
|
||||||
content = attributedString(from: childElement, preserveFormatting: preserveFormatting)
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
|
||||||
content.addAttribute(.baselineOffset, value: 6, range: NSRange(location: 0, length: content.length))
|
content.addAttribute(.baselineOffset, value: 6, range: NSRange(location: 0, length: content.length))
|
||||||
content.setFontPreservingSymbolicTraits(UIFont.systemFont(ofSize: UIFont.systemFontSize * 0.7))
|
content.setFontPreservingSymbolicTraits(UIFont.systemFont(ofSize: UIFont.systemFontSize * 0.7))
|
||||||
|
|
||||||
case "sub":
|
case "sub":
|
||||||
content = attributedString(from: childElement, preserveFormatting: preserveFormatting)
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
|
||||||
content.addAttribute(.baselineOffset, value: -4, range: NSRange(location: 0, length: content.length))
|
content.addAttribute(.baselineOffset, value: -4, range: NSRange(location: 0, length: content.length))
|
||||||
content.setFontPreservingSymbolicTraits(UIFont.systemFont(ofSize: UIFont.systemFontSize * 0.7))
|
content.setFontPreservingSymbolicTraits(UIFont.systemFont(ofSize: UIFont.systemFontSize * 0.7))
|
||||||
|
|
||||||
case "blockquote":
|
case "blockquote":
|
||||||
content = attributedString(from: childElement, preserveFormatting: preserveFormatting)
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
|
||||||
content.addAttribute(.MatrixBlockquote, value: true, range: NSRange(location: 0, length: content.length))
|
content.addAttribute(.MatrixBlockquote, value: true, range: NSRange(location: 0, length: content.length))
|
||||||
|
|
||||||
case "code", "pre":
|
case "code", "pre":
|
||||||
let preserveFormatting = preserveFormatting || tag == "pre"
|
let preserveFormatting = preserveFormatting || tag == "pre"
|
||||||
content = attributedString(from: childElement, preserveFormatting: preserveFormatting)
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
|
||||||
content.setFontPreservingSymbolicTraits(UIFont.monospacedSystemFont(ofSize: UIFont.systemFontSize, weight: .regular))
|
content.setFontPreservingSymbolicTraits(UIFont.monospacedSystemFont(ofSize: UIFont.systemFontSize, weight: .regular))
|
||||||
content.addAttribute(.backgroundColor, value: UIColor.compound._bgCodeBlock as Any, range: NSRange(location: 0, length: content.length))
|
content.addAttribute(.backgroundColor, value: UIColor.compound._bgCodeBlock as Any, range: NSRange(location: 0, length: content.length))
|
||||||
|
|
||||||
@@ -163,18 +168,43 @@ struct AttributedStringBuilderV2: AttributedStringBuilderProtocol {
|
|||||||
content = NSMutableAttributedString(string: "\n")
|
content = NSMutableAttributedString(string: "\n")
|
||||||
|
|
||||||
case "a":
|
case "a":
|
||||||
content = attributedString(from: childElement, preserveFormatting: preserveFormatting)
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
|
||||||
if let href = try? childElement.attr("href") {
|
if let href = try? childElement.attr("href") {
|
||||||
content.addAttribute(.link, value: href, range: NSRange(location: 0, length: content.length))
|
content.addAttribute(.link, value: href, range: NSRange(location: 0, length: content.length))
|
||||||
}
|
}
|
||||||
|
|
||||||
case "span":
|
case "span":
|
||||||
if (try? childElement.attr(Self.attributeMSC4286)) ?? nil != nil {
|
if (try? childElement.attr(Self.attributeMSC4286)) ?? nil != nil {
|
||||||
content = attributedString(from: childElement, preserveFormatting: preserveFormatting)
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "ul", "ol":
|
||||||
|
var listIndex = 1
|
||||||
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: tag, listIndex: &listIndex, indentLevel: indentLevel + 1)
|
||||||
|
if listTag == nil { // If not within another list
|
||||||
|
content.insert(NSAttributedString(string: "\n"), at: 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
case "li":
|
||||||
|
var bullet = ""
|
||||||
|
if listTag == "ol" {
|
||||||
|
bullet = "\(listIndex). "
|
||||||
|
listIndex += 1
|
||||||
|
} else {
|
||||||
|
bullet = "• "
|
||||||
|
}
|
||||||
|
|
||||||
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel + 1)
|
||||||
|
content.insert(NSAttributedString(string: bullet), at: 0)
|
||||||
|
content.append(NSAttributedString(string: "\n"))
|
||||||
|
|
||||||
|
let paragraphStyle = NSMutableParagraphStyle()
|
||||||
|
paragraphStyle.headIndent = CGFloat(indentLevel) * 20
|
||||||
|
paragraphStyle.firstLineHeadIndent = CGFloat(indentLevel) * 20
|
||||||
|
content.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: content.length))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
content = attributedString(from: childElement, preserveFormatting: preserveFormatting)
|
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
result.append(content)
|
result.append(content)
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ struct FormattedBodyText_Previews: PreviewProvider, TestablePreview {
|
|||||||
This is an unordered list
|
This is an unordered list
|
||||||
<ul>
|
<ul>
|
||||||
<li>Jones’ <b>Crumpets</b></li>
|
<li>Jones’ <b>Crumpets</b></li>
|
||||||
<li><i>Crumpetorium<i></li>
|
<li><i>Crumpetorium</i></li>
|
||||||
<li>Village <u>Bakery</u></li>
|
<li>Village <u>Bakery</u></li>
|
||||||
</ul>
|
</ul>
|
||||||
""",
|
""",
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:0afe442ef495ebf79cfb765870127fd522e5634d9fcaf97ad7f18d2e6d61ff16
|
oid sha256:4ec1eee24450c078e2d930204eb6c4bd5f5a48c1d472926ad25dd061389d7c45
|
||||||
size 1144762
|
size 1144610
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:eeff85fc90e7c67e1812d308516d642ed5e534675384a9acbd7f1a112bb904f3
|
oid sha256:4d6c10079176b2c9d5d4155e0d917a25191723ce8b0c3c1c23a4b2ceed15f3fb
|
||||||
size 1106059
|
size 1116696
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:0afe442ef495ebf79cfb765870127fd522e5634d9fcaf97ad7f18d2e6d61ff16
|
oid sha256:4ec1eee24450c078e2d930204eb6c4bd5f5a48c1d472926ad25dd061389d7c45
|
||||||
size 1144762
|
size 1144610
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:eeff85fc90e7c67e1812d308516d642ed5e534675384a9acbd7f1a112bb904f3
|
oid sha256:4d6c10079176b2c9d5d4155e0d917a25191723ce8b0c3c1c23a4b2ceed15f3fb
|
||||||
size 1106059
|
size 1116696
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:1c1d75edcce4fd949e15c41cf00a0ee5cb2974a5573ac079e9bbeef230008170
|
oid sha256:aeee2464439a366386e0ededbd5ebde7c330a9a90c26964dc9a63e56563dc7f5
|
||||||
size 1323823
|
size 1323827
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:71608e9218a46fa9f22b59e90352d6a463597bb9b2dbff95d063d334085bd8a5
|
oid sha256:e84edbb38495d3c2d323ee5dcd37896c9b286bec6377980625d35e861e5dbd19
|
||||||
size 1303346
|
size 1307233
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:1c1d75edcce4fd949e15c41cf00a0ee5cb2974a5573ac079e9bbeef230008170
|
oid sha256:aeee2464439a366386e0ededbd5ebde7c330a9a90c26964dc9a63e56563dc7f5
|
||||||
size 1323823
|
size 1323827
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:71608e9218a46fa9f22b59e90352d6a463597bb9b2dbff95d063d334085bd8a5
|
oid sha256:e84edbb38495d3c2d323ee5dcd37896c9b286bec6377980625d35e861e5dbd19
|
||||||
size 1303346
|
size 1307233
|
||||||
|
|||||||
Reference in New Issue
Block a user