(ns figwheel.client.heads-up
(:require
[clojure.string :as string]
[figwheel.client.socket :as socket]
[figwheel.client.utils :as utils]
[cljs.core.async :refer [put! chan (.-body js/document)
(.appendChild el))))
{ :container-el (.getElementById js/document cont-id)
:content-area-el (.getElementById js/document content-id) }
))
(defn set-style! [{:keys [container-el]} st-map]
(mapv
(fn [[k v]]
(gobj/set (.-style container-el) (name k) v))
st-map))
(defn set-content! [{:keys [content-area-el] :as c} dom-str]
(set! (.-innerHTML content-area-el) dom-str))
(defn get-content [{:keys [content-area-el]}]
(.-innerHTML content-area-el))
(defn close-link []
(str ""
"x"
""))
(defn display-heads-up [style msg]
(go
(let [c (ensure-container)]
(set-style! c (merge {
:paddingTop "10px"
:paddingBottom "10px"
:width "100%"
:minHeight "68px"
:opacity "1.0" }
style))
(set-content! c msg)
("
s
" "
sub-head
"")))
(defn file-selector-div [file-name line-number column-number msg]
(str "
" msg "
"))
(defn format-line [msg {:keys [file line column]}]
(let [msg (goog.string/htmlEscape msg)]
(if (or file line)
(file-selector-div file line column msg)
(str "" msg "
"))))
(defn escape [x]
(goog.string/htmlEscape x))
(defn pad-line-number [n line-number]
(let [len (count ((fnil str "") line-number))]
(-> (if (< len n)
(apply str (repeat (- n len) " "))
"")
(str line-number))))
(defn inline-error-line [style line-number line]
(str "" "" line-number " " (escape line) ""))
(defn format-inline-error-line [[typ line-number line]]
(condp = typ
:code-line (inline-error-line "color: #999;" line-number line)
:error-in-code (inline-error-line "color: #ccc; font-weight: bold;" line-number line)
:error-message (inline-error-line "color: #D07D7D;" line-number line)
(inline-error-line "color: #666;" line-number line)))
(defn pad-line-numbers [inline-error]
(let [max-line-number-length (count (str (reduce max (map second inline-error))))]
(map #(update-in % [1]
(partial pad-line-number max-line-number-length)) inline-error)))
(defn format-inline-error [inline-error]
(let [lines (map format-inline-error-line (pad-line-numbers inline-error))]
(str ""
(string/join "\n" lines)
"
")))
(def flatten-exception #(take-while some? (iterate :cause %)))
(defn exception->display-data [{:keys [failed-loading-clj-file
failed-compiling
reader-exception
analysis-exception
display-ex-data
class file line column message
error-inline] :as exception}]
(let [last-message (cond
(and file line)
(str "Please see line " line " of file " file )
file (str "Please see " file)
:else nil)]
{:head (cond
failed-loading-clj-file "Couldn't load Clojure file"
analysis-exception "Could not Analyze"
reader-exception "Could not Read"
failed-compiling "Could not Compile"
:else "Compile Exception")
:sub-head file
:messages (concat
(map
#(str "" % "
")
(if message
[(str (if class
(str (escape class)
": ") "")
"" (escape message) "")
(when display-ex-data
(str "" (utils/pprint-to-string display-ex-data) "
"))
(when (pos? (count error-inline))
(format-inline-error error-inline))]
(map #(str (escape (:class %))
": " (escape (:message %))) (flatten-exception (:exception-data exception)))))
(when last-message [(str "" (escape last-message) "
")]))
:file file
:line line
:column column}))
(defn auto-notify-source-file-line [{:keys [file line column]}]
(socket/send! {:figwheel-event "file-selected"
:file-name (str file)
:file-line (str line)
:file-column (str column)}))
(defn display-exception [exception-data]
(let [{:keys [head
sub-head
messages
last-message
file
line
column]}
(-> exception-data
exception->display-data)
msg (apply str messages
#_(map #(str "" (goog.string/htmlEscape %)
"
") messages))]
(display-heads-up {:backgroundColor "rgba(255, 161, 161, 0.95)"}
(str (close-link)
(heading head sub-head)
(file-selector-div file line column msg)))))
(defn warning-data->display-data [{:keys [file line column message error-inline] :as warning-data}]
(let [last-message (cond
(and file line)
(str "Please see line " line " of file " file )
file (str "Please see " file)
:else nil)]
{:head "Compile Warning"
:sub-head file
:messages (concat
(map
#(str "" % "
")
[(when message
(str "" (escape message) ""))
(when (pos? (count error-inline))
(format-inline-error error-inline))])
(when last-message
[(str "" (escape last-message) "
")]))
:file file
:line line
:column column}))
(defn display-system-warning [header msg]
(display-heads-up {:backgroundColor "rgba(255, 220, 110, 0.95)" }
(str (close-link) (heading header)
"" msg "
"
#_(format-line msg {}))))
(defn display-warning [warning-data]
(let [{:keys [head
sub-head
messages
last-message
file
line
column]}
(-> warning-data
warning-data->display-data)
msg (apply str messages)]
(display-heads-up {:backgroundColor "rgba(255, 220, 110, 0.95)" }
(str (close-link)
(heading head sub-head)
(file-selector-div file line column msg)))))
(defn format-warning-message [{:keys [message file line column] :as warning-data}]
(cond-> message
line (str " at line " line)
(and line column) (str ", column " column)
file (str " in file " file)) )
(defn append-warning-message [{:keys [message file line column] :as warning-data}]
(when message
(let [{:keys [content-area-el]} (ensure-container)
el (dom/createElement "div")
child-count (.-length (dom/getChildren content-area-el))]
(if (< child-count 6)
(do
(set! (.-innerHTML el)
(format-line (format-warning-message warning-data)
warning-data))
(dom/append content-area-el el))
(when-let [last-child (dom/getLastElementChild content-area-el)]
(if-let [message-count (data/get last-child "figwheel_count")]
(let [message-count (inc (js/parseInt message-count))]
(data/set last-child "figwheel_count" message-count)
(set! (.-innerHTML last-child)
(str message-count " more warnings have not been displayed ...")))
(dom/append
content-area-el
(dom/createDom "div" #js {:data-figwheel_count 1
:style "margin-top: 3px; font-weight: bold"}
"1 more warning that has not been displayed ..."))))))))
(defn clear []
(go
(let [c (ensure-container)]
(set-style! c { :opacity "0.0" })
(
")
;; ---- bad compile helper ui ----
(defn close-bad-compile-screen []
(when-let [el (js/document.getElementById "figwheelFailScreen")]
(dom/removeNode el)))
(defn bad-compile-screen []
(let [body (-> (dom/getElementsByTagNameAndClass "body")
(aget 0))]
(close-bad-compile-screen)
#_(dom/removeChildren body)
(dom/append body
(dom/createDom
"div"
#js {:id "figwheelFailScreen"
:style (str "background-color: rgba(24, 26, 38, 0.95);"
"position: absolute;"
"z-index: 9000;"
"width: 100vw;"
"height: 100vh;"
"top: 0px; left: 0px;"
"font-family: monospace")}
(dom/createDom
"div"
#js {:class "message"
:style (str
"color: #FFF5DB;"
"width: 100vw;"
"margin: auto;"
"margin-top: 10px;"
"text-align: center; "
"padding: 2px 0px;"
"font-size: 13px;"
"position: relative")}
(dom/createDom
"a"
#js {:onclick (fn [e]
(.preventDefault e)
(close-bad-compile-screen))
:href "javascript:"
:style "position: absolute; right: 10px; top: 10px; color: #666"}
"X")
(dom/createDom "h2" #js {:style "color: #FFF5DB"}
"Figwheel Says: Your code didn't compile.")
(dom/createDom "div" #js {:style "font-size: 12px"}
(dom/createDom "p" #js { :style "color: #D07D7D;"}
"Keep trying. This page will auto-refresh when your code compiles successfully.")
))))))