147 lines
4.7 KiB
Clojure
147 lines
4.7 KiB
Clojure
(ns ^:figwheel-no-load figwheel.client.utils
|
|
(:require [clojure.string :as string]
|
|
[goog.string :as gstring]
|
|
[goog.object :as gobj]
|
|
[cljs.reader :refer [read-string]]
|
|
[cljs.pprint :refer [pprint]]
|
|
[goog.userAgent.product :as product])
|
|
(:import [goog.async Deferred]
|
|
[goog.string StringBuffer])
|
|
(:require-macros [figwheel.client.utils :refer [feature?]]))
|
|
|
|
;; don't auto reload this file it will mess up the debug printing
|
|
|
|
(def ^:dynamic *print-debug* false)
|
|
|
|
(defn html-env? [] (not (nil? goog/global.document)))
|
|
|
|
(defn react-native-env? [] (and (exists? goog/global.navigator)
|
|
(= goog/global.navigator.product "ReactNative")))
|
|
|
|
(defn node-env? [] (not (nil? goog/nodeGlobalRequire)))
|
|
|
|
(defn html-or-react-native-env? []
|
|
(or (html-env?) (react-native-env?)))
|
|
|
|
(defn worker-env? [] (and
|
|
(nil? goog/global.document)
|
|
(exists? js/self)
|
|
(exists? (.-importScripts js/self))))
|
|
|
|
(defn host-env? [] (cond (node-env?) :node
|
|
(html-env?) :html
|
|
(react-native-env?) :react-native
|
|
(worker-env?) :worker))
|
|
|
|
(defn base-url-path [] (string/replace goog/basePath #"(.*)goog/" "$1"))
|
|
|
|
;; Custom Event must exist before calling this
|
|
(defn create-custom-event [event-name data]
|
|
(if-not product/IE
|
|
(js/CustomEvent. event-name (js-obj "detail" data))
|
|
;; in windows world
|
|
;; this will probably not work at some point in
|
|
;; newer versions of IE
|
|
(let [event (js/document.createEvent "CustomEvent")]
|
|
(.. event (initCustomEvent event-name false false data))
|
|
event)))
|
|
|
|
;; actually we should probably lift the event system here off the DOM
|
|
;; so that we work well in Node and other environments
|
|
(defn dispatch-custom-event [event-name data]
|
|
(when (and (html-env?) (gobj/get js/window "CustomEvent") (js* "typeof document !== 'undefined'"))
|
|
(.dispatchEvent (.-body js/document)
|
|
(create-custom-event event-name data))))
|
|
|
|
(defn debug-prn [o]
|
|
(when *print-debug*
|
|
(let [o (if (or (map? o)
|
|
(seq? o))
|
|
(prn-str o)
|
|
o)]
|
|
(.log js/console o))))
|
|
|
|
(defn log
|
|
([x] (log :info x))
|
|
([level arg]
|
|
(let [f (condp = (if (html-or-react-native-env?) level :info)
|
|
:warn #(.warn js/console %)
|
|
:debug #(.debug js/console %)
|
|
:error #(.error js/console %)
|
|
#(.log js/console %))]
|
|
(f arg))))
|
|
|
|
(defn eval-helper [code {:keys [eval-fn] :as opts}]
|
|
(if eval-fn
|
|
(eval-fn code opts)
|
|
(js* "eval(~{code})")))
|
|
|
|
(defn pprint-to-string [x]
|
|
(let [sb (StringBuffer.)
|
|
sbw (StringBufferWriter. sb)]
|
|
(pprint x sbw)
|
|
(gstring/trimRight (str sb))))
|
|
|
|
;; Deferred helpers that focus on guaranteed successful side effects
|
|
;; not very monadic but it meets our needs
|
|
|
|
(defn liftContD
|
|
"chains an async action on to a deferred
|
|
Must provide a goog.async.Deferred and action function that
|
|
takes an initial value and a continuation fn to call with the result"
|
|
[deferred f]
|
|
(.then deferred (fn [val]
|
|
(let [new-def (Deferred.)]
|
|
(f val #(.callback new-def %))
|
|
new-def))))
|
|
|
|
(defn mapConcatD
|
|
"maps an async action across a collection and chains the results
|
|
onto a deferred"
|
|
[deferred f coll]
|
|
(let [results (atom [])]
|
|
(.then
|
|
(reduce (fn [defr v]
|
|
(liftContD defr
|
|
(fn [_ fin]
|
|
(f v (fn [v]
|
|
(swap! results conj v)
|
|
(fin v))))))
|
|
deferred coll)
|
|
(fn [_] (.succeed Deferred @results)))))
|
|
|
|
;; persistent storage of configuration keys
|
|
|
|
(defonce local-persistent-config
|
|
(let [a (atom {})]
|
|
(when (feature? js/localStorage "setItem")
|
|
(add-watch a :sync-local-storage
|
|
(fn [_ _ _ n]
|
|
(mapv (fn [[ky v]]
|
|
(.setItem js/localStorage (name ky) (pr-str v)))
|
|
n))))
|
|
a))
|
|
|
|
(defn persistent-config-set!
|
|
"Set a local value on a key that in a browser will persist even when
|
|
the browser gets reloaded."
|
|
[ky v]
|
|
(swap! local-persistent-config assoc ky v))
|
|
|
|
(defn persistent-config-get
|
|
([ky not-found]
|
|
(try
|
|
(cond
|
|
(contains? @local-persistent-config ky)
|
|
(get @local-persistent-config ky)
|
|
(and (feature? js/localStorage "getItem")
|
|
(.getItem js/localStorage (name ky)))
|
|
(let [v (read-string (.getItem js/localStorage (name ky)))]
|
|
(persistent-config-set! ky v)
|
|
v)
|
|
:else not-found)
|
|
(catch js/Error e
|
|
not-found)))
|
|
([ky]
|
|
(persistent-config-get ky nil)))
|