Skip to content

Instantly share code, notes, and snippets.

@trikitrok
Last active April 26, 2018 18:31
Show Gist options
  • Save trikitrok/03ed9b48d3e9f4942a60a5810347793e to your computer and use it in GitHub Desktop.
Save trikitrok/03ed9b48d3e9f4942a60a5810347793e to your computer and use it in GitHub Desktop.
(ns horizon.controls.widgets.tree.hierarchy
(:require
[horizon.common.utils.coeffects.extraction :as coeffects.extraction]
[horizon.common.utils.coeffects.factories :as coeffects]
[horizon.common.utils.effects.processing :as effects.processing]
[horizon.common.utils.keys-pressed :as kp]
[horizon.controls.utils.css-transitions-group :as css-transitions-group :include-macros true]
[horizon.controls.utils.icons :as icons]
[horizon.controls.utils.reactive :as utils.reactive]
[horizon.controls.widgets.mdl :as mdl]
[horizon.controls.widgets.tree.hierarchy-helpers :as tree.hierarchy-helpers]
[om.core :as om :include-macros true]
[om.dom :include-macros true]
[sablono.core :refer-macros [html]])
(:require-macros
[horizon.common.macros :refer [defhandler]]))
(defhandler expand-node [e channel expanded-nodes-ids node-id expanded?]
(effects.processing/process-all!
(tree.hierarchy-helpers/expand-nodes-effects
channel expanded? expanded-nodes-ids node-id)))
(defhandler select-node [e channel value]
(effects.processing/process-all!
(tree.hierarchy-helpers/select-node-effects channel value)))
(defhandler select-alert [e channel value]
(effects.processing/process-all!
(tree.hierarchy-helpers/select-alert-effects channel value)))
(defn handle-branch-channel-messages [tree-channel msg]
(effects.processing/process-all!
(tree.hierarchy-helpers/branch-channel-messages-effects
tree-channel msg)))
(defn- get-expanded-nodes-from-dom []
(let [expanded-html-nodes (vec (array-seq (js->clj (.getElementsByClassName js/document "device-name"))))]
(mapv #(hash-map :id (.-id (.-dataset %)) :name (.-name (.-dataset %))) expanded-html-nodes)))
(defn- extracting-data [owner]
(coeffects.extraction/extract-all!
[(coeffects/om-state owner [:shift-selection :selected :pressed-keys])
(coeffects/arbitrary-fn :expanded-nodes get-expanded-nodes-from-dom)]))
(defn- handle-tree-channel-messages [owner channel msg]
(effects.processing/process-all!
(tree.hierarchy-helpers/tree-channel-messages-effects owner
channel
msg
#(extracting-data owner))))
(defn- info-view [{:keys [level expanded info-data num-children selected]} owner branch-channel]
(reify
om/IRender
(render [_]
(let [{node-id :NodeId icon-type :IconType severity :Severity node-name :NodeName title
:Title node-alerts :Alerts} info-data
expanded? (contains? expanded node-id)
icon (icons/build-icon-class icon-type)
icon-color (icons/build-icon-color severity)
node-class (tree.hierarchy-helpers/select-node-classes selected node-id level num-children)]
(html
[:div
(if (zero? num-children)
{:class node-class
:on-click #(select-node % branch-channel {:id node-id
:name node-name})}
{:class node-class})
(if (pos? num-children)
[:div.expander
{:on-click #(expand-node % branch-channel expanded node-id expanded?)}
(mdl/button
{:icon (if expanded?
[:i.fa.fa-minus]
[:i.fa.fa-plus])})]
[:div.dummy-expander])
[:div.alert-icon
(when (some? icon-type)
(mdl/button
{:title title
:on-click #(select-alert % branch-channel node-alerts)
:icon [:i {:class icon :style {:color icon-color}}]}))]
[:div.device-name
{:data-id node-id
:data-name node-name}
node-name]])))))
(defn- branch-view
[{node-id :NodeId nodes :Nodes :as data} owner {:keys [level tree-channel]}]
(reify
om/IInitState
(init-state [_]
{:expanded false
:selected false
:branch-channel (utils.reactive/build-channel-loop
#(handle-branch-channel-messages tree-channel %))})
om/IRenderState
(render-state [_ {:keys [expanded branch-channel selected]}]
(html
[:div.branch-container
(let [num-branches (count nodes)]
(list
(om/build info-view
{:expanded expanded
:level level
:info-data data
:selected selected
:num-children num-branches}
{:opts branch-channel})
(css-transitions-group/with-transition
:rim-list
(when (and (pos? num-branches)
(contains? expanded node-id))
(om/build-all branch-view
nodes
{:opts {:level (inc level)
:tree-channel tree-channel}
:state {:selected selected
:expanded expanded}})))))]))))
(defn- set-state-pressed-keys [owner keys]
(om/set-state! owner :pressed-keys (set keys)))
(defn main-view [{:keys [values expanded selected view]} owner channel]
(reify
om/IInitState
(init-state [_]
{:shift-selection nil
:pressed-keys #{}
:selected selected
:tree-channel (utils.reactive/build-channel-loop
#(handle-tree-channel-messages owner channel %))})
om/IDidMount
(did-mount [_]
(kp/listen-to-pressed-keys
#{:control :shift}
#(set-state-pressed-keys owner %)
:tree-view-listen-pressed-keys))
om/IWillUnmount
(will-unmount [_]
(kp/unlisten-to-pressed-keys :tree-view-listen-pressed-keys))
om/IRenderState
(render-state [_ {:keys [tree-channel selected]}]
(html
[:div.tree-hierarchy-container
(om/build branch-view
values
{:opts {:level 0
:tree-channel tree-channel
:view view}
:state {:selected selected
:expanded expanded}})]))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment