0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-13 10:38:13 -05:00

♻️ Refactor update master component function

This commit is contained in:
Andrés Moya 2020-10-06 15:04:16 +02:00
parent a3eb634740
commit 7c75b75f5b
2 changed files with 122 additions and 88 deletions

View file

@ -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}))))))

View file

@ -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?]