From bdcbe46d0d00418dcee77984722d51bc7194bae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Tue, 28 Jun 2022 11:05:45 +0200 Subject: [PATCH] :recycle: Move component instantiation to new types module --- backend/src/app/rpc/queries/files.clj | 5 +- backend/src/app/tasks/file_gc.clj | 3 +- common/src/app/common/file_builder.cljc | 1 + common/src/app/common/pages/focus.cljc | 3 +- common/src/app/common/pages/helpers.cljc | 235 ------------- common/src/app/common/spec.cljc | 1 + common/src/app/common/types/container.cljc | 79 +++++ common/src/app/common/types/page.cljc | 6 - common/src/app/common/types/pages_list.cljc | 26 ++ common/src/app/common/types/shape_tree.cljc | 318 ++++++++++++++++++ frontend/src/app/main/data/viewer.cljs | 5 +- frontend/src/app/main/data/workspace.cljs | 20 +- .../src/app/main/data/workspace/bool.cljs | 6 +- .../src/app/main/data/workspace/changes.cljs | 3 +- .../src/app/main/data/workspace/common.cljs | 9 + .../app/main/data/workspace/drawing/box.cljs | 3 +- .../main/data/workspace/drawing/curve.cljs | 4 +- .../src/app/main/data/workspace/groups.cljs | 6 +- .../app/main/data/workspace/interactions.cljs | 6 +- .../app/main/data/workspace/libraries.cljs | 7 +- .../data/workspace/libraries_helpers.cljs | 77 ++--- .../app/main/data/workspace/path/drawing.cljs | 4 +- .../app/main/data/workspace/selection.cljs | 10 +- .../src/app/main/data/workspace/shapes.cljs | 6 +- .../app/main/data/workspace/svg_upload.cljs | 11 +- .../app/main/data/workspace/transforms.cljs | 3 +- frontend/src/app/main/refs.cljs | 3 +- frontend/src/app/main/render.cljs | 3 +- .../sidebar/options/menus/interactions.cljs | 3 +- .../ui/workspace/viewport/frame_grid.cljs | 4 +- .../main/ui/workspace/viewport/guides.cljs | 3 +- .../app/main/ui/workspace/viewport/hooks.cljs | 7 +- .../main/ui/workspace/viewport/widgets.cljs | 4 +- frontend/src/app/util/geom/snap_points.cljs | 5 +- frontend/src/app/util/names.cljs | 38 --- frontend/src/app/util/snap_data.cljs | 5 +- frontend/test/app/components_basic_test.cljs | 3 +- frontend/test/app/components_sync_test.cljs | 3 +- frontend/test/app/test_helpers/libraries.cljs | 13 +- 39 files changed, 542 insertions(+), 409 deletions(-) create mode 100644 common/src/app/common/types/container.cljc create mode 100644 common/src/app/common/types/pages_list.cljc create mode 100644 common/src/app/common/types/shape_tree.cljc delete mode 100644 frontend/src/app/util/names.cljs diff --git a/backend/src/app/rpc/queries/files.clj b/backend/src/app/rpc/queries/files.clj index 18ec92848..7adc19fbd 100644 --- a/backend/src/app/rpc/queries/files.clj +++ b/backend/src/app/rpc/queries/files.clj @@ -12,6 +12,7 @@ [app.common.geom.shapes :as gsh] [app.common.pages.helpers :as cph] [app.common.pages.migrations :as pmg] + [app.common.types.shape-tree :as ctt] [app.common.spec :as us] [app.db :as db] [app.db.sql :as sql] @@ -304,7 +305,7 @@ (get-thumbnail-frame [data] (d/seek :use-for-thumbnail? (for [page (-> data :pages-index vals) - frame (-> page :objects cph/get-frames)] + frame (-> page :objects ctt/get-frames)] (assoc frame :page-id (:id page))))) ;; function responsible to filter objects data structure of @@ -355,7 +356,7 @@ (-> data :pages first)) page (dm/get-in data [:pages-index page-id]) - frame-ids (if (some? frame) (list frame-id) (map :id (cph/get-frames (:objects page)))) + frame-ids (if (some? frame) (list frame-id) (map :id (ctt/get-frames (:objects page)))) obj-ids (map #(str page-id %) frame-ids) thumbs (retrieve-object-thumbnails cfg id obj-ids)] diff --git a/backend/src/app/tasks/file_gc.clj b/backend/src/app/tasks/file_gc.clj index 29ad2eeb8..1f9d5042e 100644 --- a/backend/src/app/tasks/file_gc.clj +++ b/backend/src/app/tasks/file_gc.clj @@ -14,6 +14,7 @@ [app.common.logging :as l] [app.common.pages.helpers :as cph] [app.common.pages.migrations :as pmg] + [app.common.types.shape-tree :as ctt] [app.db :as db] [app.util.blob :as blob] [app.util.time :as dt] @@ -128,7 +129,7 @@ get-objects-ids (fn [{:keys [id objects]}] - (->> (cph/get-frames objects) + (->> (ctt/get-frames objects) (map #(str id (:id %))))) using (into #{} diff --git a/common/src/app/common/file_builder.cljc b/common/src/app/common/file_builder.cljc index 882991a1f..5fcc64c0f 100644 --- a/common/src/app/common/file_builder.cljc +++ b/common/src/app/common/file_builder.cljc @@ -14,6 +14,7 @@ [app.common.pages.changes-spec :as pcs] [app.common.pages.init :as init] [app.common.spec :as us] + [app.common.types.page :as ctp] [app.common.uuid :as uuid] [cuerdas.core :as str])) diff --git a/common/src/app/common/pages/focus.cljc b/common/src/app/common/pages/focus.cljc index a7ca0f495..57a048b2e 100644 --- a/common/src/app/common/pages/focus.cljc +++ b/common/src/app/common/pages/focus.cljc @@ -8,6 +8,7 @@ (:require [app.common.data :as d] [app.common.pages.helpers :as cph] + [app.common.types.shape-tree :as ctt] [app.common.uuid :as uuid])) (defn focus-objects @@ -21,7 +22,7 @@ (cond-> objects (some? ids-with-children) (-> (select-keys ids-with-children) - (assoc-in [uuid/zero :shapes] (cph/sort-z-index objects focus)))))) + (assoc-in [uuid/zero :shapes] (ctt/sort-z-index objects focus)))))) (defn filter-not-focus [objects focus ids] diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index 52fa4748d..5984cd46a 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -8,10 +8,7 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] - [app.common.geom.shapes :as gsh] - [app.common.math :as mth] [app.common.spec :as us] - [app.common.types.page :as ctp] [app.common.uuid :as uuid] [cuerdas.core :as str])) @@ -62,14 +59,6 @@ (and (not (frame-shape? shape)) (= (:frame-id shape) uuid/zero))) -(defn get-shape - [container shape-id] - (us/assert ::ctp/container container) - (us/assert ::us/uuid shape-id) - (-> container - (get :objects) - (get shape-id))) - (defn get-children-ids [objects id] (if-let [shapes (-> (get objects id) :shapes (some-> vec))] @@ -158,146 +147,6 @@ (:shapes) (keep lookup))))) -(defn get-frames - "Retrieves all frame objects as vector" - [objects] - (or (-> objects meta ::index-frames) - (let [lookup (d/getf objects) - xform (comp (remove #(= uuid/zero %)) - (keep lookup) - (filter frame-shape?))] - (->> (keys objects) - (into [] xform))))) - -(defn get-frames-ids - "Retrieves all frame ids as vector" - [objects] - (->> (get-frames objects) - (mapv :id))) - -(defn get-nested-frames - [objects frame-id] - (into #{} - (comp (filter frame-shape?) - (map :id)) - (get-children objects frame-id))) - -(defn get-root-frames-ids - "Retrieves all frame objects as vector. It is not implemented in - function of `get-immediate-children` for performance reasons. This - function is executed in the render hot path." - [objects] - (let [add-frame - (fn [result shape] - (cond-> result - (frame-shape? shape) - (conj (:id shape))))] - (reduce-objects objects (complement frame-shape?) add-frame []))) - -(defn get-root-objects - "Get all the objects under the root object" - [objects] - (let [add-shape - (fn [result shape] - (conj result shape))] - (reduce-objects objects (complement frame-shape?) add-shape []))) - -(defn get-root-shapes - "Get all shapes that are not frames" - [objects] - (let [add-shape - (fn [result shape] - (cond-> result - (not (frame-shape? shape)) - (conj shape)))] - (reduce-objects objects (complement frame-shape?) add-shape []))) - -(defn get-root-shapes-ids - [objects] - (->> (get-root-shapes objects) - (mapv :id))) - -(defn get-base - [objects id-a id-b] - - (let [parents-a (reverse (get-parents-seq objects id-a)) - parents-b (reverse (get-parents-seq objects id-b)) - - [base base-child-a base-child-b] - (loop [parents-a (rest parents-a) - parents-b (rest parents-b) - base uuid/zero] - (cond - (not= (first parents-a) (first parents-b)) - [base (first parents-a) (first parents-b)] - - (or (empty? parents-a) (empty? parents-b)) - [uuid/zero (first parents-a) (first parents-b)] - - :else - (recur (rest parents-a) (rest parents-b) (first parents-a)))) - - index-base-a (when base-child-a (get-position-on-parent objects base-child-a)) - index-base-b (when base-child-b (get-position-on-parent objects base-child-b))] - - [base index-base-a index-base-b])) - -(defn is-shape-over-shape? - [objects base-shape-id over-shape-id {:keys [top-frames?]}] - - (let [[base index-a index-b] (get-base objects base-shape-id over-shape-id)] - (cond - (= base base-shape-id) - (and (not top-frames?) - (frame-shape? objects base-shape-id) - (root-frame? objects base-shape-id)) - - (= base over-shape-id) - (or top-frames? - (not (frame-shape? objects over-shape-id)) - (not (root-frame? objects over-shape-id))) - - :else - (< index-a index-b)))) - -(defn sort-z-index - ([objects ids] - (sort-z-index objects ids nil)) - - ([objects ids {:keys [bottom-frames?] :as options}] - (letfn [(comp [id-a id-b] - (let [type-a (dm/get-in objects [id-a :type]) - type-b (dm/get-in objects [id-b :type])] - (cond - (and bottom-frames? (= :frame type-a) (not= :frame type-b)) - 1 - - (and bottom-frames? (not= :frame type-a) (= :frame type-b)) - -1 - - (= id-a id-b) - 0 - - (is-shape-over-shape? objects id-a id-b options) - 1 - - :else - -1)))] - (sort comp ids)))) - -(defn frame-id-by-position - [objects position] - (let [top-frame - (->> (get-frames-ids objects) - (sort-z-index objects) - (d/seek #(and position (gsh/has-point? (get objects %) position))))] - (or top-frame uuid/zero))) - -(defn frame-by-position - [objects position] - (let [frame-id (frame-id-by-position objects position)] - (get objects frame-id))) - (declare indexed-shapes) (defn get-base-shape @@ -467,57 +316,6 @@ (reduce add-element (d/ordered-set) ids))) -(defn clone-object - "Gets a copy of the object and all its children, with new ids - and with the parent-children links correctly set. Admits functions - to make more transformations to the cloned objects and the - original ones. - - Returns the cloned object, the list of all new objects (including - the cloned one), and possibly a list of original objects modified." - - ([object parent-id objects update-new-object] - (clone-object object parent-id objects update-new-object identity)) - - ([object parent-id objects update-new-object update-original-object] - (let [new-id (uuid/next)] - (loop [child-ids (seq (:shapes object)) - new-direct-children [] - new-children [] - updated-children []] - - (if (empty? child-ids) - (let [new-object (cond-> object - true - (assoc :id new-id - :parent-id parent-id) - - (some? (:shapes object)) - (assoc :shapes (mapv :id new-direct-children))) - - new-object (update-new-object new-object object) - new-objects (into [new-object] new-children) - - updated-object (update-original-object object new-object) - updated-objects (if (identical? object updated-object) - updated-children - (into [updated-object] updated-children))] - - [new-object new-objects updated-objects]) - - (let [child-id (first child-ids) - child (get objects child-id) - _ (us/assert some? child) - - [new-child new-child-objects updated-child-objects] - (clone-object child new-id objects update-new-object update-original-object)] - - (recur - (next child-ids) - (into new-direct-children [new-child]) - (into new-children new-child-objects) - (into updated-children updated-child-objects)))))))) - (defn indexed-shapes "Retrieves a list with the indexes for each element in the layer tree. This will be used for shift+selection." @@ -700,36 +498,3 @@ :id)) -(defn get-viewer-frames - ([objects] - (get-viewer-frames objects nil)) - - ([objects {:keys [all-frames?]}] - (into [] - (comp (map (d/getf objects)) - (if all-frames? - (map identity) - (remove :hide-in-viewer))) - (sort-z-index objects (get-frames-ids objects) {:top-frames? true})))) - -(defn start-page-index - [objects] - (with-meta objects {::index-frames (get-frames (with-meta objects nil))})) - -(defn update-page-index - [objects] - (with-meta objects {::index-frames (get-frames (with-meta objects nil))})) - -(defn start-object-indices - [file] - (letfn [(process-index [page-index page-id] - (update-in page-index [page-id :objects] start-page-index))] - (update file :pages-index #(reduce process-index % (keys %))))) - -(defn update-object-indices - [file page-id] - (update-in file [:pages-index page-id :objects] update-page-index)) - -(defn rotated-frame? - [frame] - (not (mth/almost-zero? (:rotation frame 0)))) diff --git a/common/src/app/common/spec.cljc b/common/src/app/common/spec.cljc index e596179ad..a1fb2fd72 100644 --- a/common/src/app/common/spec.cljc +++ b/common/src/app/common/spec.cljc @@ -107,6 +107,7 @@ (s/def ::number (s/conformer number-conformer str)) (s/def ::integer (s/conformer integer-conformer str)) (s/def ::not-empty-string (s/and string? #(not (str/empty? %)))) +(s/def ::set-of-string (s/every string? :kind set?)) (s/def ::url string?) (s/def ::fn fn?) (s/def ::id ::uuid) diff --git a/common/src/app/common/types/container.cljc b/common/src/app/common/types/container.cljc new file mode 100644 index 000000000..168cfe8ca --- /dev/null +++ b/common/src/app/common/types/container.cljc @@ -0,0 +1,79 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; 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) UXBOX Labs SL + +(ns app.common.types.container + (:require + [app.common.geom.point :as gpt] + [app.common.geom.shapes :as gsh] + [app.common.spec :as us] + [app.common.types.shape-tree :as ctt] + [clojure.spec.alpha :as s])) + +(s/def ::type #{:page :component}) +(s/def ::id uuid?) +(s/def ::name string?) +(s/def ::path (s/nilable string?)) + +(s/def ::container + (s/keys :req-un [::id ::name ::ctt/objects] + :opt-un [::type ::path])) + +(defn get-shape + [container shape-id] + (us/assert ::container container) + (us/assert ::us/uuid shape-id) + (-> container + (get :objects) + (get shape-id))) + +(defn instantiate-component + [container component component-file position] + (let [component-shape (get-shape component (:id component)) + + orig-pos (gpt/point (:x component-shape) (:y component-shape)) + delta (gpt/subtract position orig-pos) + + objects (:objects container) + unames (volatile! (ctt/retrieve-used-names objects)) + + frame-id (ctt/frame-id-by-position objects (gpt/add orig-pos delta)) + + update-new-shape + (fn [new-shape original-shape] + (let [new-name (ctt/generate-unique-name @unames (:name new-shape))] + + (when (nil? (:parent-id original-shape)) + (vswap! unames conj new-name)) + + (cond-> new-shape + true + (as-> $ + (gsh/move $ delta) + (assoc $ :frame-id frame-id) + (assoc $ :parent-id + (or (:parent-id $) (:frame-id $))) + (dissoc $ :touched)) + + (nil? (:shape-ref original-shape)) + (assoc :shape-ref (:id original-shape)) + + (nil? (:parent-id original-shape)) + (assoc :component-id (:id original-shape) + :component-file component-file + :component-root? true + :name new-name) + + (some? (:parent-id original-shape)) + (dissoc :component-root?)))) + + [new-shape new-shapes _] + (ctt/clone-object component-shape + nil + (get component :objects) + update-new-shape)] + + [new-shape new-shapes])) + diff --git a/common/src/app/common/types/page.cljc b/common/src/app/common/types/page.cljc index 0ed513dc0..b86092f35 100644 --- a/common/src/app/common/types/page.cljc +++ b/common/src/app/common/types/page.cljc @@ -95,12 +95,6 @@ (s/def ::page (s/keys :req-un [::id ::name ::objects ::options])) -(s/def ::type #{:page :component}) -(s/def ::path (s/nilable string?)) -(s/def ::container - (s/keys :req-un [::id ::name ::objects] - :opt-un [::type ::path])) - ;; --- Helpers for flow (defn rename-flow diff --git a/common/src/app/common/types/pages_list.cljc b/common/src/app/common/types/pages_list.cljc new file mode 100644 index 000000000..3f037ece2 --- /dev/null +++ b/common/src/app/common/types/pages_list.cljc @@ -0,0 +1,26 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; 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) UXBOX Labs SL + +(ns app.common.types.pages-list + (:require + [app.common.data :as d])) + +(defn get-page + [file-data id] + (get-in file-data [:pages-index id])) + +(defn add-page + [file-data page] + (let [; It's legitimate to add a page that is already there, + ; for example in an idempotent changes operation. + conj-if-not-exists (fn [pages id] + (cond-> pages + (not (d/seek #(= % id) pages)) + (conj id)))] + (-> file-data + (update :pages conj-if-not-exists (:id page)) + (update :pages-index assoc (:id page) page)))) + diff --git a/common/src/app/common/types/shape_tree.cljc b/common/src/app/common/types/shape_tree.cljc new file mode 100644 index 000000000..c9bcef507 --- /dev/null +++ b/common/src/app/common/types/shape_tree.cljc @@ -0,0 +1,318 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; 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) UXBOX Labs SL + +(ns app.common.types.shape-tree + (:require + [app.common.data :as d] + [app.common.data.macros :as dm] + [app.common.geom.point :as gpt] + [app.common.geom.shapes :as gsh] + [app.common.math :as mth] + [app.common.pages.helpers :as cph] + [app.common.spec :as us] + [app.common.types.shape :as cts] + [app.common.uuid :as uuid] + [clojure.spec.alpha :as s])) + +(s/def ::objects (s/map-of uuid? ::cts/shape)) + +(defn add-shape + "Insert a shape in the tree, at the given index below the given parent or frame. + Update the parent as needed." + [id shape container frame-id parent-id index ignore-touched] + (let [update-parent-shapes + (fn [shapes] + ;; Ensure that shapes is always a vector. + (let [shapes (into [] shapes)] + (cond + (some #{id} shapes) + shapes + + (nil? index) + (conj shapes id) + + :else + (cph/insert-at-index shapes index [id])))) + + update-parent + (fn [parent] + (-> parent + (update :shapes update-parent-shapes) + (update :shapes d/vec-without-nils) + (cond-> (and (:shape-ref parent) + (not= (:id parent) frame-id) + (not ignore-touched)) + (-> (update :touched cph/set-touched-group :shapes-group) + (dissoc :remote-synced?))))) + + ;; TODO: this looks wrong, why we allow nil values? + update-objects + (fn [objects parent-id] + (if (and (or (nil? parent-id) (contains? objects parent-id)) + (or (nil? frame-id) (contains? objects frame-id))) + (-> objects + (assoc id (-> shape + (assoc :frame-id frame-id) + (assoc :parent-id parent-id) + (assoc :id id))) + (update parent-id update-parent)) + objects)) + + parent-id (or parent-id frame-id)] + + (update container :objects update-objects parent-id))) + +(defn get-frames + "Retrieves all frame objects as vector" + [objects] + (or (-> objects meta ::index-frames) + (let [lookup (d/getf objects) + xform (comp (remove #(= uuid/zero %)) + (keep lookup) + (filter cph/frame-shape?))] + (->> (keys objects) + (into [] xform))))) + +(defn get-frames-ids + "Retrieves all frame ids as vector" + [objects] + (->> (get-frames objects) + (mapv :id))) + +(defn get-nested-frames + [objects frame-id] + (into #{} + (comp (filter cph/frame-shape?) + (map :id)) + (cph/get-children objects frame-id))) + +(defn get-root-frames-ids + "Retrieves all frame objects as vector. It is not implemented in + function of `get-immediate-children` for performance reasons. This + function is executed in the render hot path." + [objects] + (let [add-frame + (fn [result shape] + (cond-> result + (cph/frame-shape? shape) + (conj (:id shape))))] + (cph/reduce-objects objects (complement cph/frame-shape?) add-frame []))) + +(defn get-root-objects + "Get all the objects under the root object" + [objects] + (let [add-shape + (fn [result shape] + (conj result shape))] + (cph/reduce-objects objects (complement cph/frame-shape?) add-shape []))) + +(defn get-root-shapes + "Get all shapes that are not frames" + [objects] + (let [add-shape + (fn [result shape] + (cond-> result + (not (cph/frame-shape? shape)) + (conj shape)))] + (cph/reduce-objects objects (complement cph/frame-shape?) add-shape []))) + +(defn get-root-shapes-ids + [objects] + (->> (get-root-shapes objects) + (mapv :id))) + +(defn get-base + [objects id-a id-b] + + (let [parents-a (reverse (cph/get-parents-seq objects id-a)) + parents-b (reverse (cph/get-parents-seq objects id-b)) + + [base base-child-a base-child-b] + (loop [parents-a (rest parents-a) + parents-b (rest parents-b) + base uuid/zero] + (cond + (not= (first parents-a) (first parents-b)) + [base (first parents-a) (first parents-b)] + + (or (empty? parents-a) (empty? parents-b)) + [uuid/zero (first parents-a) (first parents-b)] + + :else + (recur (rest parents-a) (rest parents-b) (first parents-a)))) + + index-base-a (when base-child-a (cph/get-position-on-parent objects base-child-a)) + index-base-b (when base-child-b (cph/get-position-on-parent objects base-child-b))] + + [base index-base-a index-base-b])) + + +(defn is-shape-over-shape? + [objects base-shape-id over-shape-id {:keys [top-frames?]}] + + (let [[base index-a index-b] (get-base objects base-shape-id over-shape-id)] + (cond + (= base base-shape-id) + (and (not top-frames?) + (cph/frame-shape? objects base-shape-id) + (cph/root-frame? objects base-shape-id)) + + (= base over-shape-id) + (or top-frames? + (not (cph/frame-shape? objects over-shape-id)) + (not (cph/root-frame? objects over-shape-id))) + + :else + (< index-a index-b)))) + +(defn sort-z-index + ([objects ids] + (sort-z-index objects ids nil)) + + ([objects ids {:keys [bottom-frames?] :as options}] + (letfn [(comp [id-a id-b] + (let [type-a (dm/get-in objects [id-a :type]) + type-b (dm/get-in objects [id-b :type])] + (cond + (and bottom-frames? (= :frame type-a) (not= :frame type-b)) + 1 + + (and bottom-frames? (not= :frame type-a) (= :frame type-b)) + -1 + + (= id-a id-b) + 0 + + (is-shape-over-shape? objects id-a id-b options) + 1 + + :else + -1)))] + (sort comp ids)))) + +(defn frame-id-by-position + [objects position] + (assert (gpt/point? position)) + (let [top-frame + (->> (get-frames-ids objects) + (sort-z-index objects) + (d/seek #(and position (gsh/has-point? (get objects %) position))))] + (or top-frame uuid/zero))) + +(defn frame-by-position + [objects position] + (let [frame-id (frame-id-by-position objects position)] + (get objects frame-id))) + +(defn get-viewer-frames + ([objects] + (get-viewer-frames objects nil)) + + ([objects {:keys [all-frames?]}] + (into [] + (comp (map (d/getf objects)) + (if all-frames? + identity + (remove :hide-in-viewer))) + (sort-z-index objects (get-frames-ids objects) {:top-frames? true})))) + +(defn start-page-index + [objects] + (with-meta objects {::index-frames (get-frames (with-meta objects nil))})) + +(defn update-page-index + [objects] + (with-meta objects {::index-frames (get-frames (with-meta objects nil))})) + +(defn start-object-indices + [file] + (letfn [(process-index [page-index page-id] + (update-in page-index [page-id :objects] start-page-index))] + (update file :pages-index #(reduce process-index % (keys %))))) + +(defn update-object-indices + [file page-id] + (update-in file [:pages-index page-id :objects] update-page-index)) + +(defn rotated-frame? + [frame] + (not (mth/almost-zero? (:rotation frame 0)))) + +(defn retrieve-used-names + [objects] + (into #{} (comp (map :name) (remove nil?)) (vals objects))) + +(defn- extract-numeric-suffix + [basename] + (if-let [[_ p1 p2] (re-find #"(.*)-([0-9]+)$" basename)] + [p1 (+ 1 (d/parse-integer p2))] + [basename 1])) + +(defn generate-unique-name + "A unique name generator" + [used basename] + (s/assert ::us/set-of-string used) + (s/assert ::us/string basename) + (if-not (contains? used basename) + basename + (let [[prefix initial] (extract-numeric-suffix basename)] + (loop [counter initial] + (let [candidate (str prefix "-" counter)] + (if (contains? used candidate) + (recur (inc counter)) + candidate)))))) + +(defn clone-object + "Gets a copy of the object and all its children, with new ids + and with the parent-children links correctly set. Admits functions + to make more transformations to the cloned objects and the + original ones. + + Returns the cloned object, the list of all new objects (including + the cloned one), and possibly a list of original objects modified." + + ([object parent-id objects update-new-object] + (clone-object object parent-id objects update-new-object identity)) + + ([object parent-id objects update-new-object update-original-object] + (let [new-id (uuid/next)] + (loop [child-ids (seq (:shapes object)) + new-direct-children [] + new-children [] + updated-children []] + + (if (empty? child-ids) + (let [new-object (cond-> object + true + (assoc :id new-id + :parent-id parent-id) + + (some? (:shapes object)) + (assoc :shapes (mapv :id new-direct-children))) + + new-object (update-new-object new-object object) + new-objects (into [new-object] new-children) + + updated-object (update-original-object object new-object) + updated-objects (if (identical? object updated-object) + updated-children + (into [updated-object] updated-children))] + + [new-object new-objects updated-objects]) + + (let [child-id (first child-ids) + child (get objects child-id) + _ (us/assert some? child) + + [new-child new-child-objects updated-child-objects] + (clone-object child new-id objects update-new-object update-original-object)] + + (recur + (next child-ids) + (into new-direct-children [new-child]) + (into new-children new-child-objects) + (into updated-children updated-child-objects)))))))) + diff --git a/frontend/src/app/main/data/viewer.cljs b/frontend/src/app/main/data/viewer.cljs index 54c042222..896c49390 100644 --- a/frontend/src/app/main/data/viewer.cljs +++ b/frontend/src/app/main/data/viewer.cljs @@ -10,6 +10,7 @@ [app.common.geom.point :as gpt] [app.common.pages.helpers :as cph] [app.common.spec :as us] + [app.common.types.shape-tree :as ctt] [app.common.types.shape.interactions :as ctsi] [app.main.data.comments :as dcm] [app.main.data.fonts :as df] @@ -116,8 +117,8 @@ (map (fn [page-id] (let [data (get-in file [:data :pages-index page-id])] [page-id (assoc data - :frames (cph/get-viewer-frames (:objects data)) - :all-frames (cph/get-viewer-frames (:objects data) {:all-frames? true}))]))) + :frames (ctt/get-viewer-frames (:objects data)) + :all-frames (ctt/get-viewer-frames (:objects data) {:all-frames? true}))]))) (into {}))] (ptk/reify ::bundle-fetched diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 62dc383ad..d778cdb0b 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -21,6 +21,7 @@ [app.common.text :as txt] [app.common.transit :as t] [app.common.types.shape :as cts] + [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] [app.config :as cfg] [app.main.data.events :as ev] @@ -59,7 +60,6 @@ [app.util.globals :as ug] [app.util.http :as http] [app.util.i18n :as i18n] - [app.util.names :as un] [app.util.router :as rt] [app.util.timers :as tm] [app.util.webapi :as wapi] @@ -157,7 +157,7 @@ :workspace-project project :workspace-file (assoc file :initialized true) :workspace-data (-> (:data file) - (cph/start-object-indices) + (ctst/start-object-indices) ;; DEBUG: Uncomment this to try out migrations in local without changing ;; the version number #_(assoc :version 17) @@ -270,8 +270,8 @@ ptk/WatchEvent (watch [it state _] (let [pages (get-in state [:workspace-data :pages-index]) - unames (un/retrieve-used-names pages) - name (un/generate-unique-name unames "Page-1") + unames (ctst/retrieve-used-names pages) + name (ctst/generate-unique-name unames "Page-1") changes (-> (pcb/empty-changes it) (pcb/add-empty-page id name))] @@ -285,9 +285,9 @@ (watch [it state _] (let [id (uuid/next) pages (get-in state [:workspace-data :pages-index]) - unames (un/retrieve-used-names pages) + unames (ctst/retrieve-used-names pages) page (get-in state [:workspace-data :pages-index page-id]) - name (un/generate-unique-name unames (:name page)) + name (ctst/generate-unique-name unames (:name page)) no_thumbnails_objects (->> (:objects page) (d/mapm (fn [_ val] (dissoc val :use-for-thumbnail?)))) @@ -991,7 +991,7 @@ (let [selected (wsh/lookup-selected state) pages (-> state :workspace-data :pages-index vals) get-frames (fn [{:keys [objects id] :as page}] - (->> (cph/get-frames objects) + (->> (ctst/get-frames objects) (sequence (comp (filter :use-for-thumbnail?) (map :id) @@ -1223,7 +1223,7 @@ ;; selected and its parents objects (cph/selected-subtree objects selected) - selected (->> (cph/sort-z-index objects selected) + selected (->> (ctst/sort-z-index objects selected) (into (d/ordered-set)))] (assoc data :selected selected))) @@ -1478,7 +1478,7 @@ [frame-id frame-id delta]) (empty? page-selected) - (let [frame-id (cph/frame-id-by-position page-objects mouse-pos) + (let [frame-id (ctst/frame-id-by-position page-objects mouse-pos) delta (gpt/subtract mouse-pos orig-pos)] [frame-id frame-id delta]) @@ -1590,7 +1590,7 @@ height 16 page-id (:current-page-id state) frame-id (-> (wsh/lookup-page-objects state page-id) - (cph/frame-id-by-position @ms/mouse-position)) + (ctst/frame-id-by-position @ms/mouse-position)) shape (cp/setup-rect-selrect {:id id :type :text diff --git a/frontend/src/app/main/data/workspace/bool.cljs b/frontend/src/app/main/data/workspace/bool.cljs index 771c06bb2..70fe8d222 100644 --- a/frontend/src/app/main/data/workspace/bool.cljs +++ b/frontend/src/app/main/data/workspace/bool.cljs @@ -11,11 +11,11 @@ [app.common.pages.changes-builder :as pcb] [app.common.pages.helpers :as cph] [app.common.path.shapes-to-path :as stp] + [app.common.types.shape-tree :as ctt] [app.common.uuid :as uuid] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.selection :as dws] [app.main.data.workspace.state-helpers :as wsh] - [app.util.names :as un] [beicon.core :as rx] [cuerdas.core :as str] [potok.core :as ptk])) @@ -90,8 +90,8 @@ (let [page-id (:current-page-id state) objects (wsh/lookup-page-objects state) base-name (-> bool-type d/name str/capital (str "-1")) - name (-> (un/retrieve-used-names objects) - (un/generate-unique-name base-name)) + name (-> (ctt/retrieve-used-names objects) + (ctt/generate-unique-name base-name)) shapes (selected-shapes state)] (when-not (empty? shapes) diff --git a/frontend/src/app/main/data/workspace/changes.cljs b/frontend/src/app/main/data/workspace/changes.cljs index 209c8f549..a1f4da573 100644 --- a/frontend/src/app/main/data/workspace/changes.cljs +++ b/frontend/src/app/main/data/workspace/changes.cljs @@ -13,6 +13,7 @@ [app.common.pages.changes-spec :as pcs] [app.common.pages.helpers :as cph] [app.common.spec :as us] + [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] @@ -165,7 +166,7 @@ (update-in state path (fn [file] (-> file (cp/process-changes redo-changes false) - (cph/update-object-indices page-id)))) + (ctst/update-object-indices page-id)))) (catch :default err (log/error :js/error err) diff --git a/frontend/src/app/main/data/workspace/common.cljs b/frontend/src/app/main/data/workspace/common.cljs index 6f9ac6d35..39724ee8b 100644 --- a/frontend/src/app/main/data/workspace/common.cljs +++ b/frontend/src/app/main/data/workspace/common.cljs @@ -7,6 +7,15 @@ (ns app.main.data.workspace.common (:require [app.common.logging :as log] + [app.common.pages :as cp] + [app.common.pages.changes-builder :as pcb] + [app.common.pages.helpers :as cph] + [app.common.spec :as us] + [app.common.types.page :as ctp] + [app.common.types.shape :as cts] + [app.common.types.shape-tree :as ctt] + [app.common.types.shape.interactions :as ctsi] + [app.common.uuid :as uuid] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.undo :as dwu] [app.main.worker :as uw] diff --git a/frontend/src/app/main/data/workspace/drawing/box.cljs b/frontend/src/app/main/data/workspace/drawing/box.cljs index bdffbe1f7..aa550f98c 100644 --- a/frontend/src/app/main/data/workspace/drawing/box.cljs +++ b/frontend/src/app/main/data/workspace/drawing/box.cljs @@ -11,6 +11,7 @@ [app.common.math :as mth] [app.common.pages :as cp] [app.common.pages.helpers :as cph] + [app.common.types.shape-tree :as ctt] [app.common.uuid :as uuid] [app.main.data.workspace.drawing.common :as common] [app.main.data.workspace.state-helpers :as wsh] @@ -65,7 +66,7 @@ focus (:workspace-focus-selected state) zoom (get-in state [:workspace-local :zoom] 1) - fid (cph/frame-id-by-position objects initial) + fid (ctt/frame-id-by-position objects initial) shape (get-in state [:workspace-drawing :object]) shape (-> shape diff --git a/frontend/src/app/main/data/workspace/drawing/curve.cljs b/frontend/src/app/main/data/workspace/drawing/curve.cljs index d60cc040c..66062fd16 100644 --- a/frontend/src/app/main/data/workspace/drawing/curve.cljs +++ b/frontend/src/app/main/data/workspace/drawing/curve.cljs @@ -8,7 +8,7 @@ (:require [app.common.geom.shapes :as gsh] [app.common.geom.shapes.path :as gsp] - [app.common.pages.helpers :as cph] + [app.common.types.shape-tree :as ctt] [app.main.data.workspace.drawing.common :as common] [app.main.data.workspace.state-helpers :as wsh] [app.main.streams :as ms] @@ -47,7 +47,7 @@ (let [objects (wsh/lookup-page-objects state) content (get-in state [:workspace-drawing :object :content] []) position (get-in content [0 :params] nil) - frame-id (cph/frame-id-by-position objects position)] + frame-id (ctt/frame-id-by-position objects position)] (-> state (assoc-in [:workspace-drawing :object :frame-id] frame-id)))))) diff --git a/frontend/src/app/main/data/workspace/groups.cljs b/frontend/src/app/main/data/workspace/groups.cljs index 2b315fc5e..d5533bc98 100644 --- a/frontend/src/app/main/data/workspace/groups.cljs +++ b/frontend/src/app/main/data/workspace/groups.cljs @@ -11,10 +11,10 @@ [app.common.pages :as cp] [app.common.pages.changes-builder :as pcb] [app.common.pages.helpers :as cph] + [app.common.types.shape-tree :as ctt] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.selection :as dws] [app.main.data.workspace.state-helpers :as wsh] - [app.util.names :as un] [beicon.core :as rx] [potok.core :as ptk])) @@ -71,8 +71,8 @@ (= (count shapes) 1) (= (:type (first shapes)) :group)) (:name (first shapes)) - (-> (un/retrieve-used-names objects) - (un/generate-unique-name base-name))) + (-> (ctt/retrieve-used-names objects) + (ctt/generate-unique-name base-name))) selrect (gsh/selection-rect shapes) group (-> (cp/make-minimal-group frame-id selrect gname) diff --git a/frontend/src/app/main/data/workspace/interactions.cljs b/frontend/src/app/main/data/workspace/interactions.cljs index 40c6a80f9..e1a653be7 100644 --- a/frontend/src/app/main/data/workspace/interactions.cljs +++ b/frontend/src/app/main/data/workspace/interactions.cljs @@ -12,12 +12,12 @@ [app.common.pages.helpers :as cph] [app.common.spec :as us] [app.common.types.page :as ctp] + [app.common.types.shape-tree :as ctst] [app.common.types.shape.interactions :as ctsi] [app.common.uuid :as uuid] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.state-helpers :as wsh] [app.main.streams :as ms] - [app.util.names :as un] [beicon.core :as rx] [potok.core :as ptk])) @@ -32,7 +32,7 @@ flows (get-in page [:options :flows] []) unames (into #{} (map :name flows)) - name (un/generate-unique-name unames "Flow-1") + name (ctst/generate-unique-name unames "Flow-1") new-flow {:id (uuid/next) :name name @@ -182,7 +182,7 @@ from-frame-id (if (cph/frame-shape? from-shape) from-id (:frame-id from-shape)) - target-frame (cph/frame-by-position objects position)] + target-frame (ctst/frame-by-position objects position)] (when (and (not= (:id target-frame) uuid/zero) (not= (:id target-frame) from-frame-id) diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 6e4fa70ca..9a8acafb0 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -15,7 +15,9 @@ [app.common.pages.helpers :as cph] [app.common.spec :as us] [app.common.types.color :as ctc] + [app.common.types.container :as ctn] [app.common.types.file :as ctf] + [app.common.types.shape-tree :as ctst] [app.common.types.typography :as ctt] [app.common.uuid :as uuid] [app.main.data.dashboard :as dd] @@ -30,7 +32,6 @@ [app.main.repo :as rp] [app.main.store :as st] [app.util.i18n :refer [tr]] - [app.util.names :as un] [app.util.router :as rt] [app.util.time :as dt] [beicon.core :as rx] @@ -352,7 +353,7 @@ component (cph/get-component libraries id) all-components (-> state :workspace-data :components vals) unames (into #{} (map :name) all-components) - new-name (un/generate-unique-name unames (:name component)) + new-name (ctst/generate-unique-name unames (:name component)) [new-shape new-shapes _updated-shapes main-instance main-instance-page] (dwlh/duplicate-component component) @@ -525,7 +526,7 @@ libraries (wsh/get-libraries state) container (cph/get-container local-file :page page-id) - shape (cph/get-shape container id) + shape (ctn/get-shape container id) changes (-> (pcb/empty-changes it) diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index 1c74d9d1e..2914f4095 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -16,9 +16,10 @@ [app.common.spec :as us] [app.common.text :as txt] [app.common.types.color :as ctc] + [app.common.types.container :as ctn] + [app.common.types.shape-tree :as ctst] [app.main.data.workspace.groups :as dwg] [app.main.data.workspace.state-helpers :as wsh] - [app.util.names :as un] [cljs.spec.alpha :as s] [clojure.set :as set])) @@ -93,7 +94,7 @@ (some? (:parent-id new-shape)) (dissoc :component-root?)))] - (cph/clone-object shape nil objects update-new-shape update-original-shape))) + (ctst/clone-object shape nil objects update-new-shape update-original-shape))) (defn generate-add-component "If there is exactly one id, and it's a group, use it as root. Otherwise, @@ -131,7 +132,7 @@ ids from all of them." [component] (let [component-root (cph/get-component-root component)] - (cph/clone-object component-root + (ctst/clone-object component-root nil (get component :objects) identity))) @@ -140,49 +141,9 @@ "Generate changes to create a new instance from a component." [it file-id component-id position page libraries] (let [component (cph/get-component libraries file-id component-id) - component-shape (cph/get-shape component component-id) - orig-pos (gpt/point (:x component-shape) (:y component-shape)) - delta (gpt/subtract position orig-pos) - - objects (:objects page) - unames (volatile! (un/retrieve-used-names objects)) - - frame-id (cph/frame-id-by-position objects (gpt/add orig-pos delta)) - - update-new-shape - (fn [new-shape original-shape] - (let [new-name (un/generate-unique-name @unames (:name new-shape))] - - (when (nil? (:parent-id original-shape)) - (vswap! unames conj new-name)) - - (cond-> new-shape - true - (as-> $ - (gsh/move $ delta) - (assoc $ :frame-id frame-id) - (assoc $ :parent-id - (or (:parent-id $) (:frame-id $))) - (dissoc $ :touched)) - - (nil? (:shape-ref original-shape)) - (assoc :shape-ref (:id original-shape)) - - (nil? (:parent-id original-shape)) - (assoc :component-id (:id original-shape) - :component-file file-id - :component-root? true - :name new-name) - - (some? (:parent-id original-shape)) - (dissoc :component-root?)))) - - [new-shape new-shapes _] - (cph/clone-object component-shape - nil - (get component :objects) - update-new-shape) + [new-shape new-shapes] + (ctn/instantiate-component page component file-id position) changes (reduce #(pcb/add-object %1 %2 {:ignore-touched true}) (pcb/empty-changes it (:id page)) @@ -484,12 +445,12 @@ instance, and all its children, from the given component." [changes libraries container shape-id reset?] (log/debug :msg "Sync shape direct" :shape (str shape-id) :reset? reset?) - (let [shape-inst (cph/get-shape container shape-id) + (let [shape-inst (ctn/get-shape container shape-id) component (cph/get-component libraries (:component-file shape-inst) (:component-id shape-inst)) shape-main (when component - (cph/get-shape component (:shape-ref shape-inst))) + (ctn/get-shape component (:shape-ref shape-inst))) initial-root? (:component-root? shape-inst) @@ -545,9 +506,9 @@ set-remote-synced? (change-remote-synced shape-inst container true)) - children-inst (mapv #(cph/get-shape container %) + children-inst (mapv #(ctn/get-shape container %) (:shapes shape-inst)) - children-main (mapv #(cph/get-shape component %) + children-main (mapv #(ctn/get-shape component %) (:shapes shape-main)) only-inst (fn [changes child-inst] @@ -610,11 +571,11 @@ the values in the shape and all its children." [changes libraries container shape-id] (log/debug :msg "Sync shape inverse" :shape (str shape-id)) - (let [shape-inst (cph/get-shape container shape-id) + (let [shape-inst (ctn/get-shape container shape-id) component (cph/get-component libraries (:component-file shape-inst) (:component-id shape-inst)) - shape-main (cph/get-shape component (:shape-ref shape-inst)) + shape-main (ctn/get-shape component (:shape-ref shape-inst)) initial-root? (:component-root? shape-inst) @@ -670,9 +631,9 @@ set-remote-synced? (change-remote-synced shape-inst container true)) - children-inst (mapv #(cph/get-shape container %) + children-inst (mapv #(ctn/get-shape container %) (:shapes shape-inst)) - children-main (mapv #(cph/get-shape component %) + children-main (mapv #(ctn/get-shape component %) (:shapes shape-main)) only-inst (fn [changes child-inst] @@ -787,7 +748,7 @@ (defn- add-shape-to-instance [changes component-shape index component container root-instance root-main omit-touched? set-remote-synced?] (log/info :msg (str "ADD [P] " (:name component-shape))) - (let [component-parent-shape (cph/get-shape component (:parent-id component-shape)) + (let [component-parent-shape (ctn/get-shape component (:parent-id component-shape)) parent-shape (d/seek #(cph/is-main-of? component-parent-shape %) (cph/get-children-with-self (:objects container) (:id root-instance))) @@ -813,7 +774,7 @@ original-shape) [_ new-shapes _] - (cph/clone-object component-shape + (ctst/clone-object component-shape (:id parent-shape) (get component :objects) update-new-shape @@ -855,7 +816,7 @@ (defn- add-shape-to-main [changes shape index component page root-instance root-main] (log/info :msg (str "ADD [C] " (:name shape))) - (let [parent-shape (cph/get-shape page (:parent-id shape)) + (let [parent-shape (ctn/get-shape page (:parent-id shape)) component-parent-shape (d/seek #(cph/is-main-of? % parent-shape) (cph/get-children-with-self (:objects component) (:id root-main))) @@ -875,7 +836,7 @@ original-shape)) [_new-shape new-shapes updated-shapes] - (cph/clone-object shape + (ctst/clone-object shape (:id component-parent-shape) (get page :objects) update-new-shape @@ -982,7 +943,7 @@ index-before " -> " index-after)) - (let [parent (cph/get-shape container (:parent-id shape)) + (let [parent (ctn/get-shape container (:parent-id shape)) changes' (-> changes (update :redo-changes conj (make-change diff --git a/frontend/src/app/main/data/workspace/path/drawing.cljs b/frontend/src/app/main/data/workspace/path/drawing.cljs index ff61c094a..fe2f4f55e 100644 --- a/frontend/src/app/main/data/workspace/path/drawing.cljs +++ b/frontend/src/app/main/data/workspace/path/drawing.cljs @@ -8,10 +8,10 @@ (:require [app.common.geom.point :as gpt] [app.common.geom.shapes.path :as upg] - [app.common.pages.helpers :as cph] [app.common.path.commands :as upc] [app.common.path.shapes-to-path :as upsp] [app.common.spec :as us] + [app.common.types.shape-tree :as ctt] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.drawing.common :as dwdc] [app.main.data.workspace.edition :as dwe] @@ -258,7 +258,7 @@ (let [objects (wsh/lookup-page-objects state) content (get-in state [:workspace-drawing :object :content] []) position (get-in content [0 :params] nil) - frame-id (cph/frame-id-by-position objects position)] + frame-id (ctt/frame-id-by-position objects position)] (-> state (assoc-in [:workspace-drawing :object :frame-id] frame-id)))))) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index dbc2a68ba..f26c3400e 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -15,6 +15,7 @@ [app.common.pages.helpers :as cph] [app.common.spec :as us] [app.common.types.page :as ctp] + [app.common.types.shape-tree :as ctt] [app.common.types.shape.interactions :as ctsi] [app.common.uuid :as uuid] [app.main.data.modal :as md] @@ -26,7 +27,6 @@ [app.main.refs :as refs] [app.main.streams :as ms] [app.main.worker :as uw] - [app.util.names :as un] [beicon.core :as rx] [cljs.spec.alpha :as s] [clojure.set :as set] @@ -284,7 +284,7 @@ move to the desired position, and recalculate parents and frames as needed." [all-objects page ids delta it] (let [shapes (map (d/getf all-objects) ids) - unames (volatile! (un/retrieve-used-names (:objects page))) + unames (volatile! (ctt/retrieve-used-names (:objects page))) update-unames! (fn [new-name] (vswap! unames conj new-name)) all-ids (reduce #(into %1 (cons %2 (cph/get-children-ids all-objects %2))) (d/ordered-set) ids) ids-map (into {} (map #(vector % (uuid/next))) all-ids) @@ -319,7 +319,7 @@ (defn- prepare-duplicate-frame-change [changes objects page unames update-unames! ids-map obj delta] (let [new-id (ids-map (:id obj)) - frame-name (un/generate-unique-name @unames (:name obj)) + frame-name (ctt/generate-unique-name @unames (:name obj)) _ (update-unames! frame-name) new-frame (-> obj @@ -354,7 +354,7 @@ (if (some? obj) (let [new-id (ids-map (:id obj)) parent-id (or parent-id frame-id) - name (un/generate-unique-name @unames (:name obj)) + name (ctt/generate-unique-name @unames (:name obj)) _ (update-unames! name) new-obj (-> obj @@ -395,7 +395,7 @@ (let [update-flows (fn [flows] (reduce (fn [flows frame] - (let [name (un/generate-unique-name @unames "Flow-1") + (let [name (ctt/generate-unique-name @unames "Flow-1") _ (vswap! unames conj name) new-flow {:id (uuid/next) :name name diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index 77d526f4b..237ce6029 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -16,6 +16,7 @@ [app.common.types.page :as csp] [app.common.types.shape :as spec.shape] [app.common.types.shape.interactions :as csi] + [app.common.types.shape-tree :as ctt] [app.common.uuid :as uuid] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.edition :as dwe] @@ -23,7 +24,6 @@ [app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.state-helpers :as wsh] [app.main.streams :as ms] - [app.util.names :as un] [beicon.core :as rx] [cljs.spec.alpha :as s] [potok.core :as ptk])) @@ -84,8 +84,8 @@ id (or (:id attrs) (uuid/next)) name (-> objects - (un/retrieve-used-names) - (un/generate-unique-name (:name attrs))) + (ctst/retrieve-used-names) + (ctst/generate-unique-name (:name attrs))) shape (make-new-shape (assoc attrs :id id :name name) diff --git a/frontend/src/app/main/data/workspace/svg_upload.cljs b/frontend/src/app/main/data/workspace/svg_upload.cljs index 3c830bd59..683bc946f 100644 --- a/frontend/src/app/main/data/workspace/svg_upload.cljs +++ b/frontend/src/app/main/data/workspace/svg_upload.cljs @@ -13,15 +13,14 @@ [app.common.geom.shapes :as gsh] [app.common.pages :as cp] [app.common.pages.changes-builder :as pcb] - [app.common.pages.helpers :as cph] [app.common.spec :refer [max-safe-int min-safe-int]] + [app.common.types.shape-tree :as ctt] [app.common.uuid :as uuid] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.selection :as dws] [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.state-helpers :as wsh] [app.util.color :as uc] - [app.util.names :as un] [app.util.path.parser :as upp] [app.util.svg :as usvg] [beicon.core :as rx] @@ -360,7 +359,7 @@ (let [{:keys [tag attrs hidden]} element-data attrs (usvg/format-styles attrs) element-data (cond-> element-data (map? element-data) (assoc :attrs attrs)) - name (un/generate-unique-name unames (or (:id attrs) (tag->name tag))) + name (ctt/generate-unique-name unames (or (:id attrs) (tag->name tag))) att-refs (usvg/find-attr-references attrs) references (usvg/find-def-references (:defs svg-data) att-refs) @@ -437,17 +436,17 @@ (try (let [page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) - frame-id (cph/frame-id-by-position objects position) + frame-id (ctt/frame-id-by-position objects position) selected (wsh/lookup-selected state) [vb-x vb-y vb-width vb-height] (svg-dimensions svg-data) x (- x vb-x (/ vb-width 2)) y (- y vb-y (/ vb-height 2)) - unames (un/retrieve-used-names objects) + unames (ctt/retrieve-used-names objects) svg-name (->> (str/replace (:name svg-data) ".svg" "") - (un/generate-unique-name unames)) + (ctt/generate-unique-name unames)) svg-data (-> svg-data (assoc :x x diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index e8e9268fa..34b2ef920 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -16,6 +16,7 @@ [app.common.pages.common :as cpc] [app.common.pages.helpers :as cph] [app.common.spec :as us] + [app.common.types.shape-tree :as ctt] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.collapse :as dwc] [app.main.data.workspace.guides :as dwg] @@ -752,7 +753,7 @@ (let [position @ms/mouse-position page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) - frame-id (cph/frame-id-by-position objects position) + frame-id (ctt/frame-id-by-position objects position) moving-shapes (->> ids diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index 46302a4a1..35edbc26c 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -10,6 +10,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.pages.helpers :as cph] + [app.common.types.shape-tree :as ctt] [app.main.data.workspace.state-helpers :as wsh] [app.main.store :as st] [okulary.core :as l])) @@ -284,7 +285,7 @@ (l/derived :options workspace-page)) (def workspace-frames - (l/derived cph/get-frames workspace-page-objects =)) + (l/derived ctt/get-frames workspace-page-objects =)) (def workspace-editor (l/derived :workspace-editor st/state)) diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index 240a44201..66b8ee2c4 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -21,6 +21,7 @@ [app.common.geom.shapes.bounds :as gsb] [app.common.math :as mth] [app.common.pages.helpers :as cph] + [app.common.types.shape-tree :as ctst] [app.config :as cfg] [app.main.fonts :as fonts] [app.main.ui.context :as muc] @@ -61,7 +62,7 @@ (defn- calculate-dimensions [objects] (let [bounds - (->> (cph/get-root-objects objects) + (->> (ctst/get-root-objects objects) (map (partial gsb/get-object-bounds objects)) (gsh/join-rects))] (-> bounds diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs index 18035e283..5efd82332 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs @@ -10,6 +10,7 @@ [app.common.data.macros :as dm] [app.common.pages.helpers :as cph] [app.common.types.page :as ctp] + [app.common.types.shape-tree :as ctt] [app.common.types.shape.interactions :as ctsi] [app.common.uuid :as uuid] [app.main.data.workspace :as dw] @@ -182,7 +183,7 @@ (let [objects (deref refs/workspace-page-objects) destination (get objects (:destination interaction)) - frames (mf/with-memo [objects] (cph/get-viewer-frames objects {:all-frames? (not= :navigate (:action-type interaction))})) + frames (mf/with-memo [objects] (ctt/get-viewer-frames objects {:all-frames? (not= :navigate (:action-type interaction))})) overlay-pos-type (:overlay-pos-type interaction) close-click-outside? (:close-click-outside interaction false) diff --git a/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs b/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs index ece6b20b2..6f1691283 100644 --- a/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs @@ -9,7 +9,7 @@ [app.common.data :as d] [app.common.geom.shapes :as gsh] [app.common.math :as mth] - [app.common.pages.helpers :as cph] + [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] [app.main.refs :as refs] [app.util.geom.grid :as gg] @@ -134,7 +134,7 @@ [:g.grid-display {:style {:pointer-events "none"}} (for [frame frames] (when (and (not (is-transform? frame)) - (not (cph/rotated-frame? frame)) + (not (ctst/rotated-frame? frame)) (or (empty? focus) (contains? focus (:id frame)))) [:& grid-display-frame {:key (str "grid-" (:id frame)) :zoom zoom diff --git a/frontend/src/app/main/ui/workspace/viewport/guides.cljs b/frontend/src/app/main/ui/workspace/viewport/guides.cljs index ed338e282..067db2303 100644 --- a/frontend/src/app/main/ui/workspace/viewport/guides.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/guides.cljs @@ -11,6 +11,7 @@ [app.common.geom.shapes :as gsh] [app.common.math :as mth] [app.common.pages.helpers :as cph] + [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] [app.main.data.workspace :as dw] [app.main.refs :as refs] @@ -292,7 +293,7 @@ (when (or (nil? frame) (and (cph/root-frame? frame) - (not (cph/rotated-frame? frame)))) + (not (ctst/rotated-frame? frame)))) [:g.guide-area {:opacity (when frame-guide-outside? 0)} (when-not disabled-guides? (let [{:keys [x y width height]} (guide-area-axis pos vbox zoom frame axis)] diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs index a6f488149..2909ab0b4 100644 --- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs @@ -10,6 +10,7 @@ [app.common.geom.shapes :as gsh] [app.common.pages :as cp] [app.common.pages.helpers :as cph] + [app.common.types.shape-tree :as ctt] [app.main.data.shortcuts :as dsc] [app.main.data.workspace :as dw] [app.main.data.workspace.path.shortcuts :as psc] @@ -183,7 +184,7 @@ ids (into (d/ordered-set) - (cph/sort-z-index objects ids {:bottom-frames? mod?})) + (ctt/sort-z-index objects ids {:bottom-frames? mod?})) grouped? (fn [id] (contains? #{:group :bool} (get-in objects [id :type]))) @@ -218,7 +219,7 @@ (let [root-frame-ids (mf/use-memo (mf/deps objects) - #(cph/get-root-shapes-ids objects)) + #(ctt/get-root-shapes-ids objects)) modifiers (select-keys modifiers root-frame-ids)] (sfd/use-dynamic-modifiers objects globals/document modifiers))) @@ -229,7 +230,7 @@ (defn setup-active-frames [objects hover-ids selected active-frames zoom transform vbox] - (let [all-frames (mf/use-memo (mf/deps objects) #(cph/get-root-frames-ids objects)) + (let [all-frames (mf/use-memo (mf/deps objects) #(ctt/get-root-frames-ids objects)) selected-frames (mf/use-memo (mf/deps selected) #(->> all-frames (filter selected))) xf-selected-frame (comp (remove cph/root-frame?) diff --git a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs index 56725968f..1ae92aa12 100644 --- a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs @@ -10,7 +10,7 @@ [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] - [app.common.pages.helpers :as cph] + [app.common.types.shape-tree :as ctt] [app.common.uuid :as uuid] [app.main.data.workspace :as dw] [app.main.data.workspace.interactions :as dwi] @@ -178,7 +178,7 @@ on-frame-enter (unchecked-get props "on-frame-enter") on-frame-leave (unchecked-get props "on-frame-leave") on-frame-select (unchecked-get props "on-frame-select") - frames (cph/get-frames objects)] + frames (ctt/get-frames objects)] [:g.frame-titles (for [frame frames] diff --git a/frontend/src/app/util/geom/snap_points.cljs b/frontend/src/app/util/geom/snap_points.cljs index 1940deaf7..8a7a1cbe6 100644 --- a/frontend/src/app/util/geom/snap_points.cljs +++ b/frontend/src/app/util/geom/snap_points.cljs @@ -8,7 +8,8 @@ (:require [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] - [app.common.pages.helpers :as cph])) + [app.common.pages.helpers :as cph] + [app.common.types.shape-tree :as ctst])) (defn selrect-snap-points [{:keys [x y width height] :as selrect}] #{(gpt/point x y) @@ -38,7 +39,7 @@ (cond (and (some? frame) - (not (cph/rotated-frame? frame)) + (not (ctst/rotated-frame? frame)) (not (cph/root-frame? frame))) #{} diff --git a/frontend/src/app/util/names.cljs b/frontend/src/app/util/names.cljs deleted file mode 100644 index 6a2288fcd..000000000 --- a/frontend/src/app/util/names.cljs +++ /dev/null @@ -1,38 +0,0 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public -;; 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) UXBOX Labs SL - -(ns app.util.names - (:require - [app.common.data :as d] - [app.common.spec :as us] - [cljs.spec.alpha :as s])) - -(s/def ::set-of-string (s/every string? :kind set?)) - -(defn- extract-numeric-suffix - [basename] - (if-let [[_ p1 p2] (re-find #"(.*)-([0-9]+)$" basename)] - [p1 (+ 1 (d/parse-integer p2))] - [basename 1])) - -(defn retrieve-used-names - [objects] - (into #{} (comp (map :name) (remove nil?)) (vals objects))) - -(defn generate-unique-name - "A unique name generator" - [used basename] - (s/assert ::set-of-string used) - (s/assert ::us/string basename) - (if-not (contains? used basename) - basename - (let [[prefix initial] (extract-numeric-suffix basename)] - (loop [counter initial] - (let [candidate (str prefix "-" counter)] - (if (contains? used candidate) - (recur (inc counter)) - candidate)))))) - diff --git a/frontend/src/app/util/snap_data.cljs b/frontend/src/app/util/snap_data.cljs index 81f60b952..916f1b992 100644 --- a/frontend/src/app/util/snap_data.cljs +++ b/frontend/src/app/util/snap_data.cljs @@ -12,6 +12,7 @@ [app.common.data :as d] [app.common.pages.diff :as diff] [app.common.pages.helpers :as cph] + [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] [app.util.geom.grid :as gg] [app.util.geom.snap-points :as snap] @@ -55,7 +56,7 @@ (defn get-grids-snap-points [frame coord] - (if (not (cph/rotated-frame? frame)) + (if (not (ctst/rotated-frame? frame)) [] (let [grid->snap (fn [[grid-type position]] {:type :layout @@ -196,7 +197,7 @@ (defn add-page "Adds page information" [snap-data {:keys [objects options] :as page}] - (let [frames (cph/get-frames objects) + (let [frames (ctst/get-frames objects) shapes (->> (vals (:objects page)) (remove cph/frame-shape?)) guides (vals (:guides options)) diff --git a/frontend/test/app/components_basic_test.cljs b/frontend/test/app/components_basic_test.cljs index b392e7100..bc0d2b744 100644 --- a/frontend/test/app/components_basic_test.cljs +++ b/frontend/test/app/components_basic_test.cljs @@ -3,6 +3,7 @@ [app.common.data :as d] [app.common.geom.point :as gpt] [app.common.pages.helpers :as cph] + [app.common.types.container :as ctc] [app.main.data.workspace :as dw] [app.main.data.workspace.groups :as dwg] [app.main.data.workspace.libraries :as dwl] @@ -520,7 +521,7 @@ ; (let [page (thp/current-page new-state) shape1 (thp/get-shape new-state :shape1) - parent1 (cph/get-shape page (:parent-id shape1)) + parent1 (ctc/get-shape page (:parent-id shape1)) [[group shape1 shape2] [c-group c-shape1 c-shape2] diff --git a/frontend/test/app/components_sync_test.cljs b/frontend/test/app/components_sync_test.cljs index b3d754a37..442b8c60f 100644 --- a/frontend/test/app/components_sync_test.cljs +++ b/frontend/test/app/components_sync_test.cljs @@ -4,6 +4,7 @@ [app.common.data :as d] [app.common.geom.point :as gpt] [app.common.pages.helpers :as cph] + [app.common.types.container :as ctc] [app.main.data.workspace :as dw] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.shapes :as dwsh] @@ -1352,7 +1353,7 @@ instance1 (thp/get-shape state :instance1) instance2 (thp/get-shape state :instance2) - shape2 (cph/get-shape (wsh/lookup-page state) + shape2 (ctc/get-shape (wsh/lookup-page state) (first (:shapes instance2))) update-fn1 (fn [shape] diff --git a/frontend/test/app/test_helpers/libraries.cljs b/frontend/test/app/test_helpers/libraries.cljs index f3644d8e3..428653234 100644 --- a/frontend/test/app/test_helpers/libraries.cljs +++ b/frontend/test/app/test_helpers/libraries.cljs @@ -8,6 +8,7 @@ [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.common.pages.helpers :as cph] + [app.common.types.container :as ctc] [app.main.data.workspace :as dw] [app.main.data.workspace.libraries-helpers :as dwlh] [app.main.data.workspace.state-helpers :as wsh] @@ -59,7 +60,7 @@ verify that they are a well constructed instance tree." [state root-inst-id] (let [page (thp/current-page state) - root-inst (cph/get-shape page root-inst-id) + root-inst (ctc/get-shape page root-inst-id) shapes-inst (cph/get-children-with-self (:objects page) root-inst-id)] (is-instance-root (first shapes-inst)) @@ -72,7 +73,7 @@ verify that they are not a component instance." [state root-inst-id] (let [page (thp/current-page state) - root-inst (cph/get-shape page root-inst-id) + root-inst (ctc/get-shape page root-inst-id) shapes-inst (cph/get-children-with-self (:objects page) root-inst-id)] (run! is-noninstance shapes-inst) @@ -84,7 +85,7 @@ the main component and all its shapes." [state root-inst-id] (let [page (thp/current-page state) - root-inst (cph/get-shape page root-inst-id) + root-inst (ctc/get-shape page root-inst-id) libs (wsh/get-libraries state) component (cph/get-component libs (:component-id root-inst)) @@ -102,7 +103,7 @@ (cph/get-component libs (:component-id component-shape)) main-shape - (cph/get-shape component (:shape-ref shape))] + (ctc/get-shape component (:shape-ref shape))] (t/is (some? main-shape))))] @@ -122,7 +123,7 @@ corresponding component shape missing." [state root-inst-id] (let [page (thp/current-page state) - root-inst (cph/get-shape page root-inst-id) + root-inst (ctc/get-shape page root-inst-id) libs (wsh/get-libraries state) component (cph/get-component libs (:component-id root-inst)) @@ -140,7 +141,7 @@ (cph/get-component libs (:component-id component-shape)) main-shape - (cph/get-shape component (:shape-ref shape))] + (ctc/get-shape component (:shape-ref shape))] (t/is (some? main-shape))))]