2025-01-06 17:40:35 +01:00

129 lines
4.1 KiB
Swift

struct ButtonsBlock: BlockLineProcessor {
static let blockId: ContentBlock = .buttons
let content: Content
let results: PageGenerationResults
let language: ContentLanguage
private let buttons: ButtonBlock
init(content: Content, results: PageGenerationResults, language: ContentLanguage) {
self.content = content
self.results = results
self.language = language
self.buttons = .init(content: content, results: results, language: language)
}
func process(_ lines: [String], markdown: Substring) -> String {
let buttons = lines.split(separator: "").compactMap { buttonLines in
makeButton(buttonLines, markdown: markdown)
}
return ContentButtons(items: buttons).content
}
func makeButton(_ lines: ArraySlice<String>, markdown: Substring) -> ContentButtons.Item? {
let arguments: [ButtonBlock.Key : String] = lines.reduce(into: [:]) { dict, line in
guard line.trimmed != "" else {
return
}
let (rawKey, rawValue) = line.splitAtFirst(":")
guard let key = ButtonBlock.Key(rawValue: rawKey.trimmed) else {
print("Invalid key \(rawKey)")
invalid(markdown)
return
}
dict[key] = rawValue.trimmed
}
return self.buttons.process(arguments, markdown: markdown)
}
}
struct ButtonBlock: KeyedBlockProcessor {
enum Key: String, Equatable {
case icon
case file
case text
case name
case url
case event
}
static let blockId: ContentBlock = .button
let content: Content
let results: PageGenerationResults
let language: ContentLanguage
init(content: Content, results: PageGenerationResults, language: ContentLanguage) {
self.content = content
self.results = results
self.language = language
}
func process(_ arguments: [Key : String], markdown: Substring) -> String {
guard let button = process(arguments, markdown: markdown) else {
return ""
}
return ContentButtons(items: [button]).content
}
func process(_ arguments: [Key : String], markdown: Substring) -> ContentButtons.Item? {
guard let rawIcon = arguments[.icon],
let text = arguments[.text],
let icon = PageIcon(rawValue: rawIcon) else {
invalid(markdown)
return nil
}
if let file = arguments[.file] {
let name = arguments[.name]
return download(fileId: file, icon: icon, text: text, filename: name)
}
if let url = arguments[.url] {
return link(url: url, icon: icon, text: text, markdown: markdown)
}
if let event = arguments[.event] {
return action(event: event, icon: icon, text: text)
}
invalid(markdown)
return nil
}
private func download(fileId: String, icon: PageIcon, text: String, filename: String?) -> ContentButtons.Item? {
guard let file = content.file(fileId) else {
results.missing(file: fileId, source: "Download button")
return nil
}
results.require(file: file)
results.require(icon: icon)
return ContentButtons.Item(
icon: icon,
filePath: file.absoluteUrl,
text: text,
downloadFileName: filename)
}
private func link(url: String, icon: PageIcon, text: String, markdown: Substring) -> ContentButtons.Item? {
guard let encodedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
invalid(markdown)
return nil
}
results.externalLink(to: url)
results.require(icon: icon)
return .init(icon: icon, filePath: encodedUrl, text: text)
}
private func action(event: String, icon: PageIcon, text: String) -> ContentButtons.Item? {
results.require(icon: icon)
return .init(icon: icon, filePath: nil, text: text, onClickText: event)
}
}