diff --git a/backend/deps.edn b/backend/deps.edn index bf334bc38..14ac69459 100644 --- a/backend/deps.edn +++ b/backend/deps.edn @@ -43,6 +43,7 @@ lambdaisland/uri {:mvn/version "1.3.45" :exclusions [org.clojure/data.json]} + frankiesardo/linked {:mvn/version "1.3.0"} danlentz/clj-uuid {:mvn/version "0.1.9"} org.jsoup/jsoup {:mvn/version "1.13.1"} org.im4java/im4java {:mvn/version "1.4.0"} diff --git a/backend/src/uxbox/util/transit.clj b/backend/src/uxbox/util/transit.clj index e1937326d..7a6c2d148 100644 --- a/backend/src/uxbox/util/transit.clj +++ b/backend/src/uxbox/util/transit.clj @@ -2,17 +2,22 @@ ;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; file, You can obtain one at http://mozilla.org/MPL/2.0/. ;; -;; Copyright (c) 2019 Andrey Antukh +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL (ns uxbox.util.transit (:require [cognitect.transit :as t] [clojure.java.io :as io] + [linked.core :as lk] [uxbox.util.time :as dt] [uxbox.util.data :as data] [uxbox.common.geom.point :as gpt] [uxbox.common.geom.matrix :as gmt]) (:import + linked.set.LinkedSet java.io.ByteArrayInputStream java.io.ByteArrayOutputStream java.io.File @@ -42,14 +47,24 @@ (def matrix-read-handler (t/read-handler gmt/map->Matrix)) +(def ordered-set-write-handler + (t/write-handler + (constantly "ordered-set") + (fn [v] (vec v)))) + +(def ordered-set-read-handler + (t/read-handler #(into (lk/set) %))) + (def +read-handlers+ (assoc dt/+read-handlers+ "matrix" matrix-read-handler + "ordered-set" ordered-set-read-handler "point" point-read-handler)) (def +write-handlers+ (assoc dt/+write-handlers+ File file-write-handler + LinkedSet ordered-set-write-handler Matrix matrix-write-handler Point point-write-handler)) diff --git a/common/uxbox/common/data.cljc b/common/uxbox/common/data.cljc index 85694129a..401e1818b 100644 --- a/common/uxbox/common/data.cljc +++ b/common/uxbox/common/data.cljc @@ -8,10 +8,27 @@ "Data manipulation and query helper functions." (:refer-clojure :exclude [concat read-string]) (:require [clojure.set :as set] + [linked.set :as lks] #?(:cljs [cljs.reader :as r] :clj [clojure.edn :as r]) #?(:cljs [cljs.core :as core] - :clj [clojure.core :as core]))) + :clj [clojure.core :as core])) + #?(:clj + (:import linked.set.LinkedSet))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Data Structures +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn ordered-set + ([] lks/empty-linked-set) + ([a] (conj lks/empty-linked-set a)) + ([a & xs] (apply conj lks/empty-linked-set a xs))) + +(defn ordered-set? + [o] + #?(:cljs (instance? lks/LinkedSet o) + :clj (instance? LinkedSet o))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Data Structures Manipulation diff --git a/frontend/deps.edn b/frontend/deps.edn index 5749c14fe..956d696d2 100644 --- a/frontend/deps.edn +++ b/frontend/deps.edn @@ -9,6 +9,7 @@ expound/expound {:mvn/version "0.8.4"} danlentz/clj-uuid {:mvn/version "0.1.9"} + frankiesardo/linked {:mvn/version "1.3.0"} funcool/beicon {:mvn/version "2020.05.08-2"} funcool/cuerdas {:mvn/version "2020.03.26-3"} diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs index 5d75023bc..c2beee199 100644 --- a/frontend/src/uxbox/main/data/workspace.cljs +++ b/frontend/src/uxbox/main/data/workspace.cljs @@ -77,7 +77,7 @@ (def workspace-default {:zoom 1 :flags #{} - :selected #{} + :selected (d/ordered-set) :expanded {} :drawing nil :drawing-tool nil @@ -505,7 +505,7 @@ :id id}] (rx/of (dwc/commit-changes [rchange] [uchange] {:commit-local? true}) - (dws/select-shapes #{id}) + (dws/select-shapes (d/ordered-set id)) (when (= :text (:type attrs)) (start-edition-mode id))))))) @@ -1155,7 +1155,7 @@ selected (->> rchanges (filter #(selected (:old-id %))) (map #(get-in % [:obj :id])) - (into #{}))] + (into (d/ordered-set)))] (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}) (dws/select-shapes selected)))))) @@ -1273,7 +1273,7 @@ uchanges (conj uchanges {:type :del-obj :id id})] (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}) - (dws/select-shapes #{id})))))))) + (dws/select-shapes (d/ordered-set id))))))))) (def ungroup-selected (ptk/reify ::ungroup-selected diff --git a/frontend/src/uxbox/main/data/workspace/selection.cljs b/frontend/src/uxbox/main/data/workspace/selection.cljs index b3564e961..ce04297a8 100644 --- a/frontend/src/uxbox/main/data/workspace/selection.cljs +++ b/frontend/src/uxbox/main/data/workspace/selection.cljs @@ -27,6 +27,9 @@ (s/def ::set-of-uuid (s/every uuid? :kind set?)) +(s/def ::ordered-set-of-uuid + (s/every uuid? :kind d/ordered-set?)) + (s/def ::set-of-string (s/every string? :kind set?)) @@ -128,7 +131,7 @@ (defn select-shapes [ids] - (us/verify ::set-of-uuid ids) + (us/verify ::ordered-set-of-uuid ids) (ptk/reify ::select-shapes ptk/UpdateEvent (update [_ state] @@ -147,10 +150,9 @@ ptk/UpdateEvent (update [_ state] (update state :workspace-local #(-> % - (assoc :selected #{}) + (assoc :selected (d/ordered-set)) (dissoc :selected-frame)))))) - ;; --- Select Shapes (By selrect) (def select-shapes-by-current-selrect @@ -294,7 +296,7 @@ selected (->> rchanges (filter #(selected (:old-id %))) (map #(get-in % [:obj :id])) - (into #{}))] + (into (d/ordered-set)))] (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}) (select-shapes selected)))))) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs index 09ae5f85a..9a973bffa 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs @@ -10,12 +10,13 @@ (ns uxbox.main.ui.workspace.sidebar.options.interactions (:require [rumext.alpha :as mf] - [uxbox.main.ui.icons :as i] + [uxbox.common.data :as d] [uxbox.common.pages-helpers :as cph] [uxbox.main.data.workspace :as dw] [uxbox.main.refs :as refs] [uxbox.main.store :as st] [uxbox.main.ui.components.dropdown :refer [dropdown]] + [uxbox.main.ui.icons :as i] [uxbox.util.dom :as dom] [uxbox.util.i18n :as i18n :refer [t]])) @@ -36,7 +37,7 @@ show-frames-dropdown? (mf/use-state false) on-set-blur #(reset! show-frames-dropdown? false) - on-navigate #(st/emit! (dw/select-shapes #{(:id destination)})) + on-navigate #(st/emit! (dw/select-shapes (d/ordered-set (:id destination)))) on-select-destination (fn [dest] diff --git a/frontend/src/uxbox/util/transit.cljs b/frontend/src/uxbox/util/transit.cljs index c1c37c562..3b884b269 100644 --- a/frontend/src/uxbox/util/transit.cljs +++ b/frontend/src/uxbox/util/transit.cljs @@ -2,14 +2,20 @@ ;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; file, You can obtain one at http://mozilla.org/MPL/2.0/. ;; -;; Copyright (c) 2016-2017 Andrey Antukh +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL (ns uxbox.util.transit "A lightweight abstraction for transit serialization." - (:require [cognitect.transit :as t] - [uxbox.common.geom.point :as gpt] - [uxbox.common.geom.matrix :as gmt] - [uxbox.util.time :as dt])) + (:require + [cognitect.transit :as t] + [linked.core :as lk] + [linked.set :as lks] + [uxbox.common.geom.point :as gpt] + [uxbox.common.geom.matrix :as gmt] + [uxbox.util.time :as dt])) (deftype Blob [content] IDeref @@ -51,18 +57,28 @@ (fn [value] (gmt/map->Matrix value)))) +(def ordered-set-write-handler + (t/write-handler + (constantly "ordered-set") + (fn [v] (vec v)))) + +(def ordered-set-read-handler + (t/read-handler #(into (lk/set) %))) + ;; --- Transit Handlers (def ^:privare +read-handlers+ {"u" uuid + "ordered-set" ordered-set-read-handler "jsonblob" blob-read-handler "matrix" matrix-read-handler "point" point-read-handler}) (def ^:privare +write-handlers+ - {gmt/Matrix matrix-write-handler - Blob blob-write-handler - gpt/Point point-write-handler}) + {gmt/Matrix matrix-write-handler + Blob blob-write-handler + lks/LinkedSet ordered-set-write-handler + gpt/Point point-write-handler}) ;; --- Public Api diff --git a/frontend/src/uxbox/worker/selection.cljs b/frontend/src/uxbox/worker/selection.cljs index 06a4af085..9d11abd81 100644 --- a/frontend/src/uxbox/worker/selection.cljs +++ b/frontend/src/uxbox/worker/selection.cljs @@ -11,6 +11,7 @@ (:require [cljs.spec.alpha :as s] [okulary.core :as l] + [uxbox.common.data :as d] [uxbox.common.exceptions :as ex] [uxbox.common.geom.shapes :as geom] [uxbox.common.pages :as cp] @@ -57,9 +58,10 @@ (= frame-id (:frame-id shape))) (geom/overlaps? shape rect)))] - (into #{} (comp (map #(unchecked-get % "data")) - (filter matches?) - (map :id)) + (into (d/ordered-set) + (comp (map #(unchecked-get % "data")) + (filter matches?) + (map :id)) result)))) (defn- create-index