/
core.cljs
117 lines (101 loc) · 3.6 KB
/
core.cljs
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
(ns ajenda.core
(:require
[clojure.set :refer [rename-keys]]
[clojure.string :as string]
[clojure.walk :refer [postwalk]]
[reagent.core :as r]
[reagent.dom.server :refer [render-to-static-markup]]))
(defn $ [this]
(-> this r/dom-node js/$))
(defn js->clj-keywordized [v]
(js->clj v :keywordize-keys true))
(defn ->camel-case [s]
(string/replace s #"-{1,}\b." #(when-let [c (last %)] (.toUpperCase c))))
(defn events-handler [calendar f sync?]
(if sync?
(fn [start end timezone callback]
(callback (clj->js (f start end timezone))))
(fn [start end timezone callback]
(f start end timezone #(callback (clj->js %))))))
(defn parse-event [calendar-event]
(some-> (js->clj-keywordized calendar-event)
(rename-keys {:_id :id})
(update :id keyword)))
(defn unparse-event [model-event]
(some-> (rename-keys model-event {:id :_id})
(clj->js)))
(defn save-event [calendar id event]
(if event
(do
(doseq [[k v] (select-keys event [:start :end :tip :title])]
(goog.object/set event (name k) (clj->js v)))
(.fullCalendar calendar "updateEvent" event))
(.fullCalendar calendar "removeEvents" id)))
(defn wrap-event-click
"removes the event from calendar when the click handler returns nil"
[calendar f sync?]
(fn [event js-event view]
(let [id (.-_id event)]
(if sync?
(save-event calendar id (f (keyword id) view))
(f (keyword id) view (fn [event] (save-event calendar id event)))))))
(defn wrap-event-render
"calls the select function and paints the event with the result"
[calendar f sync?]
(fn [event element view]
(f (parse-event event) element view)))
(defn wrap-mouseover [calendar f sync?]
(fn [event js-event view]
(f (parse-event event) view)))
(defn wrap-select [calendar f sync?]
(if sync?
(fn [start end js-event view]
(when-let [event (f start end view)]
(.fullCalendar calendar "renderEvent" (unparse-event event))))
(fn [start end js-event view]
(f start end view
(fn [event]
(when event
(.fullCalendar calendar "renderEvent" (unparse-event event))))))))
(defn camel-case-event-keys [opts]
(postwalk
(fn [node]
(if (keyword? node)
(keyword (->camel-case (name node)))
node))
opts))
(def event-wrappers
{"event-click" wrap-event-click
"event-mouseover" wrap-mouseover
"event-render" wrap-event-render
"select" wrap-select
"events" events-handler})
(defn wrap-event [calendar [k handler]]
(let [key-name (name k)
event-id (string/replace key-name #"-sync$" "")
sync? (string/ends-with? key-name "-sync")
wrapper (get event-wrappers event-id)]
(println k wrapper)
(if wrapper
{(keyword event-id) (wrapper calendar handler sync?)}
{k handler})))
(defn parse-opts [calendar opts]
(-> (reduce
(fn [wrapped-opts event]
(merge wrapped-opts (wrap-event calendar event)))
{}
opts)
(camel-case-event-keys)
(clj->js)))
(defn calendar [opts]
(let []
(r/create-class
{:display-name "calendar"
:component-did-mount (fn [this]
(let [calendar ($ this)]
(.fullCalendar calendar (parse-opts calendar opts))))
:component-did-update (fn [this _]
(-> this $ (.fullCalendar "render")))
:component-will-unmount (fn [this]
(-> this $ (.fullCalendar "destroy")))
:reagent-render (fn [_] [:div.calendar])})))