mirror of
https://github.com/penpot/penpot.git
synced 2025-03-18 10:41:29 -05:00
🎉 Add many improvements on nil handling and code structure on changes impl.
This commit is contained in:
parent
d61a86cad1
commit
394e6b08ad
2 changed files with 100 additions and 91 deletions
|
@ -15,6 +15,20 @@
|
|||
[app.common.pages.spec :as spec]
|
||||
[app.common.spec :as us]))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Specific helpers
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn- without-obj
|
||||
"Clear collection from specified obj and without nil values."
|
||||
[coll o]
|
||||
(into [] (filter #(not= % o)) coll))
|
||||
|
||||
(defn vec-without-nils
|
||||
[coll]
|
||||
(into [] (remove nil?) coll))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Page Transformation Changes
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -54,45 +68,50 @@
|
|||
(assoc data :options (d/dissoc-in (:options data) path)))))))
|
||||
|
||||
(defmethod process-change :add-obj
|
||||
[data {:keys [id obj page-id component-id frame-id parent-id
|
||||
index ignore-touched]}]
|
||||
(letfn [(update-fn [data]
|
||||
(let [parent-id (or parent-id frame-id)
|
||||
objects (:objects data)
|
||||
obj (assoc obj
|
||||
:frame-id frame-id
|
||||
:parent-id parent-id
|
||||
:id id)]
|
||||
(if (and (or (nil? parent-id) (contains? objects parent-id))
|
||||
(or (nil? frame-id) (contains? objects frame-id)))
|
||||
(-> data
|
||||
(update :objects assoc id obj)
|
||||
(update-in [:objects parent-id :shapes]
|
||||
(fn [shapes]
|
||||
(let [shapes (or shapes [])]
|
||||
(cond
|
||||
(some #{id} shapes)
|
||||
shapes
|
||||
[data {:keys [id obj page-id component-id frame-id parent-id index ignore-touched]}]
|
||||
(letfn [(update-parent-shapes [shapes]
|
||||
;; Ensure that shapes is always a vector.
|
||||
(let [shapes (into [] shapes)]
|
||||
(cond
|
||||
(some #{id} shapes)
|
||||
shapes
|
||||
|
||||
(nil? index)
|
||||
(if (= :frame (:type obj))
|
||||
(d/concat [id] shapes)
|
||||
(conj shapes id))
|
||||
(nil? index)
|
||||
(if (= :frame (:type obj))
|
||||
(into [id] shapes)
|
||||
(conj shapes id))
|
||||
|
||||
:else
|
||||
(cph/insert-at-index shapes index [id])))))
|
||||
:else
|
||||
(cph/insert-at-index shapes index [id]))))
|
||||
|
||||
(update-parent [parent]
|
||||
(-> parent
|
||||
(update :shapes update-parent-shapes)
|
||||
(update :shapes 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?)))))
|
||||
|
||||
(update-objects [objects parent-id]
|
||||
(if (and (or (nil? parent-id) (contains? objects parent-id))
|
||||
(or (nil? frame-id) (contains? objects frame-id)))
|
||||
(-> objects
|
||||
(assoc id (-> obj
|
||||
(assoc :frame-id frame-id)
|
||||
(assoc :parent-id parent-id)
|
||||
(assoc :id id)))
|
||||
(update parent-id update-parent))
|
||||
objects))
|
||||
|
||||
(update-container [data]
|
||||
(let [parent-id (or parent-id frame-id)]
|
||||
(update data :objects update-objects parent-id)))]
|
||||
|
||||
(cond-> (and (:shape-ref (get-in data [:objects parent-id]))
|
||||
(not= parent-id frame-id)
|
||||
(not ignore-touched))
|
||||
(->
|
||||
(update-in [:objects parent-id :touched]
|
||||
cph/set-touched-group :shapes-group)
|
||||
(d/dissoc-in [:objects parent-id :remote-synced?]))))
|
||||
data)))]
|
||||
(if page-id
|
||||
(d/update-in-when data [:pages-index page-id] update-fn)
|
||||
(d/update-in-when data [:components component-id] update-fn))))
|
||||
(d/update-in-when data [:pages-index page-id] update-container)
|
||||
(d/update-in-when data [:components component-id] update-container))))
|
||||
|
||||
(defmethod process-change :mod-obj
|
||||
[data {:keys [id page-id component-id operations]}]
|
||||
|
@ -107,32 +126,27 @@
|
|||
|
||||
(defmethod process-change :del-obj
|
||||
[data {:keys [page-id component-id id ignore-touched]}]
|
||||
(letfn [(delete-object [objects id]
|
||||
(letfn [(delete-from-parent [parent]
|
||||
(let [parent (update parent :shapes without-obj id)]
|
||||
(cond-> parent
|
||||
(and (:shape-ref parent)
|
||||
(not ignore-touched))
|
||||
(-> (update :touched cph/set-touched-group :shapes-group)
|
||||
(dissoc :remote-synced?)))))
|
||||
|
||||
(delete-from-objects [objects]
|
||||
(if-let [target (get objects id)]
|
||||
(let [parent-id (cph/get-parent id objects)
|
||||
frame-id (:frame-id target)
|
||||
parent (get objects parent-id)
|
||||
objects (dissoc objects id)]
|
||||
(cond-> objects
|
||||
(and (not= parent-id frame-id)
|
||||
(#{:group :svg-raw} (:type parent)))
|
||||
(update-in [parent-id :shapes] (fn [s] (filterv #(not= % id) s)))
|
||||
|
||||
(and (:shape-ref parent) (not ignore-touched))
|
||||
(->
|
||||
(update-in [parent-id :touched] cph/set-touched-group :shapes-group)
|
||||
(d/dissoc-in [parent-id :remote-synced?]))
|
||||
|
||||
(contains? objects frame-id)
|
||||
(update-in [frame-id :shapes] (fn [s] (filterv #(not= % id) s)))
|
||||
|
||||
(seq (:shapes target)) ; Recursive delete all
|
||||
; dependend objects
|
||||
(as-> $ (reduce delete-object $ (:shapes target)))))
|
||||
(let [parent-id (or (:parent-id target)
|
||||
(:frame-id target))
|
||||
children (cph/get-children id objects)]
|
||||
(-> (reduce dissoc objects children)
|
||||
(dissoc id)
|
||||
(d/update-when parent-id delete-from-parent)))
|
||||
objects))]
|
||||
|
||||
(if page-id
|
||||
(d/update-in-when data [:pages-index page-id :objects] delete-object id)
|
||||
(d/update-in-when data [:components component-id :objects] delete-object id))))
|
||||
(d/update-in-when data [:pages-index page-id :objects] delete-from-objects)
|
||||
(d/update-in-when data [:components component-id :objects] delete-from-objects))))
|
||||
|
||||
;; reg-objects operation "regenerates" the geometry and selrect of the parent groups
|
||||
(defmethod process-change :reg-objects
|
||||
|
@ -191,25 +205,24 @@
|
|||
(insert-items prev-shapes index shapes)
|
||||
;; For masked groups, the first shape is the mask
|
||||
;; and it cannot be moved.
|
||||
(let [mask-id (first prev-shapes)
|
||||
other-ids (rest prev-shapes)
|
||||
not-mask-shapes (strip-id shapes mask-id)
|
||||
new-index (if (nil? index) nil (max (dec index) 0))
|
||||
new-shapes (insert-items other-ids new-index not-mask-shapes)]
|
||||
(let [mask-id (first prev-shapes)
|
||||
other-ids (rest prev-shapes)
|
||||
not-mask-shapes (without-obj shapes mask-id)
|
||||
new-index (if (nil? index) nil (max (dec index) 0))
|
||||
new-shapes (insert-items other-ids new-index not-mask-shapes)]
|
||||
(d/concat [mask-id] new-shapes))))
|
||||
|
||||
(strip-id [coll id]
|
||||
(filterv #(not= % id) coll))
|
||||
|
||||
(add-to-parent [parent index shapes]
|
||||
(cond-> parent
|
||||
true
|
||||
(update :shapes check-insert-items parent index shapes)
|
||||
|
||||
(and (:shape-ref parent) (= (:type parent) :group) (not ignore-touched))
|
||||
(->
|
||||
(update :touched cph/set-touched-group :shapes-group)
|
||||
(dissoc :remote-synced?))))
|
||||
(let [parent (-> parent
|
||||
(update :shapes check-insert-items parent index shapes)
|
||||
;; We need to ensure that no `nil` in the
|
||||
;; shapes list after adding all the
|
||||
;; incoming shapes to the parent.
|
||||
(update :shapes vec-without-nils))]
|
||||
(cond-> parent
|
||||
(and (:shape-ref parent) (= (:type parent) :group) (not ignore-touched))
|
||||
(-> (update :touched cph/set-touched-group :shapes-group)
|
||||
(dissoc :remote-synced?)))))
|
||||
|
||||
(remove-from-old-parent [cpindex objects shape-id]
|
||||
(let [prev-parent-id (get cpindex shape-id)]
|
||||
|
@ -217,22 +230,19 @@
|
|||
;; the new destination target parent id.
|
||||
(if (= prev-parent-id parent-id)
|
||||
objects
|
||||
(let [sid shape-id
|
||||
pid prev-parent-id
|
||||
obj (get objects pid)
|
||||
(let [sid shape-id
|
||||
pid prev-parent-id
|
||||
obj (get objects pid)
|
||||
component? (and (:shape-ref obj)
|
||||
(= (:type obj) :group)
|
||||
(not ignore-touched))]
|
||||
|
||||
(-> objects
|
||||
(d/update-in-when [pid :shapes] strip-id sid)
|
||||
|
||||
(cond-> component?
|
||||
(d/update-when
|
||||
pid
|
||||
#(-> %
|
||||
(update :touched cph/set-touched-group :shapes-group)
|
||||
(dissoc :remote-synced?)))))))))
|
||||
(d/update-in-when [pid :shapes] without-obj sid)
|
||||
(d/update-in-when [pid :shapes] vec-without-nils)
|
||||
(cond-> component? (d/update-when pid #(-> %
|
||||
(update :touched cph/set-touched-group :shapes-group)
|
||||
(dissoc :remote-synced?)))))))))
|
||||
|
||||
(update-parent-id [objects id]
|
||||
(-> objects
|
||||
|
@ -240,8 +250,7 @@
|
|||
|
||||
;; Updates the frame-id references that might be outdated
|
||||
(assign-frame-id [frame-id objects id]
|
||||
(let [objects (-> objects
|
||||
(d/update-when id assoc :frame-id frame-id))
|
||||
(let [objects (d/update-when objects id assoc :frame-id frame-id)
|
||||
obj (get objects id)]
|
||||
(cond-> objects
|
||||
;; If we moving frame, the parent frame is the root
|
||||
|
|
|
@ -103,16 +103,16 @@
|
|||
children's order will be breadth first."
|
||||
[id objects]
|
||||
|
||||
(loop [result (transient [])
|
||||
(loop [result (transient [])
|
||||
pending (transient [])
|
||||
next id]
|
||||
next id]
|
||||
(let [children (get-in objects [next :shapes] [])
|
||||
[result pending]
|
||||
;; Iterate through children and add them to the result
|
||||
;; also add them in pending to check for their children
|
||||
(loop [result result
|
||||
pending pending
|
||||
current (first children)
|
||||
current (first children)
|
||||
children (rest children)]
|
||||
(if current
|
||||
(recur (conj! result current)
|
||||
|
@ -214,7 +214,7 @@
|
|||
(if (some #{id} acc)
|
||||
acc
|
||||
(conj acc id)))
|
||||
prev-ids
|
||||
(vec prev-ids)
|
||||
ids))
|
||||
|
||||
(defn select-toplevel-shapes
|
||||
|
|
Loading…
Add table
Reference in a new issue