diff --git a/src/uxbox/data/workspace.cljs b/src/uxbox/data/workspace.cljs index c7dd0b8da..5349749b6 100644 --- a/src/uxbox/data/workspace.cljs +++ b/src/uxbox/data/workspace.cljs @@ -8,7 +8,8 @@ [uxbox.schema :as sc] [uxbox.time :as time] [uxbox.xforms :as xf] - [uxbox.shapes :as sh])) + [uxbox.shapes :as sh] + [uxbox.util.data :refer (index-of)])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Schemas @@ -376,6 +377,40 @@ (rx/from-coll (map unlock-shape (:items shape)))))))) +(defn transfer-after + "Event used in drag and drop for transfer shape + from one position to an other." + [sid tid] + (reify + rs/UpdateEvent + (-apply-update [_ state] + (let [sitem (get-in state [:shapes-by-id sid]) + titem (get-in state [:shapes-by-id tid]) + page (get-in state [:pages-by-id (:page titem)]) + index (index-of (:shapes page) tid) + [fst snd] (split-at (inc index) (:shapes page)) + + fst (remove #(= % sid) fst) + snd (remove #(= % sid) snd) + + items (concat fst [sid] snd)] + (assoc-in state [:pages-by-id (:page titem) :shapes] items))))) + +(defn transfer-before + [sid tid] + (reify + rs/UpdateEvent + (-apply-update [_ state] + (let [sitem (get-in state [:shapes-by-id sid]) + titem (get-in state [:shapes-by-id tid]) + page (get-in state [:pages-by-id (:page titem)]) + index (index-of (:shapes page) tid) + [fst snd] (split-at index (:shapes page)) + fst (remove #(= % sid) fst) + snd (remove #(= % sid) snd) + items (concat fst [sid] snd)] + (assoc-in state [:pages-by-id (:page titem) :shapes] items))))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Events (for selected) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/src/uxbox/ui/workspace/toolboxes/layers.cljs b/src/uxbox/ui/workspace/toolboxes/layers.cljs index 0d18ddc1c..e362865ef 100644 --- a/src/uxbox/ui/workspace/toolboxes/layers.cljs +++ b/src/uxbox/ui/workspace/toolboxes/layers.cljs @@ -1,18 +1,21 @@ (ns uxbox.ui.workspace.toolboxes.layers + (:require-macros [uxbox.util.syntax :refer (defer)]) (:require [sablono.core :as html :refer-macros [html]] [rum.core :as rum] [cats.labs.lens :as l] + [goog.events :as events] [uxbox.router :as r] [uxbox.rstore :as rs] [uxbox.state :as st] [uxbox.shapes :as shapes] [uxbox.library :as library] - [uxbox.util.data :refer (read-string)] + [uxbox.util.data :refer (read-string classnames)] [uxbox.data.workspace :as dw] [uxbox.ui.workspace.base :as wb] [uxbox.ui.icons :as i] [uxbox.ui.mixins :as mx] - [uxbox.ui.dom :as dom])) + [uxbox.ui.dom :as dom]) + (:import goog.events.EventType)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Lenses @@ -88,37 +91,98 @@ :builtin/rect i/box :builtin/group i/folder)) + +(defn- get-hover-position + [event group?] + (let [target (.-currentTarget event) + brect (.getBoundingClientRect target) + width (.-offsetHeight target) + y (- (.-clientY event) (.-top brect)) + part (/ (* 30 width) 100)] + (if group? + (cond + (> part y) :top + (< (- width part) y) :bottom + :else :middle) + (if (>= y (/ width 2)) + :bottom + :top)))) + (defn- layer-element-render [own item selected] (let [selected? (contains? selected (:id item)) select #(select-shape selected item %) toggle-visibility #(toggle-visibility selected item %) - toggle-blocking #(toggle-blocking item %)] - (html - [:li {:key (str (:id item)) - :on-click select - :class (when selected? "selected")} - [:div.element-list-body - {:class (when selected? "selected")} - [: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]] - (if (:group item) - [:div.sublevel-element i/sublevel]) - [:div.element-icon (element-icon item)] - [:span (:name item "Unnamed")]]]))) + toggle-blocking #(toggle-blocking item %) + local (:rum/local own) + + classes (classnames + :selected selected? + :drag-top (= :top (:over @local)) + :drag-bottom (= :bottom (:over @local)) + :drag-inside (= :middle (:over @local)))] + (letfn [(on-drag-start [event] + (let [target (.-target event) + style (.-style target) + dt (.-dataTransfer event)] + (set! (.-effectAllowed dt) "move") + (.setData dt "item/uuid" (pr-str (:id item))) + (swap! local assoc :dragging true))) + (on-drag-end [event] + (swap! local assoc :dragging false :over nil)) + (on-drop [event] + (let [dt (.-dataTransfer event) + id (read-string (.getData dt "item/uuid")) + over (:over @local)] + (case (:over @local) + :top (rs/emit! (dw/transfer-before id (:id item))) + :bottom (rs/emit! (dw/transfer-after id (:id item))) + ;; :middle (rs/emit! (dw/transfer-inside id (:id item))) + ) + (swap! local assoc :dragging false :over nil))) + (on-drag-over [event] + (dom/prevent-default event) + (let [dt (.-dataTransfer event) + over (get-hover-position event (:group item))] + (set! (.-dropEffect dt) "move") + (swap! local assoc :over over))) + (on-drag-enter [event] + (swap! local assoc :over true)) + (on-drag-leave [event] + (swap! local assoc :over false))] + (html + [:li {:key (str (:id item)) + :on-click select + :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 + :data-over (str (:over @local)) + :draggable true + :class (when selected? "selected")} + [:div.element-list-body + {:class classes} + [: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]] + (if (:group item) + [:div.sublevel-element i/sublevel]) + [:div.element-icon (element-icon item)] + [:span (:name item "Unnamed")]]])))) (def ^:static ^:private layer-element (mx/component {:render layer-element-render :name "layer-element" - :mixins [mx/static]})) + :mixins [mx/static (mx/local)]})) (declare layer-group) @@ -136,7 +200,7 @@ (swap! local assoc :open (not open?))) shapes-by-id (rum/react wb/shapes-by-id-l)] (html - [:li.group {:class (when open? "open")} + [:li.group {:class (when open? "open") :draggable true} [:div.element-list-body {:class (when selected? "selected") :on-click select} @@ -175,6 +239,63 @@ :name "layer-group" :mixins [mx/static rum/reactive (mx/local)]})) + +;; (defn layers-did-mount +;; [own local] +;; (let [rootel (mx/get-ref-dom own "rootel") +;; dragel (volatile! nil)] +;; (letfn [(on-drag-start [event] +;; (println "on-drag-start") +;; (js/console.log (.getBrowserEvent event)) +;; (let [event (.getBrowserEvent event) +;; target (.-target event) +;; dt (.-dataTransfer event)] +;; (vreset! dragel target) +;; (set! (.-effectAllowed dt) "move") + +;; (events/listen rootel EventType.DRAGOVER on-drag-over) +;; (events/listen rootel EventType.DRAGEND on-drag-end) + +;; (.setData dt "Text" (.-textContent target)) +;; (defer +;; (let [clist (.-classList target)] +;; (.add clist "ghost"))))) + +;; (on-drag-over [event] +;; (dom/prevent-default event) +;; (let [event (.getBrowserEvent event) +;; dt (.-dataTransfer event) +;; target (.-target event)] +;; (set! (.-dropEffect dt) "move") +;; (println "kaka" (.-nodeName target)) +;; (when (and target (not= target @dragel)) +;; (.insertBefore rootel @dragel (or (.-nextSibling target) +;; target))))) +;; (on-drag-end [event] +;; (println "drag end") +;; (dom/prevent-default event) + +;; (events/unlisten rootel EventType.DRAGEND on-drag-end) +;; (events/unlisten rootel EventType.DRAGOVER on-drag-over) + +;; (let [cl (.-classList @dragel)] +;; (.remove cl "ghost") +;; (println "on-drag-end")))] +;; (assoc own ::key +;; (events/listen rootel EventType.DRAGSTART on-drag-start))))) + + +;; (defn layers-will-unmount +;; [own local] +;; (let [key (::key own)] +;; (events/unlistenByKey key) +;; (dissoc own ::key))) + +;; (defn layers-transfer-state +;; [old-own own] +;; (let [key (::key old-own)] +;; (assoc own ::key key))) + (defn layers-render [own] (let [workspace (rum/react wb/workspace-l) @@ -184,7 +305,8 @@ close #(rs/emit! (dw/toggle-toolbox :layers)) ;; copy #(rs/emit! (dw/copy-selected)) group #(rs/emit! (dw/group-selected)) - delete #(rs/emit! (dw/delete-selected))] + delete #(rs/emit! (dw/delete-selected)) + dragel (volatile! nil)] (html [:div#layers.tool-window [:div.tool-window-bar @@ -192,7 +314,10 @@ [:span "Layers"] [:div.tool-window-close {:on-click close} i/close]] [:div.tool-window-content - [:ul.element-list + [:ul.element-list {;;:onDragStart on-drag-start + ;;:onDragOver on-drag-over + ;;:onDragEnd on-drag-end + :ref "rootel"} (for [shape (map #(get shapes-by-id %) (:shapes page)) :let [key (str (:id shape))]] (if (= (:type shape) :builtin/group) @@ -209,6 +334,9 @@ (def ^:static layers-toolbox (mx/component {:render layers-render + ;; :did-mount layers-did-mount + ;; :will-unmount layers-will-unmount + ;; :transfer-state layers-transfer-state :name "layers" :mixins [rum/reactive]})) diff --git a/src/uxbox/util/syntax.cljc b/src/uxbox/util/syntax.cljc index cb9fe57cd..f7d3094fb 100644 --- a/src/uxbox/util/syntax.cljc +++ b/src/uxbox/util/syntax.cljc @@ -6,3 +6,8 @@ (let [sym (symbol (str (namespace name') "-" (name name')))] `(cljs.core/defonce ~sym (do ~@body nil)))) + +(defmacro defer + [& body] + `(let [func# (fn [] ~@body)] + (js/setTimeout func# 0)))