-
Notifications
You must be signed in to change notification settings - Fork 8
/
string.cljc
82 lines (67 loc) · 2.3 KB
/
string.cljc
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
(ns dumdom.string
(:require [clojure.string :as str]
[dumdom.element :as e]
[dumdom.dom :as d]))
(defn- tag-name [node]
#?(:cljs (.-sel node)
:clj (:tag-name node)))
(defn- children [node]
#?(:cljs (.-children node)
:clj (:children node)))
(defn- attributes [node]
#?(:cljs (merge (js->clj (.. node -data -attrs)) (js->clj (.. node -data -props)))
:clj (:attributes node)))
(defn- el-key [node]
#?(:cljs (.. node -key)
:clj (:key node)))
(defn- style [node]
#?(:cljs (js->clj (.. node -data -style))
:clj (:style node)))
(defn- text-node? [vnode]
#?(:cljs (nil? (.-sel vnode))
:clj (not (map? vnode))))
(defn- text [vnode]
#?(:cljs (.-text vnode)
:clj vnode))
(defn- kebab-case [s]
(str/lower-case (str/replace s #"([a-z])([A-Z])" "$1-$2")))
(defn- render-styles [styles]
(if (string? styles)
styles
(->> styles
(remove (comp nil? second))
(map (fn [[k v]] (str (kebab-case (name k)) ": " v)))
(str/join "; "))))
(defn- escape [s]
(-> s
(str/replace #"&(?!([a-z]+|#\d+);)" "&")
(str/replace #"\"" """)))
(defn- attrs [vnode]
(let [k (el-key vnode)
attributes (cond-> (dissoc (attributes vnode) :innerHTML "innerHTML")
k (assoc :data-dumdom-key (escape (pr-str k))))
style (style vnode)]
(->> (merge attributes
(when style
{:style (render-styles style)}))
(map (fn [[k v]] (str " " (name k) "=\"" v "\"")))
(str/join ""))))
(def ^:private self-closing
#{"area" "base" "br" "col" "embed" "hr" "img" "input"
"link" "meta" "param" "source" "track" "wbr"})
(defn- closing-tag [tag-name]
(when-not (self-closing tag-name)
(str "</" tag-name ">")))
(defn- dom-str [vnode]
(cond
(nil? vnode) ""
(text-node? vnode) (text vnode)
:default (str "<" (tag-name vnode) (attrs vnode) ">"
(let [attrs (attributes vnode)]
(or (get attrs :innerHTML)
(get attrs "innerHTML")
(str/join "" (map dom-str (children vnode)))))
(closing-tag (tag-name vnode)))))
(defn render [component & [path k]]
(let [component (e/inflate-hiccup d/render component)]
(dom-str (component (or path []) (or k 0)))))