forked from objcio/swift-talk-backend
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHTMLExtensions.swift
105 lines (88 loc) · 3.74 KB
/
HTMLExtensions.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//
// HTMLExtensions.swift
// SwiftTalkServerLib
//
// Created by Florian Kugler on 09-02-2019.
//
import Foundation
import Base
import HTML
import WebServer
import CommonMark
typealias Node = HTML.Node<STRequestEnvironment>
protocol LinkTarget {
var absoluteString: String { get }
}
extension URL: LinkTarget {}
extension Route: LinkTarget {
var absoluteString: String { return path }
}
extension HTML.Node where I == STRequestEnvironment {
static func hashedStylesheet(media: String = "all", href: String) -> Node {
return Node.withInput { deps in
return Node.stylesheet(media: media, href: deps.hashedAssetName(href))
}
}
static func hashedScript(src: String) -> Node {
return Node.withInput { deps in
return Node.script(src: deps.hashedAssetName(src))
}
}
static func hashedImg(class: Class? = nil, src: String, alt: String = "", attributes: [String:String] = [:]) -> Node {
return Node.withInput { deps in
return Node.img(class: `class`, src: deps.hashedAssetName(src), alt: alt, attributes: attributes)
}
}
static func withCSRF(_ f: @escaping (CSRFToken) -> Node) -> Node {
return .withInput { f($0.csrf) }
}
static func withSession(_ f: @escaping (Session?) -> Node) -> Node {
return .withInput { f($0.session) }
}
static func withResourcePaths(_ f: @escaping ([URL]) -> Node) -> Node {
return .withInput { f($0.resourcePaths) }
}
static func withRoute(_ f: @escaping (Route) -> Node) -> Node {
return .withInput { f($0.route) }
}
static func link(to: Route, class: Class? = nil, attributes: [String:String] = [:], _ children: [Node]) -> Node {
return Node.a(class: `class`, href: to.path, attributes: attributes, children)
}
static func link(to: LinkTarget, class: Class? = nil, attributes: [String:String] = [:], _ children: [Node]) -> Node {
return Node.a(class: `class`, href: to.absoluteString, attributes: attributes, children)
}
static func button(to route: Route, confirm: String? = "Are you sure?", class: Class? = nil, attributes: [String:String] = [:], _ children: [Node]) -> Node {
var attrs = ["type": "submit"]
if let c = confirm {
attrs["data-confirm"] = c
}
return Node.withCSRF { csrf in
Node.form(class: "button_to", action: route.path, method: .post, [
Node.input(name: "csrf", id: "csrf", type: "hidden", attributes: ["value": csrf.string], []),
Node.button(class: `class`, attributes: attrs, children)
])
}
}
static func inlineSvg(class: Class? = nil, path: String, preserveAspectRatio: String? = nil, attributes: [String:String] = [:]) -> Node {
// don't render inline svg's in tests
if ProcessInfo.processInfo.environment.keys.contains("IDEiPhoneInternalTestBundleName") {
return Node.none
}
return Node.withResourcePaths { resourcePaths in
guard let name = resourcePaths.resolve("images/" + path) else {
log(info: "Couldn't find svg")
return .none
}
var a = attributes
if let c = `class` {
a["class", default: ""] += c.class
}
// NOTE This has worked fine so far, but could be done with proper xml parsing if necessary
let contents = try! String(contentsOf: name).replacingOccurrences(of: "<svg", with: "<svg " + a.asAttributes)
return .raw(contents)
}
}
static func markdown(_ string: String) -> Node {
return Node.raw(CommonMark.Node(markdown: string)!.html(options: [.unsafe]))
}
}