Add append action to element callbacks

This commit is contained in:
Shadowfacts 2024-01-16 19:15:56 -05:00
parent 64b68a6cec
commit a32b972201
5 changed files with 45 additions and 19 deletions

View File

@ -242,16 +242,18 @@ public struct AttributedStringConverter<Callbacks: HTMLConversionCallbacks> {
}() }()
private mutating func finishRun() { private mutating func finishRun() {
guard !currentRun.isEmpty else {
return
}
if actionStack.contains(.skip) { if actionStack.contains(.skip) {
currentRun = "" currentRun = ""
return return
} else if case .append(let s) = actionStack.last {
currentRun.append(s)
} else if case .replace(let replacement) = actionStack.first(where: \.isReplace) { } else if case .replace(let replacement) = actionStack.first(where: \.isReplace) {
currentRun = replacement currentRun = replacement
} }
guard !currentRun.isEmpty else {
return
}
var attributes = [NSAttributedString.Key: Any]() var attributes = [NSAttributedString.Key: Any]()
var paragraphStyle = configuration.paragraphStyle var paragraphStyle = configuration.paragraphStyle

View File

@ -16,6 +16,7 @@ public enum ElementAction: Equatable {
case `default` case `default`
case skip case skip
case replace(String) case replace(String)
case append(String)
var isReplace: Bool { var isReplace: Bool {
if case .replace(_) = self { if case .replace(_) = self {

View File

@ -109,17 +109,19 @@ public struct TextConverter<Callbacks: HTMLConversionCallbacks> {
} }
private mutating func finishRun() { private mutating func finishRun() {
guard !currentRun.isEmpty else {
return
}
if actionStack.contains(.skip) { if actionStack.contains(.skip) {
currentRun = "" currentRun = ""
return return
} else if case .append(let s) = actionStack.last {
currentRun.append(s)
} else if case .replace(let replacement) = actionStack.first(where: \.isReplace) { } else if case .replace(let replacement) = actionStack.first(where: \.isReplace) {
currentRun = replacement currentRun = replacement
} }
guard !currentRun.isEmpty else {
return
}
str.append(currentRun) str.append(currentRun)
currentRun = "" currentRun = ""
} }

View File

@ -250,27 +250,41 @@ final class AttributedStringConverterTests: XCTestCase {
struct Callbacks: HTMLConversionCallbacks { struct Callbacks: HTMLConversionCallbacks {
static func elementAction(name: String, attributes: [Attribute]) -> ElementAction { static func elementAction(name: String, attributes: [Attribute]) -> ElementAction {
let clazz = attributes.attributeValue(for: "class") let clazz = attributes.attributeValue(for: "class")
if clazz == "invisible" { if clazz == "skip" {
return .skip return .skip
} else if clazz == "ellipsis" { } else if clazz == "replace" {
return .replace("") return .replace("")
} else if clazz == "append" {
return .append("")
} else { } else {
return .default return .default
} }
} }
} }
let skipped = convert("<span class='invisible'>test</span>", callbacks: Callbacks.self) let skipped = convert("<span class='skip'>test</span>", callbacks: Callbacks.self)
XCTAssertEqual(skipped, NSAttributedString()) XCTAssertEqual(skipped, NSAttributedString())
let skipNested = convert("<span class='invisible'><b>test</b></span>", callbacks: Callbacks.self) let skipNested = convert("<span class='skip'><b>test</b></span>", callbacks: Callbacks.self)
XCTAssertEqual(skipNested, NSAttributedString()) XCTAssertEqual(skipNested, NSAttributedString())
let skipNestped2 = convert("<b><span class='invisible'>test</span></b>", callbacks: Callbacks.self) let skipNestped2 = convert("<b><span class='skip'>test</span></b>", callbacks: Callbacks.self)
XCTAssertEqual(skipNestped2, NSAttributedString()) XCTAssertEqual(skipNestped2, NSAttributedString())
let replaced = convert("<span class='ellipsis'>test</span>", callbacks: Callbacks.self) let replaced = convert("<span class='replace'>test</span>", callbacks: Callbacks.self)
XCTAssertEqual(replaced, NSAttributedString(string: "", attributes: [ XCTAssertEqual(replaced, NSAttributedString(string: "", attributes: [
.font: font, .font: font,
.paragraphStyle: NSParagraphStyle.default, .paragraphStyle: NSParagraphStyle.default,
.foregroundColor: color, .foregroundColor: color,
])) ]))
let appended = convert("<span class='append'>test</span>", callbacks: Callbacks.self)
XCTAssertEqual(appended, NSAttributedString(string: "test…", attributes: [
.font: font,
.paragraphStyle: NSParagraphStyle.default,
.foregroundColor: color,
]))
let appended2 = convert("<span class='append'>test <span>blah</span></span>", callbacks: Callbacks.self)
XCTAssertEqual(appended2, NSAttributedString(string: "test blah…", attributes: [
.font: font,
.paragraphStyle: NSParagraphStyle.default,
.foregroundColor: color,
]))
} }
func testOrderedList() { func testOrderedList() {

View File

@ -46,21 +46,28 @@ final class TextConverterTests: XCTestCase {
struct Callbacks: HTMLConversionCallbacks { struct Callbacks: HTMLConversionCallbacks {
static func elementAction(name: String, attributes: [Attribute]) -> ElementAction { static func elementAction(name: String, attributes: [Attribute]) -> ElementAction {
let clazz = attributes.attributeValue(for: "class") let clazz = attributes.attributeValue(for: "class")
if clazz == "invisible" { if clazz == "skip" {
return .skip return .skip
} else if clazz == "ellipsis" { } else if clazz == "replace" {
return .replace("") return .replace("")
} else if clazz == "append" {
return .append("")
} else { } else {
return .default return .default
} }
} }
} }
let skipped = convert("<span class='invisible'>test</span>", callbacks: Callbacks.self) let skipped = convert("<span class='skip'>test</span>", callbacks: Callbacks.self)
XCTAssertEqual(skipped, "") XCTAssertEqual(skipped, "")
let skipNested = convert("<span class='invisible'><b>test</b></span>", callbacks: Callbacks.self) let skipNested = convert("<span class='skip'><b>test</b></span>", callbacks: Callbacks.self)
XCTAssertEqual(skipNested, "") XCTAssertEqual(skipNested, "")
let replaced = convert("<span class='ellipsis'>test</span>", callbacks: Callbacks.self) let replaced = convert("<span class='replace'>test</span>", callbacks: Callbacks.self)
XCTAssertEqual(replaced, "") XCTAssertEqual(replaced, "")
let appended = convert("<span class='append'>test</span>", callbacks: Callbacks.self)
XCTAssertEqual(appended, "test…")
let appended2 = convert("<span class='append'>test <span>blah</span></span>", callbacks: Callbacks.self)
XCTAssertEqual(appended2, "test blah…")
} }
func testEmptyBlockElements() { func testEmptyBlockElements() {