/
util.clj
125 lines (105 loc) · 3.22 KB
/
util.clj
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
(ns hiccup.util
"Utility functions for Hiccup."
(:require [clojure.string :as str])
(:import java.net.URI
java.net.URLEncoder))
(def ^:dynamic ^:no-doc *html-mode* :xhtml)
(def ^:dynamic ^:no-doc *escape-strings?* true)
(def ^:dynamic ^:no-doc *base-url* nil)
(def ^:dynamic ^:no-doc *encoding* "UTF-8")
(defmacro with-base-url
"Sets a base URL that will be prepended onto relative URIs. Note that for this
to work correctly, it needs to be placed outside the [[hiccup.core/html]] or
[[hiccup2.core/html]] macros."
[base-url & body]
`(binding [*base-url* ~base-url]
~@body))
(defprotocol ToString
(^String to-str [x] "Convert a value into a string."))
(extend-protocol ToString
clojure.lang.Keyword
(to-str [k] (name k))
clojure.lang.Ratio
(to-str [r] (str (float r)))
java.net.URI
(to-str [u]
(if (or (.getHost u)
(nil? (.getPath u))
(not (-> (.getPath u) (.startsWith "/"))))
(str u)
(let [base (str *base-url*)]
(if (.endsWith base "/")
(str (subs base 0 (dec (count base))) u)
(str base u)))))
Object
(to-str [x] (str x))
nil
(to-str [_] ""))
(defn ^String as-str
"Converts its arguments into a string using [[to-str]]."
[& xs]
(apply str (map to-str xs)))
(defprotocol ToURI
(^java.net.URI to-uri [x] "Convert a value into a URI."))
(extend-protocol ToURI
java.net.URI
(to-uri [u] u)
String
(to-uri [s] (URI. s)))
(deftype RawString [^String s]
Object
(^String toString [this] s)
(^boolean equals [this other]
(and (instance? RawString other)
(= s (.toString other)))))
(defn raw-string
"Converts one or more strings into an object that will not be escaped when
used with the [[hiccup2.core/html]] macro."
{:arglists '([& xs])}
([] (RawString. ""))
([x] (RawString. (str x)))
([x & xs] (RawString. (apply str x xs))))
(defn raw-string?
"Returns true if x is a RawString created by [[raw-string]]."
[x]
(instance? RawString x))
(defn escape-html
"Change special characters into HTML character entities."
[text]
(.. ^String (as-str text)
(replace "&" "&")
(replace "<" "<")
(replace ">" ">")
(replace "\"" """)
(replace "'" (if (= *html-mode* :sgml) "'" "'"))))
(defmacro with-encoding
"Sets a default encoding for URL encoding strings. Defaults to UTF-8."
[encoding & body]
`(binding [*encoding* ~encoding]
~@body))
(defprotocol URLEncode
(url-encode [x] "Turn a value into a URL-encoded string."))
(extend-protocol URLEncode
String
(url-encode [s] (URLEncoder/encode ^String s ^String *encoding*))
java.util.Map
(url-encode [m]
(str/join "&"
(for [[k v] m]
(str (url-encode k) "=" (url-encode v)))))
Object
(url-encode [x] (url-encode (to-str x)))
nil
(url-encode [x] ""))
(defn url
"Creates a URI instance from a variable list of arguments and an optional
parameter map as the last argument. For example:
(url \"/group/\" 4 \"/products\" {:page 9})
=> \"/group/4/products?page=9\""
[& args]
(let [params (last args), args (butlast args)]
(to-uri
(str (apply str args)
(if (map? params)
(str "?" (url-encode params))
params)))))