Add the final layouts drag and drop impl.

This commit is contained in:
Andrey Antukh 2016-02-01 23:25:37 +02:00
parent 2b74c34c00
commit d238166405
2 changed files with 105 additions and 60 deletions

View file

@ -377,11 +377,18 @@
(rx/from-coll (rx/from-coll
(map unlock-shape (:items shape)))))))) (map unlock-shape (:items shape))))))))
;; FIXME: the impl can be maybe simplified.
(defn transfer-shape (defn transfer-shape
"Event used in drag and drop for transfer shape "Event used in drag and drop for transfer shape
from one position to an other." from one position to an other."
[sid tid type] [sid tid type]
(letfn [(transfer-to-group [state target]) (letfn [(transfer-to-group [state {:keys [id] :as target}]
(let [shapes (get-in state [:shapes-by-id id :items])
shapes (conj shapes sid)]
(as-> state $
(assoc-in $ [:shapes-by-id id :items] shapes)
(update-in $ [:shapes-by-id sid] assoc :group id))))
(transfer-at [index shapes sid] (transfer-at [index shapes sid]
(let [[fst snd] (split-at index shapes)] (let [[fst snd] (split-at index shapes)]
@ -426,18 +433,24 @@
(reify (reify
rs/UpdateEvent rs/UpdateEvent
(-apply-update [_ state] (-apply-update [_ state]
(let [target (get-in state [:shapes-by-id tid]) (if (= tid sid)
source (get-in state [:shapes-by-id sid]) state
state (remove-source state source)] (let [target (get-in state [:shapes-by-id tid])
(cond source (get-in state [:shapes-by-id sid])
(and (= type :inside) (:group target)) state (remove-source state source)]
(transfer-to-group state target) (cond
(and (= type :inside)
(= (:type target) :builtin/group))
(transfer-to-group state target)
(= type :before) (= type :before)
(transfer-before state target) (transfer-before state target)
(= type :after) (= type :after)
(transfer-after state target))))))) (transfer-after state target)
:else
(throw (ex-info "Invalid data" {})))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Events (for selected) ;; Events (for selected)

View file

@ -14,6 +14,7 @@
[uxbox.ui.workspace.base :as wb] [uxbox.ui.workspace.base :as wb]
[uxbox.ui.icons :as i] [uxbox.ui.icons :as i]
[uxbox.ui.mixins :as mx] [uxbox.ui.mixins :as mx]
[uxbox.util.dom.dnd :as dnd]
[uxbox.util.dom :as dom]) [uxbox.util.dom :as dom])
(:import goog.events.EventType)) (:import goog.events.EventType))
@ -115,36 +116,30 @@
toggle-visibility #(toggle-visibility selected item %) toggle-visibility #(toggle-visibility selected item %)
toggle-blocking #(toggle-blocking item %) toggle-blocking #(toggle-blocking item %)
local (:rum/local own) local (:rum/local own)
classes (classnames classes (classnames
:selected selected? :selected selected?
:drag-top (= :top (:over @local)) :drag-top (= :top (:over @local))
:drag-bottom (= :bottom (:over @local)) :drag-bottom (= :bottom (:over @local))
:drag-inside (= :middle (:over @local)))] :drag-inside (= :middle (:over @local)))]
(letfn [(on-drag-start [event] (letfn [(on-drag-start [event]
(let [target (.-target event) (let [target (dom/event->target event)]
style (.-style target) (dnd/set-allowed-effect! event "move")
dt (.-dataTransfer event)] (dnd/set-data! event (:id item))
(set! (.-effectAllowed dt) "move")
(.setData dt "item/uuid" (pr-str (:id item)))
(swap! local assoc :dragging true))) (swap! local assoc :dragging true)))
(on-drag-end [event] (on-drag-end [event]
(swap! local assoc :dragging false :over nil)) (swap! local assoc :dragging false :over nil))
(on-drop [event] (on-drop [event]
(let [dt (.-dataTransfer event) (dom/stop-propagation event)
id (read-string (.getData dt "item/uuid")) (let [id (dnd/get-data event)
over (:over @local)] over (:over @local)]
(case (:over @local) (case (:over @local)
:top (rs/emit! (dw/transfer-shape id (:id item) :before)) :top (rs/emit! (dw/transfer-shape id (:id item) :before))
:bottom (rs/emit! (dw/transfer-shape id (:id item) :after)) :bottom (rs/emit! (dw/transfer-shape id (:id item) :after)))
;; :middle (rs/emit! (dw/transfer-inside id (:id item)))
)
(swap! local assoc :dragging false :over nil))) (swap! local assoc :dragging false :over nil)))
(on-drag-over [event] (on-drag-over [event]
(dom/prevent-default event) (dom/prevent-default event)
(let [dt (.-dataTransfer event) (dnd/set-drop-effect! event "move")
over (get-hover-position event false)] (let [over (get-hover-position event false)]
(set! (.-dropEffect dt) "move")
(swap! local assoc :over over))) (swap! local assoc :over over)))
(on-drag-enter [event] (on-drag-enter [event]
(swap! local assoc :over true)) (swap! local assoc :over true))
@ -159,7 +154,6 @@
:on-drag-over on-drag-over :on-drag-over on-drag-over
:on-drag-end on-drag-end :on-drag-end on-drag-end
:on-drop on-drop :on-drop on-drop
:data-over (str (:over @local))
:draggable true :draggable true
:class (when selected? "selected")} :class (when selected? "selected")}
[:div.element-list-body [:div.element-list-body
@ -198,40 +192,78 @@
toggle-open (fn [event] toggle-open (fn [event]
(dom/stop-propagation event) (dom/stop-propagation event)
(swap! local assoc :open (not open?))) (swap! local assoc :open (not open?)))
shapes-by-id (rum/react wb/shapes-by-id-l)] shapes-by-id (rum/react wb/shapes-by-id-l)
(html classes (classnames
[:li.group {:class (when open? "open") :draggable true} :selected selected?
[:div.element-list-body :drag-top (= :top (:over @local))
{:class (when selected? "selected") :drag-bottom (= :bottom (:over @local))
:on-click select} :drag-inside (= :middle (:over @local)))]
[:div.element-actions (letfn [(on-drag-start [event]
[:div.toggle-element (let [target (dom/event->target event)]
{:class (when-not (:hidden item) "selected") (dnd/set-allowed-effect! event "move")
:on-click toggle-visibility} (dnd/set-data! event (:id item))
i/eye] (swap! local assoc :dragging true)))
[:div.block-element (on-drag-end [event]
{:class (when (:blocked item) "selected") (swap! local assoc :dragging false :over nil))
:on-click toggle-blocking} (on-drop [event]
i/lock] (dom/stop-propagation event)
[:div.chain-element (let [id (dnd/get-data event)
{:class (when (:locked item) "selected") over (:over @local)]
:on-click toggle-locking} (case (:over @local)
i/chain]] :top (rs/emit! (dw/transfer-shape id (:id item) :before))
[:div.element-icon i/folder] :bottom (rs/emit! (dw/transfer-shape id (:id item) :after))
[:span (:name item "Unnamed group")] :middle (rs/emit! (dw/transfer-shape id (:id item) :inside)))
[:span.toggle-content (swap! local assoc :dragging false :over nil)))
{:on-click toggle-open (on-drag-over [event]
:class (when open? "inverse")} (dom/prevent-default event)
i/arrow-slide]] (dnd/set-drop-effect! event "move")
(if open? (let [over (get-hover-position event true)]
[:ul (swap! local assoc :over over)))
(for [shape (map #(get shapes-by-id %) (:items item)) (on-drag-enter [event]
:let [key (str (:id shape))]] (swap! local assoc :over true))
(if (= (:type shape) :builtin/group) (on-drag-leave [event]
(-> (layer-group shape selected) (swap! local assoc :over false))]
(rum/with-key key)) (html
(-> (layer-element shape selected) [:li.group {:class (when open? "open")
(rum/with-key key))))])]))) :key (str (:id item))
:draggable true}
[:div.element-list-body
{:class classes
:on-drag-start on-drag-start
:on-drag-enter on-drag-enter
:on-drag-leave on-drag-leave
:on-drag-over on-drag-over
:on-drag-end on-drag-end
:on-drop on-drop
:on-click select}
[:div.element-actions
[:div.toggle-element
{:class (when-not (:hidden item) "selected")
:on-click toggle-visibility}
i/eye]
[:div.block-element
{:class (when (:blocked item) "selected")
:on-click toggle-blocking}
i/lock]
[:div.chain-element
{:class (when (:locked item) "selected")
:on-click toggle-locking}
i/chain]]
[:div.element-icon i/folder]
[:span (:name item "Unnamed group")]
[:span.toggle-content
{:on-click toggle-open
:class (when open? "inverse")}
i/arrow-slide]]
(if open?
[:ul
(for [shape (map #(get shapes-by-id %) (:items item))
:let [key (str (:id shape))]]
(if (= (:type shape) :builtin/group)
(-> (layer-group shape selected)
(rum/with-key key))
(-> (layer-element shape selected)
(rum/with-key key))))])]))))
(def ^:static ^:private layer-group (def ^:static ^:private layer-group
(mx/component (mx/component