Skip to content

Instantly share code, notes, and snippets.

@olivergeorge
Created March 23, 2015 21:44
Show Gist options
  • Save olivergeorge/233e961bd7f59b918dd6 to your computer and use it in GitHub Desktop.
Save olivergeorge/233e961bd7f59b918dd6 to your computer and use it in GitHub Desktop.
Rough cut/paste of a modal component
(def ESCAPE-KEY-CODE 27)
(defn handle-key-down [owner e]
"For handling non-printing events"
(if (= ESCAPE-KEY-CODE (.-keyCode e))
(if-let [on-dismiss (:on-dismiss (om/get-props owner))]
(on-dismiss e))))
(defn Modal [props owner]
(reify
om/IDidMount
(did-mount [_]
(let [key-down-callback (fn [e] (handle-key-down owner e))]
(.addEventListener js/window "keydown" key-down-callback)
(om/set-state! owner :key-down-callback key-down-callback)))
om/IWillUnmount
(will-unmount [_]
(.removeEventListener js/window "keydown" (om/get-state owner :key-down-callback)))
om/IRender
(render [_]
(let [{:keys [modal-header modal-body dialog-class
on-save on-cancel on-dismiss ok-copy loading]
:or {on-save identity on-cancel identity on-dismiss identity}} props]
(html [:div.modal-open
[:div.modal.in {:style {:display "block"} :tabIndex -1}
[:div.modal-backdrop.in {:style {:position "fixed"} ;GOTCHA: Large modals / scrolling is messy
:disabled loading
:on-click #(on-dismiss %)}]
[:div.modal-dialog {:class dialog-class}
[:div.modal-content
[:h4.modal-header modal-header
[:button.close {:disabled (not loading) :on-click #(on-dismiss %)}
[:span {:dangerouslySetInnerHTML {:__html "×"}}]]]
[:div.modal-body
(om/build ModalErrorMessage nil)
modal-body]
[:div.modal-footer
(if loading [:span [:span.fa.fa-spinner.fa-spin] " "])
[:button.btn.btn-default {:disabled loading
:on-click #(on-cancel %)} "Cancel"]
[:button.btn.btn-primary {:disabled loading
:on-click #(on-save %)} (or ok-copy "OK")]]]]]])))))
(defn hide-modal! [owner] (om/set-state! owner :show false))
(defn show-modal! [owner] (om/set-state! owner :show true))
(defn handle-modal-show [owner]
(om/set-state! owner :undo-state (.-state app-state))
(show-modal! owner)
nil)
(defn handle-modal-cancel [owner]
(reset! app-state (om/get-state owner :undo-state))
(hide-modal! owner)
nil)
(defn handle-modal-dismiss [owner]
(reset! app-state (om/get-state owner :undo-state))
(hide-modal! owner)
nil)
(defn handle-modal-save [owner]
(let [save-ch (om/get-state owner :save-ch)]
(put! (:pub-chan (om/get-shared owner))
{:topic :save :feedback-ch save-ch})
nil))
(defn UpdateForm [props owner]
(reify
om/IInitState
(init-state [_] {:show false
:saving? false
:save-ch (chan)})
om/IWillMount
(will-mount [_]
(let [save-ch (om/get-state owner :save-ch)
saving! (fn [] (om/set-state! owner :saving? true))
success! (fn [] (hide-modal! owner))
idle! (fn [] (om/set-state! owner :saving? false))]
(go (loop [state :idle]
(when-let [[e v] (<! save-ch)]
(recur (match [state e]
[:idle :saving] (do (saving!) (<! (timeout 1000)) :saving)
[:saving :success] (do (success!) (idle!) :idle)
[:saving :failure] (do (idle!) :idle)
[_ _] state)))))))
om/IRenderState
(render-state [_ {:keys [show saving?]}]
(let [{:keys [modal-header disabled]} props]
(html [:div
(if show (om/build Modal (assoc props
:loading saving?
:ok-copy "OK"
:modal-header [:span [:span.glyphicon.glyphicon-pencil] " " modal-header]
:on-dismiss #(handle-modal-dismiss owner)
:on-save #(handle-modal-save owner)
:on-cancel #(handle-modal-cancel owner))))
[(if disabled :button.btn-default :button.btn-primary)
{:type "button"
:disabled disabled
:class "UpdateButton btn btn-sm"
:style {:position "absolute" :right "1em" :z-index "1"}
:on-click #(handle-modal-show owner)}
[:span.glyphicon.glyphicon-pencil] " Update"]])))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment