add various clojurescript utility functions
This commit is contained in:
parent
c2a0531f2d
commit
8d65b78703
21
project.clj
21
project.clj
|
@ -4,8 +4,19 @@
|
||||||
:license {:name "MIT License"
|
:license {:name "MIT License"
|
||||||
:url "http://opensource.org/licenses/MIT"}
|
:url "http://opensource.org/licenses/MIT"}
|
||||||
|
|
||||||
:dependencies [[org.clojure/clojure "1.8.0"]
|
:dependencies [[cheshire "5.5.0"]
|
||||||
[compojure "1.4.0" :scope "provided"]
|
[prismatic/schema "1.0.4"]
|
||||||
[ring/ring-core "1.4.0" :scope "provided"]
|
[cljs-ajax "0.5.5"]
|
||||||
[cheshire "5.5.0"]
|
[secretary "1.2.3"]]
|
||||||
[prismatic/schema "1.0.4"]])
|
|
||||||
|
:plugins [[lein-cljsbuild "1.1.3"]]
|
||||||
|
|
||||||
|
:profiles {:provided
|
||||||
|
{:dependencies [[org.clojure/clojure "1.8.0"]
|
||||||
|
[org.clojure/clojurescript "1.8.51"]
|
||||||
|
[compojure "1.4.0"]
|
||||||
|
[ring/ring-core "1.4.0"]]}}
|
||||||
|
|
||||||
|
:cljsbuild {:builds
|
||||||
|
{:main
|
||||||
|
{:source-paths ["src"]}}})
|
||||||
|
|
62
src/webtools/cljs/ajax.cljs
Normal file
62
src/webtools/cljs/ajax.cljs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
(ns webtools.cljs.ajax
|
||||||
|
(:require
|
||||||
|
[clojure.walk :refer [stringify-keys keywordize-keys]]
|
||||||
|
[ajax.core :as ajax]
|
||||||
|
[webtools.cljs.utils :refer [->url get-anti-forgery-token]]))
|
||||||
|
|
||||||
|
(defn add-headers!
|
||||||
|
[headers]
|
||||||
|
(let [headers (stringify-keys headers)
|
||||||
|
interceptor (ajax/to-interceptor
|
||||||
|
{:request #(assoc % :headers (merge (:headers %) headers))})]
|
||||||
|
(swap! ajax/default-interceptors (partial cons interceptor))
|
||||||
|
headers))
|
||||||
|
|
||||||
|
(defn add-csrf-header!
|
||||||
|
[]
|
||||||
|
(let [token (get-anti-forgery-token)]
|
||||||
|
(if token (add-headers! {"X-CSRF-Token" token}))
|
||||||
|
token))
|
||||||
|
|
||||||
|
(defn GET
|
||||||
|
[url & {:keys [format params on-success on-error on-complete keywords? headers]}]
|
||||||
|
(let [url (->url url)
|
||||||
|
json? (or (= :json format)
|
||||||
|
(nil? format))]
|
||||||
|
(ajax/GET url
|
||||||
|
(merge
|
||||||
|
{:format (or format :json)}
|
||||||
|
(if json? {:keywords? (or keywords? true)})
|
||||||
|
(if params {:params params})
|
||||||
|
(if headers {:headers (stringify-keys headers)})
|
||||||
|
(if on-success {:handler on-success})
|
||||||
|
(if on-error {:error-handler on-error})
|
||||||
|
(if on-complete {:finally on-complete})
|
||||||
|
))))
|
||||||
|
|
||||||
|
(defn POST
|
||||||
|
[url & {:keys [format params body on-success on-error on-complete keywords? headers]}]
|
||||||
|
(let [url (->url url)
|
||||||
|
json? (or (= :json format)
|
||||||
|
(nil? format))]
|
||||||
|
(ajax/POST url
|
||||||
|
(merge
|
||||||
|
{:format (or format :json)}
|
||||||
|
(if json? {:keywords? (or keywords? true)})
|
||||||
|
(if params {:params params})
|
||||||
|
(if body {:body body})
|
||||||
|
(if headers {:headers (stringify-keys headers)})
|
||||||
|
(if on-success {:handler on-success})
|
||||||
|
(if on-error {:error-handler on-error})
|
||||||
|
(if on-complete {:finally on-complete})))))
|
||||||
|
|
||||||
|
(defn fetch!
|
||||||
|
[destination-atom url & {:keys [format params keywords? on-error headers transform]}]
|
||||||
|
(let [transform (or transform identity)]
|
||||||
|
(GET url
|
||||||
|
:format format
|
||||||
|
:params params
|
||||||
|
:keywords? keywords?
|
||||||
|
:on-error on-error
|
||||||
|
:headers headers
|
||||||
|
:on-success #(reset! destination-atom (transform %)))))
|
25
src/webtools/cljs/dom.cljs
Normal file
25
src/webtools/cljs/dom.cljs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
(ns webtools.cljs.dom)
|
||||||
|
|
||||||
|
(defn element-by-id
|
||||||
|
[id]
|
||||||
|
(.getElementById js/document id))
|
||||||
|
|
||||||
|
(defn select-all-elements
|
||||||
|
[selector]
|
||||||
|
(vec (.querySelectorAll js/document selector)))
|
||||||
|
|
||||||
|
(defn select-element
|
||||||
|
[selector]
|
||||||
|
(.querySelector js/document selector))
|
||||||
|
|
||||||
|
(defn get-metatag-content
|
||||||
|
[metatag-name]
|
||||||
|
(if-let [tag (select-element (str "meta[name='" metatag-name "']"))]
|
||||||
|
(.-content tag)))
|
||||||
|
|
||||||
|
(defn has-class?
|
||||||
|
[element class-name]
|
||||||
|
(if (.-classList element)
|
||||||
|
(.contains (.-classList element) class-name)
|
||||||
|
(doto (js/RegExp. (str "(^| )" class-name "( |$)") "gi")
|
||||||
|
(.test (.-className element)))))
|
74
src/webtools/cljs/utils.cljs
Normal file
74
src/webtools/cljs/utils.cljs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
(ns webtools.cljs.utils
|
||||||
|
(:import
|
||||||
|
goog.History)
|
||||||
|
(:require
|
||||||
|
[clojure.string :as string]
|
||||||
|
[clojure.walk :refer [keywordize-keys]]
|
||||||
|
[goog.events :as events]
|
||||||
|
[goog.history.EventType :as EventType]
|
||||||
|
[secretary.core :as secretary]
|
||||||
|
[webtools.cljs.dom :as dom]))
|
||||||
|
|
||||||
|
(defn- get-hidden-field-value
|
||||||
|
[hidden-field-id]
|
||||||
|
(if-let [hidden-field (dom/element-by-id hidden-field-id)]
|
||||||
|
(.-value hidden-field)))
|
||||||
|
|
||||||
|
(defn get-anti-forgery-token
|
||||||
|
[]
|
||||||
|
; bunch of common names for this csrf token that i've seen used
|
||||||
|
; ring's own anti-forgery middleware has a helper which outputs
|
||||||
|
; an <input type="hidden"> with the id "__anti-forgery-token"
|
||||||
|
(->> [(dom/get-metatag-content "anti-forgery-token")
|
||||||
|
(dom/get-metatag-content "__anti-forgery-token")
|
||||||
|
(dom/get-metatag-content "csrf-token")
|
||||||
|
(get-hidden-field-value "anti-forgery-token")
|
||||||
|
(get-hidden-field-value "__anti-forgery-token")
|
||||||
|
(get-hidden-field-value "csrf-token")]
|
||||||
|
(remove nil?)
|
||||||
|
(first)))
|
||||||
|
|
||||||
|
(defn dev?
|
||||||
|
[]
|
||||||
|
(if (undefined? js/__isDev)
|
||||||
|
false
|
||||||
|
(boolean js/__isDev)))
|
||||||
|
|
||||||
|
(defn context-url
|
||||||
|
[]
|
||||||
|
(if (undefined? js/__context)
|
||||||
|
""
|
||||||
|
(str js/__context)))
|
||||||
|
|
||||||
|
(defn supports-websockets?
|
||||||
|
[]
|
||||||
|
(not (-> (dom/select-element "html")
|
||||||
|
(dom/has-class? "no-websockets"))))
|
||||||
|
|
||||||
|
(defn old-ie?
|
||||||
|
[]
|
||||||
|
(-> (dom/select-element "html")
|
||||||
|
(dom/has-class? "old-ie")))
|
||||||
|
|
||||||
|
(defn ->url
|
||||||
|
[url]
|
||||||
|
(-> (str (context-url) url)
|
||||||
|
(string/replace #"(/+)" "/")))
|
||||||
|
|
||||||
|
(defn hook-browser-navigation!
|
||||||
|
[]
|
||||||
|
(doto (History.)
|
||||||
|
(events/listen
|
||||||
|
EventType/NAVIGATE
|
||||||
|
(fn [event]
|
||||||
|
(secretary/dispatch! (.-token event))))
|
||||||
|
(.setEnabled true)))
|
||||||
|
|
||||||
|
(defn redirect!
|
||||||
|
[secretary-url]
|
||||||
|
(-> (.-location js/window)
|
||||||
|
(set! secretary-url)))
|
||||||
|
|
||||||
|
(defn pprint-json
|
||||||
|
[x]
|
||||||
|
(.stringify js/JSON (clj->js x) nil " "))
|
Reference in a new issue