From a3eb63474098a03b2253dee0c00fd0fe85a498ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Mon, 5 Oct 2020 11:01:14 +0200 Subject: [PATCH 1/4] :sparkles: Preserve origin component in nested instances --- common/app/common/pages.cljc | 3 +- common/app/common/pages_helpers.cljc | 2 +- frontend/src/app/main/data/workspace.cljs | 2 - .../app/main/data/workspace/libraries.cljs | 22 ++++++--- .../data/workspace/libraries_helpers.cljs | 22 ++++++--- frontend/src/app/main/store.cljs | 49 ++++++++++++------- .../app/main/ui/workspace/context_menu.cljs | 39 ++++++++------- 7 files changed, 83 insertions(+), 56 deletions(-) diff --git a/common/app/common/pages.cljc b/common/app/common/pages.cljc index 74f14b057c..9ba3cbd0b8 100644 --- a/common/app/common/pages.cljc +++ b/common/app/common/pages.cljc @@ -46,6 +46,7 @@ (<= % max-safe-int))) (s/def ::component-id uuid?) (s/def ::component-file uuid?) +(s/def ::component-root? boolean?) (s/def ::shape-ref uuid?) (s/def ::safe-number @@ -122,7 +123,6 @@ (s/def :internal.shape/line-height ::safe-number) (s/def :internal.shape/locked boolean?) (s/def :internal.shape/page-id uuid?) -(s/def :internal.shape/component-id uuid?) (s/def :internal.shape/proportion ::safe-number) (s/def :internal.shape/proportion-lock boolean?) (s/def :internal.shape/rx ::safe-number) @@ -255,6 +255,7 @@ (s/keys :opt-un [::id ::component-id ::component-file + ::component-root? ::shape-ref]))) (s/def :internal.page/objects (s/map-of uuid? ::shape)) diff --git a/common/app/common/pages_helpers.cljc b/common/app/common/pages_helpers.cljc index c1e87dc26f..f915ad9ee7 100644 --- a/common/app/common/pages_helpers.cljc +++ b/common/app/common/pages_helpers.cljc @@ -35,7 +35,7 @@ "Get the root shape linked to the component for this shape, if any" [id objects] (let [obj (get objects id)] - (if-let [component-id (:component-id obj)] + (if-let [component-id (:component-root? obj)] id (if-let [parent-id (:parent-id obj)] (get-root-component parent-id objects) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index e809a4c0bd..7349ea59a1 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1149,11 +1149,9 @@ (let [page-id (:current-page-id state) objects (dwc/lookup-page-objects state page-id) root-id (cph/get-root-component (:id shape) objects) - root-shape (get objects root-id) mdata {:position position :shape shape - :root-shape root-shape :selected (get-in state [:workspace-local :selected])}] (-> state (assoc-in [:workspace-local :context-menu] mdata)))) diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 21807df1f4..078e8864ae 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -155,6 +155,9 @@ {:type :set :attr :component-file :val nil} + {:type :set + :attr :component-root? + :val (:component-root? updated-shape)} {:type :set :attr :shape-ref :val (:shape-ref updated-shape)}]}) @@ -176,6 +179,9 @@ {:type :set :attr :component-file :val (:component-file original-shape)} + {:type :set + :attr :component-root? + :val (:component-root? original-shape)} {:type :set :attr :shape-ref :val (:shape-ref original-shape)}]})) @@ -242,7 +248,8 @@ (assoc $ :shape-ref (:id original-shape))) (nil? (:parent-id original-shape)) - (assoc :component-id (:id original-shape)) + (assoc :component-id (:id original-shape) + :component-root? true) (and (nil? (:parent-id original-shape)) (some? file-id)) (assoc :component-file file-id) @@ -251,7 +258,7 @@ (dissoc :component-file) (some? (:parent-id original-shape)) - (dissoc :component-id :component-file)))) + (dissoc :component-root?)))) [new-shape new-shapes _] (cph/clone-object component-shape @@ -285,9 +292,7 @@ (watch [_ state stream] (let [page-id (:current-page-id state) objects (dwc/lookup-page-objects state page-id) - root-id (cph/get-root-component id objects) - - shapes (cph/get-object-with-children root-id objects) + shapes (cph/get-object-with-children id objects) rchanges (map (fn [obj] {:type :mod-obj @@ -354,7 +359,6 @@ (let [page-id (:current-page-id state) page (get-in state [:workspace-data :pages-index page-id]) objects (dwc/lookup-page-objects state page-id) - root-id (cph/get-root-component id objects) root-shape (get objects id) file-id (get root-shape :component-file) @@ -381,7 +385,6 @@ (watch [_ state stream] (let [page-id (:current-page-id state) objects (dwc/lookup-page-objects state page-id) - root-id (cph/get-root-component id objects) root-shape (get objects id) component-id (get root-shape :component-id) @@ -483,7 +486,10 @@ (ptk/reify ::sync-file-2nd-stage ptk/WatchEvent (watch [_ state stream] - (let [[rchanges uchanges] (dwlh/generate-sync-file :components nil state)] + (let [[rchanges1 uchanges1] (dwlh/generate-sync-file :components nil state) + [rchanges2 uchanges2] (dwlh/generate-sync-library :components file-id state) + rchanges (d/concat rchanges1 rchanges2) + uchanges (d/concat uchanges1 uchanges2)] (when rchanges (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}))))))) diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index 8225ea7b64..4b341d96ce 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -97,7 +97,7 @@ [asset-type library-id] (case asset-type :components - (fn [shape] (and (some? (:component-id shape)) + (fn [shape] (and (:component-root? shape) (= (:component-file shape) library-id))) :colors @@ -256,12 +256,20 @@ from parent and frame. Update the original shapes to have links to the new ones." [shape objects] + (assert (nil? (:component-id shape))) + (assert (nil? (:component-file shape))) + (assert (nil? (:shape-ref shape))) (let [update-new-shape (fn [new-shape original-shape] - (assoc new-shape :frame-id nil)) + (cond-> new-shape + true + (assoc :frame-id nil) + (nil? (:parent-id new-shape)) + (assoc :component-root? true))) + + ;; Make the original shape an instance of the new component. ;; If one of the original shape children already was a component - ;; instance, the 'instanceness' is copied into the new component, - ;; and the original shape now points to the new component. + ;; instance, the 'instanceness' is copied into the new component. update-original-shape (fn [original-shape new-shape] (cond-> original-shape true @@ -269,11 +277,11 @@ (nil? (:parent-id new-shape)) (assoc :component-id (:id new-shape) - :component-file nil) + :component-file nil + :component-root? true) (some? (:parent-id new-shape)) - (assoc :component-id nil - :component-file nil)))] + (dissoc :component-root?)))] (cph/clone-object shape nil objects update-new-shape update-original-shape))) diff --git a/frontend/src/app/main/store.cljs b/frontend/src/app/main/store.cljs index ac303d734b..b3afec5960 100644 --- a/frontend/src/app/main/store.cljs +++ b/frontend/src/app/main/store.cljs @@ -89,7 +89,9 @@ (letfn [(show-shape [shape-id level objects] (let [shape (get objects shape-id)] (println (str/pad (str (str/repeat " " level) - (:name shape)) + (:name shape) + (when (seq (filter #(not= :position-group %) + (:touched shape))) "*")) {:length 20 :type :right}) (show-component shape objects)) @@ -102,24 +104,35 @@ (show-shape shape-id (inc level) objects)))))) (show-component [shape objects] - (let [root-id (cph/get-root-component (:id shape) objects) - root-shape (when root-id (get objects root-id)) - component-id (when root-shape (:component-id root-shape)) - component-file-id (when root-shape (:component-file root-shape)) - component-file (when component-file-id (get libraries component-file-id)) - shape-ref (:shape-ref shape) - component (when component-id - (if component-file - (get-in component-file [:data :components component-id]) - (get components component-id))) - component-shape (when (and component shape-ref) - (get-in component [:objects shape-ref]))] - (if component-shape - (str/format " %s--> %s%s" - (if (:component-id shape) "#" "-") + (if (nil? (:shape-ref shape)) + "" + (let [root-id (cph/get-root-component (:id shape) objects) + root-shape (when root-id (get objects root-id)) + component-id (when root-shape (:component-id root-shape)) + component-file-id (when root-shape (:component-file root-shape)) + component-file (when component-file-id (get libraries component-file-id)) + component (when component-id + (if component-file + (get-in component-file [:data :components component-id]) + (get components component-id))) + component-shape (when (and component (:shape-ref shape)) + (get-in component [:objects (:shape-ref shape)]))] + (str/format " %s--> %s%s%s" + (if (:component-root? shape) "#" "-") (when component-file (str/format "<%s> " (:name component-file))) - (:name component-shape)) - "")))] + (:name component-shape) + (if (or (:component-root? shape) + (nil? (:component-id shape))) + "" + (let [component-id (:component-id shape) + component-file-id (:component-file shape) + component-file (when component-file-id (get libraries component-file-id)) + component (if component-file + (get-in component-file [:data :components component-id]) + (get components component-id))] + (str/format " (%s%s)" + (when component-file (str/format "<%s> " (:name component-file))) + (:name component))))))))] (println "[Workspace]") (show-shape (:id root) 0 objects) diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index a7330c3cb4..a7fea323be 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -46,7 +46,6 @@ [{:keys [mdata] :as props}] (let [{:keys [id] :as shape} (:shape mdata) selected (:selected mdata) - root-shape (:root-shape mdata) do-duplicate #(st/emit! dw/duplicate-selected) do-delete #(st/emit! dw/delete-selected) @@ -69,7 +68,7 @@ (st/emit! (dwl/update-component id)) (st/emit! (dwl/sync-file nil))) do-navigate-component-file #(st/emit! (dwl/nav-to-component-file - (:component-file root-shape)))] + (:component-file shape)))] [:* [:& menu-entry {:title "Copy" :shortcut "Ctrl + c" @@ -117,28 +116,30 @@ [:& menu-entry {:title "Lock" :on-click do-lock-shape}]) - [:& menu-separator] - - (if (nil? (:shape-ref shape)) - [:& menu-entry {:title "Create component" - :shortcut "Ctrl + K" - :on-click do-add-component}] + (when (nil? (:shape-ref shape)) [:* - [:& menu-entry {:title "Detach instance" - :on-click do-detach-component}] - [:& menu-entry {:title "Reset overrides" - :on-click do-reset-component}] - (if (nil? (:component-file root-shape)) - [:& menu-entry {:title "Update master component" - :on-click do-update-component}] - [:& menu-entry {:title "Go to master component file" - :on-click do-navigate-component-file}])]) + [:& menu-separator] + [:& menu-entry {:title "Create component" + :shortcut "Ctrl + K" + :on-click do-add-component}]]) + + (when (:component-id shape) + [:* + [:& menu-separator] + [:& menu-entry {:title "Detach instance" + :on-click do-detach-component}] + [:& menu-entry {:title "Reset overrides" + :on-click do-reset-component}] + (if (nil? (:component-file shape)) + [:& menu-entry {:title "Update master component" + :on-click do-update-component}] + [:& menu-entry {:title "Go to master component file" + :on-click do-navigate-component-file}])]) [:& menu-separator] [:& menu-entry {:title "Delete" :shortcut "Supr" - :on-click do-delete}] - ])) + :on-click do-delete}]])) (mf/defc viewport-context-menu [{:keys [mdata] :as props}] From 7c75b75f5b8a95864c6f7c269da96d28a149a6cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Tue, 6 Oct 2020 15:04:16 +0200 Subject: [PATCH 2/4] :recycle: Refactor update master component function --- .../app/main/data/workspace/libraries.cljs | 58 ++----- .../data/workspace/libraries_helpers.cljs | 152 +++++++++++++----- 2 files changed, 122 insertions(+), 88 deletions(-) diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 078e8864ae..8fb6939972 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -386,56 +386,18 @@ (let [page-id (:current-page-id state) objects (dwc/lookup-page-objects state page-id) root-shape (get objects id) + file-id (get root-shape :component-file) - component-id (get root-shape :component-id) - component-objs (dwc/lookup-component-objects state component-id) - component-obj (get component-objs component-id) + components + (if (nil? file-id) + (get-in state [:workspace-data :components]) + (get-in state [:workspace-libraries file-id :data :components])) - ;; Clone again the original shape and its children, maintaing - ;; the ids of the cloned shapes. If the original shape has some - ;; new child shapes, the cloned ones will have new generated ids. - update-new-shape (fn [new-shape original-shape] - (cond-> new-shape - true - (assoc :frame-id nil) - - (= (:component-id original-shape) component-id) - (dissoc :component-id) - - (some? (:shape-ref original-shape)) - (assoc :id (:shape-ref original-shape)))) - - touch-shape (fn [original-shape _] - (into {} original-shape)) - - [new-shape new-shapes original-shapes] - (cph/clone-object root-shape nil objects update-new-shape touch-shape) - - rchanges (d/concat - [{:type :mod-component - :id component-id - :name (:name new-shape) - :shapes new-shapes}] - (map (fn [shape] - {:type :mod-obj - :page-id page-id - :id (:id shape) - :operations [{:type :set-touched - :touched nil}]}) - original-shapes)) - - uchanges (d/concat - [{:type :mod-component - :id component-id - :name (:name component-obj) - :shapes (vals component-objs)}] - (map (fn [shape] - {:type :mod-obj - :page-id page-id - :id (:id shape) - :operations [{:type :set-touched - :touched (:touched shape)}]}) - original-shapes))] + [rchanges uchanges] + (dwlh/generate-sync-shape-inverse root-shape + objects + components + page-id)] (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))) diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index 4b341d96ce..e5e6835a23 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -24,12 +24,53 @@ (declare generate-sync-component-components) (declare generate-sync-shape-and-children-components) -(declare generate-sync-shape-components) +(declare generate-sync-shape-inverse) +(declare generate-sync-shape<-component) +(declare generate-sync-shape->component) (declare remove-component-and-ref) (declare remove-ref) +(declare reset-touched) (declare update-attrs) (declare calc-new-pos) + +;; ---- Create a new component ---- + +(defn make-component-shape + "Clone the shape and all children. Generate new ids and detach + from parent and frame. Update the original shapes to have links + to the new ones." + [shape objects] + (assert (nil? (:component-id shape))) + (assert (nil? (:component-file shape))) + (assert (nil? (:shape-ref shape))) + (let [update-new-shape (fn [new-shape original-shape] + (cond-> new-shape + true + (assoc :frame-id nil) + + (nil? (:parent-id new-shape)) + (assoc :component-root? true))) + + ;; Make the original shape an instance of the new component. + ;; If one of the original shape children already was a component + ;; instance, the 'instanceness' is copied into the new component. + update-original-shape (fn [original-shape new-shape] + (cond-> original-shape + true + (assoc :shape-ref (:id new-shape)) + + (nil? (:parent-id new-shape)) + (assoc :component-id (:id new-shape) + :component-file nil + :component-root? true) + + (some? (:parent-id new-shape)) + (dissoc :component-root?)))] + + (cph/clone-object shape nil objects update-new-shape update-original-shape))) + + ;; ---- General library synchronization functions ---- (defn generate-sync-file @@ -249,43 +290,6 @@ (generate-sync-text-shape shape page-id component-id update-node))) -;; ---- Create a new component ---- - -(defn make-component-shape - "Clone the shape and all children. Generate new ids and detach - from parent and frame. Update the original shapes to have links - to the new ones." - [shape objects] - (assert (nil? (:component-id shape))) - (assert (nil? (:component-file shape))) - (assert (nil? (:shape-ref shape))) - (let [update-new-shape (fn [new-shape original-shape] - (cond-> new-shape - true - (assoc :frame-id nil) - - (nil? (:parent-id new-shape)) - (assoc :component-root? true))) - - ;; Make the original shape an instance of the new component. - ;; If one of the original shape children already was a component - ;; instance, the 'instanceness' is copied into the new component. - update-original-shape (fn [original-shape new-shape] - (cond-> original-shape - true - (assoc :shape-ref (:id new-shape)) - - (nil? (:parent-id new-shape)) - (assoc :component-id (:id new-shape) - :component-file nil - :component-root? true) - - (some? (:parent-id new-shape)) - (dissoc :component-root?)))] - - (cph/clone-object shape nil objects update-new-shape update-original-shape))) - - ;; ---- Component synchronization helpers ---- (defn generate-sync-shape-and-children-components @@ -305,7 +309,7 @@ (if (nil? shape) [rchanges uchanges] (let [[shape-rchanges shape-uchanges] - (generate-sync-shape-components + (generate-sync-shape<-component shape root-shape root-component @@ -317,7 +321,33 @@ (d/concat rchanges shape-rchanges) (d/concat uchanges shape-uchanges)))))))) -(defn generate-sync-shape-components +(defn generate-sync-shape-inverse + "Generate changes to update the component a shape is linked to, from + the values in the shape and all its children. It acts like the above + function with reset-touched? as true. Also clears the 'touched' flags + in the source shapes." + [root-shape objects components page-id] + (let [all-shapes (cph/get-object-with-children (:id root-shape) objects) + component (get components (:component-id root-shape)) + root-component (get-in component [:objects (:shape-ref root-shape)])] + (loop [shapes (seq all-shapes) + rchanges [] + uchanges []] + (let [shape (first shapes)] + (if (nil? shape) + [rchanges uchanges] + (let [[shape-rchanges shape-uchanges] + (generate-sync-shape->component + shape + root-shape + root-component + component + page-id)] + (recur (next shapes) + (d/concat rchanges shape-rchanges) + (d/concat uchanges shape-uchanges)))))))) + +(defn generate-sync-shape<-component "Generate changes to synchronize one shape that is linked to other shape inside a component. Same considerations as above about reset-touched?" [shape root-shape root-component component page-id component-id reset-touched?] @@ -334,6 +364,33 @@ component-id reset-touched?))))) +(defn generate-sync-shape->component + "Generate changes to synchronize one shape inside a component, with other + shape that is linked to it." + [shape root-shape root-component component page-id] + (if (nil? component) + empty-changes + (let [component-shape (get (:objects component) (:shape-ref shape))] + (if (nil? component-shape) + empty-changes + (let [[rchanges1 uchanges1] + (update-attrs component-shape + shape + root-component + root-shape + nil + (:id root-component) + true) + [rchanges2 uchanges2] + (reset-touched shape + page-id + nil)] + [(d/concat rchanges1 rchanges2) + (d/concat uchanges2 uchanges2)]))))) + + +; ---- Operation generation helpers ---- + (defn remove-component-and-ref [shape page-id component-id] [[(d/without-nils {:type :mod-obj @@ -388,6 +445,21 @@ {:type :set-touched :touched (:touched shape)}]})]]) +(defn reset-touched + [shape page-id component-id] + [[(d/without-nils {:type :mod-obj + :id (:id shape) + :page-id page-id + :component-id component-id + :operations [{:type :set-touched + :touched nil}]})] + [(d/without-nils {:type :mod-obj + :id (:id shape) + :page-id page-id + :component-id component-id + :operations [{:type :set-touched + :touched (:touched shape)}]})]]) + (defn update-attrs "The main function that implements the sync algorithm." [shape component-shape root-shape root-component page-id component-id reset-touched?] From 68ca44188cf69909fad933a5f28d7414812e308d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Tue, 6 Oct 2020 15:44:42 +0200 Subject: [PATCH 3/4] :sparkles: Enhance synchronization of a component with subcomponents --- common/app/common/pages.cljc | 22 +- common/app/common/pages_helpers.cljc | 20 +- frontend/src/app/main/data/workspace.cljs | 1 - .../app/main/data/workspace/libraries.cljs | 84 ++-- .../data/workspace/libraries_helpers.cljs | 442 ++++++++++-------- frontend/src/app/main/store.cljs | 7 +- .../app/main/ui/workspace/context_menu.cljs | 5 +- .../app/main/ui/workspace/sidebar/layers.cljs | 4 +- 8 files changed, 346 insertions(+), 239 deletions(-) diff --git a/common/app/common/pages.cljc b/common/app/common/pages.cljc index 9ba3cbd0b8..81791d6520 100644 --- a/common/app/common/pages.cljc +++ b/common/app/common/pages.cljc @@ -236,12 +236,8 @@ :width :size-group :height :size-group :proportion :size-group - :x :position-group - :y :position-group :rx :radius-group - :ry :radius-group - :points :points-group - :transform :transform-group}) + :ry :radius-group}) (def color-sync-attrs [:fill-color :stroke-color]) @@ -892,21 +888,21 @@ (defmethod process-operation :set [shape op] - (let [attr (:attr op) - val (:val op) - ignore (:ignore-touched op) + (let [attr (:attr op) + val (:val op) + ignore (:ignore-touched op) shape-ref (:shape-ref shape) - group (get component-sync-attrs attr)] + group (get component-sync-attrs attr)] (cond-> shape + (and shape-ref group (not ignore) (not= val (get shape attr))) + (update :touched #(conj (or % #{}) group)) + (nil? val) (dissoc attr) (some? val) - (assoc attr val) - - (and shape-ref group (not ignore)) - (update :touched #(conj (or % #{}) group))))) + (assoc attr val)))) (defmethod process-operation :set-touched [shape op] diff --git a/common/app/common/pages_helpers.cljc b/common/app/common/pages_helpers.cljc index f915ad9ee7..5edbfd70c9 100644 --- a/common/app/common/pages_helpers.cljc +++ b/common/app/common/pages_helpers.cljc @@ -31,15 +31,15 @@ (update page :objects #(into % (d/index-by :id objects-list)))) -(defn get-root-component - "Get the root shape linked to the component for this shape, if any" - [id objects] - (let [obj (get objects id)] - (if-let [component-id (:component-root? obj)] - id - (if-let [parent-id (:parent-id obj)] - (get-root-component parent-id objects) - nil)))) +(defn get-root-shape + "Get the root shape linked to a component for this shape, if any" + [shape objects] + (if (:component-root? shape) + shape + (if-let [parent-id (:parent-id shape)] + (get-root-shape (get objects (:parent-id shape)) + objects) + nil))) (defn get-children "Retrieve all children ids recursively for a given object" @@ -58,7 +58,7 @@ (defn get-object-with-children "Retrieve a list with an object and all of its children" [id objects] - (map #(get objects %) (concat [id] (get-children id objects)))) + (map #(get objects %) (d/concat [id] (get-children id objects)))) (defn is-shape-grouped "Checks if a shape is inside a group" diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 7349ea59a1..5fcd337cd8 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1148,7 +1148,6 @@ (update [_ state] (let [page-id (:current-page-id state) objects (dwc/lookup-page-objects state page-id) - root-id (cph/get-root-component (:id shape) objects) mdata {:position position :shape shape diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 8fb6939972..15a0e254dd 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -160,7 +160,10 @@ :val (:component-root? updated-shape)} {:type :set :attr :shape-ref - :val (:shape-ref updated-shape)}]}) + :val (:shape-ref updated-shape)} + {:type :set + :attr :touched + :val (:touched updated-shape)}]}) updated-shapes)) uchanges (conj uchanges @@ -184,9 +187,13 @@ :val (:component-root? original-shape)} {:type :set :attr :shape-ref - :val (:shape-ref original-shape)}]})) + :val (:shape-ref original-shape)} + {:type :set + :attr :touched + :val (:touched original-shape)}]})) updated-shapes))] + (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}) (dws/select-shapes (d/ordered-set (:id group)))))))))) @@ -245,7 +252,8 @@ (dwc/calculate-frame-overlap all-frames $)) (assoc $ :parent-id (or (:parent-id $) (:frame-id $))) - (assoc $ :shape-ref (:id original-shape))) + (assoc $ :shape-ref (:id original-shape)) + (dissoc $ :touched)) (nil? (:parent-id original-shape)) (assoc :component-id (:id original-shape) @@ -356,25 +364,35 @@ (ptk/reify ::reset-component ptk/WatchEvent (watch [_ state stream] - (let [page-id (:current-page-id state) - page (get-in state [:workspace-data :pages-index page-id]) - objects (dwc/lookup-page-objects state page-id) - root-shape (get objects id) - file-id (get root-shape :component-file) + (js/console.info "##### RESET-COMPONENT of shape" (str id)) + (let [page-id (:current-page-id state) + page (get-in state [:workspace-data :pages-index page-id]) + objects (dwc/lookup-page-objects state page-id) + shape (get objects id) + file-id (get shape :component-file) - components - (if (nil? file-id) - (get-in state [:workspace-data :components]) - (get-in state [:workspace-libraries file-id :data :components])) + [all-shapes component root-component] + (dwlh/resolve-shapes-and-components shape + objects + state + true) + + _ (js/console.info "shape" (:name shape) "<- component" (:name component)) + _ (js/console.debug "all-shapes" (clj->js all-shapes)) + _ (js/console.debug "component" (clj->js component)) + _ (js/console.debug "root-component" (clj->js root-component)) [rchanges uchanges] - (dwlh/generate-sync-shape-and-children-components root-shape - objects - components + (dwlh/generate-sync-shape-and-children-components shape + all-shapes + component + root-component (:id page) nil true)] + (js/console.debug "rchanges" (clj->js rchanges)) + (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))) (defn update-component @@ -383,22 +401,32 @@ (ptk/reify ::update-component ptk/WatchEvent (watch [_ state stream] - (let [page-id (:current-page-id state) - objects (dwc/lookup-page-objects state page-id) - root-shape (get objects id) - file-id (get root-shape :component-file) + (js/console.info "##### UPDATE-COMPONENT of shape" (str id)) + (let [page-id (:current-page-id state) + objects (dwc/lookup-page-objects state page-id) + shape (get objects id) + file-id (get shape :component-file) - components - (if (nil? file-id) - (get-in state [:workspace-data :components]) - (get-in state [:workspace-libraries file-id :data :components])) + [all-shapes component root-component] + (dwlh/resolve-shapes-and-components shape + objects + state + true) + + _ (js/console.info "shape" (:name shape) "-> component" (:name component)) + _ (js/console.debug "all-shapes" (clj->js all-shapes)) + _ (js/console.debug "component" (clj->js component)) + _ (js/console.debug "root-component" (clj->js root-component)) [rchanges uchanges] - (dwlh/generate-sync-shape-inverse root-shape - objects - components + (dwlh/generate-sync-shape-inverse shape + all-shapes + component + root-component page-id)] + (js/console.debug "rchanges" (clj->js rchanges)) + (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))) (declare sync-file-2nd-stage) @@ -415,6 +443,7 @@ ptk/WatchEvent (watch [_ state stream] + (js/console.info "##### SYNC-FILE" (str (or file-id "local"))) (let [[rchanges1 uchanges1] (dwlh/generate-sync-file :components file-id state) [rchanges2 uchanges2] (dwlh/generate-sync-library :components file-id state) [rchanges3 uchanges3] (dwlh/generate-sync-file :colors file-id state) @@ -423,6 +452,7 @@ [rchanges6 uchanges6] (dwlh/generate-sync-library :typographies file-id state) rchanges (d/concat rchanges1 rchanges2 rchanges3 rchanges4 rchanges5 rchanges6) uchanges (d/concat uchanges1 uchanges2 uchanges3 uchanges4 uchanges5 uchanges6)] + (js/console.debug "rchanges" (clj->js rchanges)) (rx/concat (rx/of (dm/hide-tag :sync-dialog)) (when rchanges @@ -448,11 +478,13 @@ (ptk/reify ::sync-file-2nd-stage ptk/WatchEvent (watch [_ state stream] + (js/console.info "##### SYNC-FILE" (str (or file-id "local")) "(2nd stage)") (let [[rchanges1 uchanges1] (dwlh/generate-sync-file :components nil state) [rchanges2 uchanges2] (dwlh/generate-sync-library :components file-id state) rchanges (d/concat rchanges1 rchanges2) uchanges (d/concat uchanges1 uchanges2)] (when rchanges + (js/console.debug "rchanges" (clj->js rchanges)) (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}))))))) (def ignore-sync diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index e5e6835a23..e9a89be2bf 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -21,8 +21,10 @@ (declare generate-sync-container) (declare generate-sync-shape) +(declare has-asset-reference-fn) -(declare generate-sync-component-components) +(declare get-assets) +(declare resolve-shapes-and-components) (declare generate-sync-shape-and-children-components) (declare generate-sync-shape-inverse) (declare generate-sync-shape<-component) @@ -50,7 +52,10 @@ (assoc :frame-id nil) (nil? (:parent-id new-shape)) - (assoc :component-root? true))) + (dissoc :component-id + :component-file + :component-root? + :shape-ref))) ;; Make the original shape an instance of the new component. ;; If one of the original shape children already was a component @@ -58,7 +63,8 @@ update-original-shape (fn [original-shape new-shape] (cond-> original-shape true - (assoc :shape-ref (:id new-shape)) + (-> (assoc :shape-ref (:id new-shape)) + (dissoc :touched)) (nil? (:parent-id new-shape)) (assoc :component-id (:id new-shape) @@ -96,7 +102,7 @@ (let [[page-rchanges page-uchanges] (generate-sync-container asset-type library-id - library-items + state page (:id page) nil)] @@ -123,7 +129,7 @@ (let [[comp-rchanges comp-uchanges] (generate-sync-container asset-type library-id - library-items + state local-component nil (:id local-component))] @@ -132,7 +138,30 @@ (d/concat uchanges comp-uchanges))) [rchanges uchanges]))))) -(defn has-asset-reference-fn +(defn- generate-sync-container + "Generate changes to synchronize all shapes in a particular container + (a page or a component) that are linked to the given library." + [asset-type library-id state container page-id component-id] + (let [has-asset-reference? (has-asset-reference-fn asset-type library-id) + linked-shapes (cph/select-objects has-asset-reference? container)] + (loop [shapes (seq linked-shapes) + rchanges [] + uchanges []] + (if-let [shape (first shapes)] + (let [[shape-rchanges shape-uchanges] + (generate-sync-shape asset-type + library-id + state + (get container :objects) + page-id + component-id + shape)] + (recur (next shapes) + (d/concat rchanges shape-rchanges) + (d/concat uchanges shape-uchanges))) + [rchanges uchanges])))) + +(defn- has-asset-reference-fn "Gets a function that checks if a shape uses some asset of the given type in the given library." [asset-type library-id] @@ -167,50 +196,28 @@ #(and (some? (:typography-ref-id %)) (= library-id (:typography-ref-file %))))))))) -(defn generate-sync-container - "Generate changes to synchronize all shapes in a particular container - (a page or a component)." - [asset-type library-id library-items container page-id component-id] - (let [has-asset-reference? (has-asset-reference-fn asset-type library-id) - linked-shapes (cph/select-objects has-asset-reference? container)] - (loop [shapes (seq linked-shapes) - rchanges [] - uchanges []] - (if-let [shape (first shapes)] - (let [[shape-rchanges shape-uchanges] - (generate-sync-shape asset-type - library-id - library-items - (get container :objects) - page-id - component-id - shape)] - (recur (next shapes) - (d/concat rchanges shape-rchanges) - (d/concat uchanges shape-uchanges))) - [rchanges uchanges])))) - -(defmulti generate-sync-shape (fn [type _ _ _ _ _ _ _] type)) +(defmulti generate-sync-shape + "Generate changes to synchronize one shape, that use the given type + of asset of the given library." + (fn [type _ _ _ _ _ _ _] type)) (defmethod generate-sync-shape :components - [_ library-id library-items objects page-id component-id shape] + [_ library-id state objects page-id component-id shape] + (let [[all-shapes component root-component] + (resolve-shapes-and-components shape + objects + state + false)] - ;; Synchronize a shape that is the root instance of a component, and all of its - ;; children. All attributes of the component shape that have changed, and whose - ;; group have not been touched in the linked shape, will be copied to the shape. - ;; Any shape that is linked to a no-longer existent component shape will be - ;; detached. - (let [root-shape shape - components library-items - reset-touched? false] - (generate-sync-shape-and-children-components root-shape - objects - components + (generate-sync-shape-and-children-components shape + all-shapes + component + root-component page-id component-id - reset-touched?))) + false))) -(defn generate-sync-text-shape [shape page-id component-id update-node] +(defn- generate-sync-text-shape [shape page-id component-id update-node] (let [old-content (:content shape) new-content (ut/map-node update-node old-content) rchanges [(d/without-nils {:type :mod-obj @@ -232,59 +239,61 @@ [rchanges lchanges]))) (defmethod generate-sync-shape :colors - [_ library-id library-items _ page-id component-id shape] + [_ library-id state _ page-id component-id shape] ;; Synchronize a shape that uses some colors of the library. The value of the ;; color in the library is copied to the shape. - (if (= :text (:type shape)) - (let [update-node (fn [node] - (if-let [color (get library-items (:fill-color-ref-id node))] - (assoc node :fill-color (:value color)) - node))] - (generate-sync-text-shape shape page-id component-id update-node)) - (loop [attrs (seq cp/color-sync-attrs) - roperations [] - uoperations []] - (let [attr (first attrs)] - (if (nil? attr) - (if (empty? roperations) - empty-changes - (let [rchanges [(d/without-nils {:type :mod-obj - :page-id page-id - :component-id component-id - :id (:id shape) - :operations roperations})] - uchanges [(d/without-nils {:type :mod-obj - :page-id page-id - :component-id component-id - :id (:id shape) - :operations uoperations})]] - [rchanges uchanges])) - (let [attr-ref-id (keyword (str (name attr) "-ref-id"))] - (if-not (contains? shape attr-ref-id) - (recur (next attrs) - roperations - uoperations) - (let [color (get library-items (get shape attr-ref-id)) - roperation {:type :set - :attr attr - :val (:value color) - :ignore-touched true} - uoperation {:type :set - :attr attr - :val (get shape attr) - :ignore-touched true}] + (let [colors (get-assets library-id :colors state)] + (if (= :text (:type shape)) + (let [update-node (fn [node] + (if-let [color (get colors (:fill-color-ref-id node))] + (assoc node :fill-color (:value color)) + node))] + (generate-sync-text-shape shape page-id component-id update-node)) + (loop [attrs (seq cp/color-sync-attrs) + roperations [] + uoperations []] + (let [attr (first attrs)] + (if (nil? attr) + (if (empty? roperations) + empty-changes + (let [rchanges [(d/without-nils {:type :mod-obj + :page-id page-id + :component-id component-id + :id (:id shape) + :operations roperations})] + uchanges [(d/without-nils {:type :mod-obj + :page-id page-id + :component-id component-id + :id (:id shape) + :operations uoperations})]] + [rchanges uchanges])) + (let [attr-ref-id (keyword (str (name attr) "-ref-id"))] + (if-not (contains? shape attr-ref-id) (recur (next attrs) - (conj roperations roperation) - (conj uoperations uoperation)))))))))) + roperations + uoperations) + (let [color (get colors (get shape attr-ref-id)) + roperation {:type :set + :attr attr + :val (:value color) + :ignore-touched true} + uoperation {:type :set + :attr attr + :val (get shape attr) + :ignore-touched true}] + (recur (next attrs) + (conj roperations roperation) + (conj uoperations uoperation))))))))))) (defmethod generate-sync-shape :typographies - [_ library-id library-items _ page-id component-id shape] + [_ library-id state _ page-id component-id shape] ;; Synchronize a shape that uses some typographies of the library. The attributes ;; of the typography are copied to the shape." - (let [update-node (fn [node] - (if-let [typography (get library-items (:typography-ref-id node))] + (let [typographies (get-assets library-id :typographies state) + update-node (fn [node] + (if-let [typography (get typographies (:typography-ref-id node))] (merge node (d/without-keys typography [:name :id])) node))] (generate-sync-text-shape shape page-id component-id update-node))) @@ -292,65 +301,108 @@ ;; ---- Component synchronization helpers ---- +(defn- get-assets + [library-id asset-type state] + (if (nil? library-id) + (get-in state [:workspace-data asset-type]) + (get-in state [:workspace-libraries library-id :data asset-type]))) + +(defn- get-component + [state file-id component-id] + (let [components (if (nil? file-id) + (get-in state [:workspace-data :components]) + (get-in state [:workspace-libraries file-id :data :components]))] + (get components component-id))) + +(defn resolve-shapes-and-components + "Get all shapes inside a component instance, and the component they are + linked with. If follow-indirection? is true, and the shape corresponding + to the root shape is also a component instance, follow the link and get + the final component." + [shape objects state follow-indirection?] + (loop [all-shapes (cph/get-object-with-children (:id shape) objects) + local-objects objects + local-shape shape] + + (let [root-shape (cph/get-root-shape local-shape local-objects) + component (get-component state + (get root-shape :component-file) + (get root-shape :component-id)) + component-shape (get-in component [:objects (:shape-ref local-shape)])] + + (if (or (nil? (:component-id component-shape)) + (not follow-indirection?)) + [all-shapes component component-shape] + (let [resolve-indirection + (fn [shape] + (let [component-shape (get-in component [:objects (:shape-ref shape)])] + (-> shape + (assoc :shape-ref (:shape-ref component-shape)) + (d/assoc-when :component-id (:component-id component-shape)) + (d/assoc-when :component-file (:component-file component-shape))))) + new-shapes (map resolve-indirection all-shapes)] + (recur new-shapes + (:objects component) + component-shape)))))) + (defn generate-sync-shape-and-children-components - "Generate changes to synchronize one shape that is linked to a component, - and all its children. If reset-touched? is false, same considerations as - in generate-sync-shape :components. If it's true, all attributes of the - component that have changed will be copied, and the 'touched' flags in - the shapes will be cleared." - [root-shape objects components page-id component-id reset-touched?] - (let [all-shapes (cph/get-object-with-children (:id root-shape) objects) - component (get components (:component-id root-shape)) - root-component (get-in component [:objects (:shape-ref root-shape)])] - (loop [shapes (seq all-shapes) - rchanges [] - uchanges []] - (let [shape (first shapes)] - (if (nil? shape) - [rchanges uchanges] - (let [[shape-rchanges shape-uchanges] - (generate-sync-shape<-component - shape - root-shape - root-component - component - page-id - component-id - reset-touched?)] - (recur (next shapes) - (d/concat rchanges shape-rchanges) - (d/concat uchanges shape-uchanges)))))))) + "Generate changes to synchronize one shape that the root of a component + instance, and all its children, from the given component. + If reset? is false, all atributes of each component shape that have + changed, and whose group has not been touched in the instance shape will + be copied to this one. + If reset? is true, all changed attributes will be copied and the 'touched' + flags in the instance shape will be cleared." + [root-shape all-shapes component root-component page-id component-id reset?] + (loop [shapes (seq all-shapes) + rchanges [] + uchanges []] + (let [shape (first shapes)] + (if (nil? shape) + [rchanges uchanges] + (let [[shape-rchanges shape-uchanges] + (generate-sync-shape<-component + shape + root-shape + root-component + component + page-id + component-id + reset?)] + (recur (next shapes) + (d/concat rchanges shape-rchanges) + (d/concat uchanges shape-uchanges))))))) -(defn generate-sync-shape-inverse +(defn- generate-sync-shape-inverse "Generate changes to update the component a shape is linked to, from - the values in the shape and all its children. It acts like the above - function with reset-touched? as true. Also clears the 'touched' flags - in the source shapes." - [root-shape objects components page-id] - (let [all-shapes (cph/get-object-with-children (:id root-shape) objects) - component (get components (:component-id root-shape)) - root-component (get-in component [:objects (:shape-ref root-shape)])] - (loop [shapes (seq all-shapes) - rchanges [] - uchanges []] - (let [shape (first shapes)] - (if (nil? shape) - [rchanges uchanges] - (let [[shape-rchanges shape-uchanges] - (generate-sync-shape->component - shape - root-shape - root-component - component - page-id)] - (recur (next shapes) - (d/concat rchanges shape-rchanges) - (d/concat uchanges shape-uchanges)))))))) + the values in the shape and all its children. + All atributes of each instance shape that have changed, will be copied + to the component shape. Also clears the 'touched' flags in the source + shapes. + And if the component shapes are, in turn, instances of a second component, + their 'touched' flags will be set accordingly." + [root-shape all-shapes component root-component page-id] + (loop [shapes (seq all-shapes) + rchanges [] + uchanges []] + (let [shape (first shapes)] + (if (nil? shape) + [rchanges uchanges] + (let [[shape-rchanges shape-uchanges] + (generate-sync-shape->component + shape + root-shape + root-component + component + page-id)] + (recur (next shapes) + (d/concat rchanges shape-rchanges) + (d/concat uchanges shape-uchanges))))))) -(defn generate-sync-shape<-component +(defn- generate-sync-shape<-component "Generate changes to synchronize one shape that is linked to other shape inside a component. Same considerations as above about reset-touched?" - [shape root-shape root-component component page-id component-id reset-touched?] + [shape root-shape root-component component page-id component-id reset?] (if (nil? component) (remove-component-and-ref shape page-id component-id) (let [component-shape (get (:objects component) (:shape-ref shape))] @@ -362,25 +414,32 @@ root-component page-id component-id - reset-touched?))))) + {:omit-touched? (not reset?) + :reset-touched? reset? + :set-touched? false}))))) -(defn generate-sync-shape->component +(defn- generate-sync-shape->component "Generate changes to synchronize one shape inside a component, with other shape that is linked to it." [shape root-shape root-component component page-id] + (js/console.log "component" (clj->js component)) (if (nil? component) empty-changes (let [component-shape (get (:objects component) (:shape-ref shape))] + (js/console.log "component-shape" (clj->js component-shape)) (if (nil? component-shape) empty-changes - (let [[rchanges1 uchanges1] + (let [_(js/console.info "update" (:name shape) "->" (:name component-shape)) + [rchanges1 uchanges1] (update-attrs component-shape shape root-component root-shape nil (:id root-component) - true) + {:omit-touched? false + :reset-touched? false + :set-touched? true}) [rchanges2 uchanges2] (reset-touched shape page-id @@ -391,13 +450,16 @@ ; ---- Operation generation helpers ---- -(defn remove-component-and-ref +(defn- remove-component-and-ref [shape page-id component-id] [[(d/without-nils {:type :mod-obj :id (:id shape) :page-id page-id :component-id component-id :operations [{:type :set + :attr :component-root? + :val nil} + {:type :set :attr :component-id :val nil} {:type :set @@ -413,6 +475,9 @@ :page-id page-id :component-id component-id :operations [{:type :set + :attr :component-root? + :val (:component-root? shape)} + {:type :set :attr :component-id :val (:component-id shape)} {:type :set @@ -424,7 +489,7 @@ {:type :set-touched :touched (:touched shape)}]})]]) -(defn remove-ref +(defn- -remove-ref [shape page-id component-id] [[(d/without-nils {:type :mod-obj :id (:id shape) @@ -445,7 +510,7 @@ {:type :set-touched :touched (:touched shape)}]})]]) -(defn reset-touched +(defn- reset-touched [shape page-id component-id] [[(d/without-nils {:type :mod-obj :id (:id shape) @@ -460,32 +525,42 @@ :operations [{:type :set-touched :touched (:touched shape)}]})]]) -(defn update-attrs - "The main function that implements the sync algorithm." - [shape component-shape root-shape root-component page-id component-id reset-touched?] +(defn- update-attrs + "The main function that implements the sync algorithm. Copy + attributes that have changed in the origin shape to the dest shape. + If omit-touched? is true, attributes whose group has been touched + in the destination shape will be ignored. + If reset-touched? is true, the 'touched' flags will be cleared in + the dest shape. + If set-touched? is true, the corresponding 'touched' flags will be + set in dest shape if they are different than their current values." + [dest-shape origin-shape dest-root origin-root page-id component-id + {:keys [omit-touched? reset-touched? set-touched?] :as options}] ;; === Uncomment this to debug synchronization === ;; (println "SYNC" - ;; "[C]" (:name component-shape) + ;; "[C]" (:name origin-shape) ;; "->" ;; (if page-id "[W]" ["C"]) - ;; (:name shape)) + ;; (:name dest-shape) + ;; (str options)) (let [; The position attributes need a special sync algorith, because we do ; not synchronize the absolute position, but the position relative of ; the container shape of the component. - new-pos (calc-new-pos shape component-shape root-shape root-component) - pos-group (get cp/component-sync-attrs :x) - touched (get shape :touched #{})] + new-pos (calc-new-pos dest-shape origin-shape dest-root origin-root) + touched (get dest-shape :touched #{})] (loop [attrs (seq (keys (dissoc cp/component-sync-attrs :x :y))) - roperations (if (or (not (touched pos-group)) reset-touched? true) - [{:type :set :attr :x :val (:x new-pos)} ; ^ TODO: the position-group is being set - {:type :set :attr :y :val (:y new-pos)}] ; | as touched somewhere. Investigate why. + roperations (if (or (not= (:x new-pos) (:x dest-shape)) + (not= (:y new-pos) (:y dest-shape))) + [{:type :set :attr :x :val (:x new-pos)} + {:type :set :attr :y :val (:y new-pos)}] []) - uoperations (if (or (not (touched pos-group)) reset-touched? true) - [{:type :set :attr :x :val (:x shape)} - {:type :set :attr :y :val (:y shape)}] + uoperations (if (or (not= (:x new-pos) (:x dest-shape)) + (not= (:y new-pos) (:y dest-shape))) + [{:type :set :attr :x :val (:x dest-shape)} + {:type :set :attr :y :val (:y dest-shape)}] [])] (let [attr (first attrs)] @@ -499,51 +574,50 @@ uoperations (if reset-touched? (conj uoperations {:type :set-touched - :touched (:touched shape)}) + :touched (:touched dest-shape)}) uoperations) rchanges [(d/without-nils {:type :mod-obj - :id (:id shape) + :id (:id dest-shape) :page-id page-id :component-id component-id :operations roperations})] uchanges [(d/without-nils {:type :mod-obj - :id (:id shape) + :id (:id dest-shape) :page-id page-id :component-id component-id :operations uoperations})]] [rchanges uchanges]) - (if-not (contains? shape attr) + (if-not (contains? dest-shape attr) (recur (next attrs) roperations uoperations) (let [roperation {:type :set :attr attr - :val (get component-shape attr) - :ignore-touched true} + :val (get origin-shape attr) + :ignore-touched (not set-touched?)} uoperation {:type :set :attr attr - :val (get shape attr) - :ignore-touched true} + :val (get dest-shape attr) + :ignore-touched (not set-touched?)} attr-group (get cp/component-sync-attrs attr)] - (if (or (not (touched attr-group)) reset-touched?) - (recur (next attrs) - (conj roperations roperation) - (conj uoperations uoperation)) + (if (and (touched attr-group) omit-touched?) (recur (next attrs) roperations - uoperations))))))))) + uoperations) + (recur (next attrs) + (conj roperations roperation) + (conj uoperations uoperation)))))))))) -(defn calc-new-pos - [shape component-shape root-shape root-component] - (let [root-pos (gpt/point (:x root-shape) (:y root-shape)) - root-component-pos (gpt/point (:x root-component) (:y root-component)) - component-pos (gpt/point (:x component-shape) (:y component-shape)) - delta (gpt/subtract component-pos root-component-pos) - shape-pos (gpt/point (:x shape) (:y shape)) - new-pos (gpt/add root-pos delta)] +(defn- calc-new-pos + [dest-shape origin-shape dest-root origin-root] + (let [root-pos (gpt/point (:x dest-root) (:y dest-root)) + origin-root-pos (gpt/point (:x origin-root) (:y origin-root)) + origin-pos (gpt/point (:x origin-shape) (:y origin-shape)) + delta (gpt/subtract origin-pos origin-root-pos) + shape-pos (gpt/point (:x dest-shape) (:y dest-shape)) + new-pos (gpt/add root-pos delta)] new-pos)) - diff --git a/frontend/src/app/main/store.cljs b/frontend/src/app/main/store.cljs index b3afec5960..9e34aa3233 100644 --- a/frontend/src/app/main/store.cljs +++ b/frontend/src/app/main/store.cljs @@ -106,8 +106,7 @@ (show-component [shape objects] (if (nil? (:shape-ref shape)) "" - (let [root-id (cph/get-root-component (:id shape) objects) - root-shape (when root-id (get objects root-id)) + (let [root-shape (cph/get-root-shape shape objects) component-id (when root-shape (:component-id root-shape)) component-file-id (when root-shape (:component-file root-shape)) component-file (when component-file-id (get libraries component-file-id)) @@ -118,7 +117,9 @@ component-shape (when (and component (:shape-ref shape)) (get-in component [:objects (:shape-ref shape)]))] (str/format " %s--> %s%s%s" - (if (:component-root? shape) "#" "-") + (cond (:component-root? shape) "#" + (:component-id shape) "@" + :else "-") (when component-file (str/format "<%s> " (:name component-file))) (:name component-shape) (if (or (:component-root? shape) diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index a7fea323be..cc109cc50d 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -20,6 +20,7 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.main.data.workspace :as dw] + [app.main.data.workspace.common :as dwc] [app.main.data.workspace.libraries :as dwl] [app.main.ui.hooks :refer [use-rxsub]] [app.main.ui.components.dropdown :refer [dropdown]])) @@ -65,8 +66,10 @@ do-detach-component #(st/emit! (dwl/detach-component id)) do-reset-component #(st/emit! (dwl/reset-component id)) do-update-component #(do + (st/emit! dwc/start-undo-transaction) (st/emit! (dwl/update-component id)) - (st/emit! (dwl/sync-file nil))) + (st/emit! (dwl/sync-file nil)) + (st/emit! dwc/commit-undo-transaction)) do-navigate-component-file #(st/emit! (dwl/nav-to-component-file (:component-file shape)))] [:* diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs index 42b89610c2..889d04dcde 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs @@ -89,7 +89,8 @@ :default-value (:name shape "")}] [:span.element-name {:on-double-click on-click} - (:name shape "")]))) + (:name shape "") + (when (seq (:touched shape)) " *")]))) (defn- make-collapsed-iref [id] @@ -305,6 +306,7 @@ :component-id :component-file :shape-ref + :touched :metadata])] (persistent! (reduce-kv (fn [res id obj] From a6d47cca10b654942825a20a139701a09f7f66ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Thu, 15 Oct 2020 11:15:35 +0200 Subject: [PATCH 4/4] :sparkles: Make some small fixes --- common/app/common/pages_helpers.cljc | 2 +- .../app/main/data/workspace/libraries.cljs | 42 ++++++++++++------- .../data/workspace/libraries_helpers.cljs | 9 ++-- frontend/src/app/main/store.cljs | 3 +- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/common/app/common/pages_helpers.cljc b/common/app/common/pages_helpers.cljc index 5edbfd70c9..1432923bde 100644 --- a/common/app/common/pages_helpers.cljc +++ b/common/app/common/pages_helpers.cljc @@ -58,7 +58,7 @@ (defn get-object-with-children "Retrieve a list with an object and all of its children" [id objects] - (map #(get objects %) (d/concat [id] (get-children id objects)))) + (map #(get objects %) (cons id (get-children id objects)))) (defn is-shape-grouped "Checks if a shape is inside a group" diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 15a0e254dd..00226a92ef 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -364,7 +364,8 @@ (ptk/reify ::reset-component ptk/WatchEvent (watch [_ state stream] - (js/console.info "##### RESET-COMPONENT of shape" (str id)) + ;; ===== Uncomment this to debug ===== + ;; (js/console.info "##### RESET-COMPONENT of shape" (str id)) (let [page-id (:current-page-id state) page (get-in state [:workspace-data :pages-index page-id]) objects (dwc/lookup-page-objects state page-id) @@ -377,10 +378,11 @@ state true) - _ (js/console.info "shape" (:name shape) "<- component" (:name component)) - _ (js/console.debug "all-shapes" (clj->js all-shapes)) - _ (js/console.debug "component" (clj->js component)) - _ (js/console.debug "root-component" (clj->js root-component)) + ;; ===== Uncomment this to debug ===== + ;; _ (js/console.info "shape" (:name shape) "<- component" (:name component)) + ;; _ (js/console.debug "all-shapes" (clj->js all-shapes)) + ;; _ (js/console.debug "component" (clj->js component)) + ;; _ (js/console.debug "root-component" (clj->js root-component)) [rchanges uchanges] (dwlh/generate-sync-shape-and-children-components shape @@ -391,7 +393,8 @@ nil true)] - (js/console.debug "rchanges" (clj->js rchanges)) + ;; ===== Uncomment this to debug ===== + ;; (js/console.debug "rchanges" (clj->js rchanges)) (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))) @@ -401,7 +404,8 @@ (ptk/reify ::update-component ptk/WatchEvent (watch [_ state stream] - (js/console.info "##### UPDATE-COMPONENT of shape" (str id)) + ;; ===== Uncomment this to debug ===== + ;; (js/console.info "##### UPDATE-COMPONENT of shape" (str id)) (let [page-id (:current-page-id state) objects (dwc/lookup-page-objects state page-id) shape (get objects id) @@ -413,10 +417,11 @@ state true) - _ (js/console.info "shape" (:name shape) "-> component" (:name component)) - _ (js/console.debug "all-shapes" (clj->js all-shapes)) - _ (js/console.debug "component" (clj->js component)) - _ (js/console.debug "root-component" (clj->js root-component)) + ;; ===== Uncomment this to debug ===== + ;; _ (js/console.info "shape" (:name shape) "-> component" (:name component)) + ;; _ (js/console.debug "all-shapes" (clj->js all-shapes)) + ;; _ (js/console.debug "component" (clj->js component)) + ;; _ (js/console.debug "root-component" (clj->js root-component)) [rchanges uchanges] (dwlh/generate-sync-shape-inverse shape @@ -425,7 +430,8 @@ root-component page-id)] - (js/console.debug "rchanges" (clj->js rchanges)) + ;; ===== Uncomment this to debug ===== + ;; (js/console.debug "rchanges" (clj->js rchanges)) (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))) @@ -443,7 +449,8 @@ ptk/WatchEvent (watch [_ state stream] - (js/console.info "##### SYNC-FILE" (str (or file-id "local"))) + ;; ===== Uncomment this to debug ===== + ;; (js/console.info "##### SYNC-FILE" (str (or file-id "local"))) (let [[rchanges1 uchanges1] (dwlh/generate-sync-file :components file-id state) [rchanges2 uchanges2] (dwlh/generate-sync-library :components file-id state) [rchanges3 uchanges3] (dwlh/generate-sync-file :colors file-id state) @@ -452,7 +459,8 @@ [rchanges6 uchanges6] (dwlh/generate-sync-library :typographies file-id state) rchanges (d/concat rchanges1 rchanges2 rchanges3 rchanges4 rchanges5 rchanges6) uchanges (d/concat uchanges1 uchanges2 uchanges3 uchanges4 uchanges5 uchanges6)] - (js/console.debug "rchanges" (clj->js rchanges)) + ;; ===== Uncomment this to debug ===== + ;; (js/console.debug "rchanges" (clj->js rchanges)) (rx/concat (rx/of (dm/hide-tag :sync-dialog)) (when rchanges @@ -478,13 +486,15 @@ (ptk/reify ::sync-file-2nd-stage ptk/WatchEvent (watch [_ state stream] - (js/console.info "##### SYNC-FILE" (str (or file-id "local")) "(2nd stage)") + ;; ===== Uncomment this to debug ===== + ;; (js/console.info "##### SYNC-FILE" (str (or file-id "local")) "(2nd stage)") (let [[rchanges1 uchanges1] (dwlh/generate-sync-file :components nil state) [rchanges2 uchanges2] (dwlh/generate-sync-library :components file-id state) rchanges (d/concat rchanges1 rchanges2) uchanges (d/concat uchanges1 uchanges2)] (when rchanges - (js/console.debug "rchanges" (clj->js rchanges)) + ;; ===== Uncomment this to debug ===== + ;; (js/console.debug "rchanges" (clj->js rchanges)) (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}))))))) (def ignore-sync diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index e9a89be2bf..8585f0d101 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -422,14 +422,17 @@ "Generate changes to synchronize one shape inside a component, with other shape that is linked to it." [shape root-shape root-component component page-id] - (js/console.log "component" (clj->js component)) + ;; ===== Uncomment this to debug ===== + ;; (js/console.log "component" (clj->js component)) (if (nil? component) empty-changes (let [component-shape (get (:objects component) (:shape-ref shape))] - (js/console.log "component-shape" (clj->js component-shape)) + ;; ===== Uncomment this to debug ===== + ;; (js/console.log "component-shape" (clj->js component-shape)) (if (nil? component-shape) empty-changes - (let [_(js/console.info "update" (:name shape) "->" (:name component-shape)) + (let [;; ===== Uncomment this to debug ===== + ;; _(js/console.info "update" (:name shape) "->" (:name component-shape)) [rchanges1 uchanges1] (update-attrs component-shape shape diff --git a/frontend/src/app/main/store.cljs b/frontend/src/app/main/store.cljs index 9e34aa3233..be3fc28d59 100644 --- a/frontend/src/app/main/store.cljs +++ b/frontend/src/app/main/store.cljs @@ -90,8 +90,7 @@ (let [shape (get objects shape-id)] (println (str/pad (str (str/repeat " " level) (:name shape) - (when (seq (filter #(not= :position-group %) - (:touched shape))) "*")) + (when (seq (:touched shape)) "*") {:length 20 :type :right}) (show-component shape objects))