diff --git a/common/src/app/common/logic/libraries.cljc b/common/src/app/common/logic/libraries.cljc index 9d2ddde99b..815021ae3b 100644 --- a/common/src/app/common/logic/libraries.cljc +++ b/common/src/app/common/logic/libraries.cljc @@ -241,7 +241,7 @@ When walking up through nested component copies, each intermediate component may live in a different library/file. We resolve the right file-data for each - component via `ctf/find-component-file` so we can locate components that span + component via `ctf/head-component` so we can locate components that span multiple libraries." [container-inst shape-inst shape-main library file libraries component] (loop [shape-inst' shape-inst @@ -251,17 +251,11 @@ (if (some? (ctn/get-shape container (:id shape-main))) container (let [parent (ctn/get-shape container-inst (:parent-id shape-inst')) - shape-inst' (ctn/get-head-shape (:objects container-inst) parent) - next-file (some-> shape-inst' - :component-file - (->> (ctf/find-component-file file libraries))) - next-data (some-> next-file :data) - component' (when next-data - (or (ctkl/get-component next-data (:component-id shape-inst')) - (ctkl/get-deleted-component next-data (:component-id shape-inst'))))] - (if (some? component') - (recur shape-inst' next-data component') - nil)))))) + shape-inst' (ctn/get-head-shape (:objects container-inst) parent)] + (when-let [[next-data component'] (when (some? shape-inst') + (ctf/head-component file libraries shape-inst' + :include-deleted? true))] + (recur shape-inst' next-data component'))))))) (defn- generate-sync-shape-direct "Generate changes to synchronize one shape that is the root of a component diff --git a/common/src/app/common/logic/variants.cljc b/common/src/app/common/logic/variants.cljc index 60955772ad..1a60f4e7d5 100644 --- a/common/src/app/common/logic/variants.cljc +++ b/common/src/app/common/logic/variants.cljc @@ -374,49 +374,31 @@ ;; Creates a map to quickly find a child of the orig-ref-shape by its shape-path o-ref-shapes-p-map (into {} (map (juxt :id :shape-path)) o-ref-shapes-wp) - ;; Process each touched children of the original-shape - [changes parents-of-swapped] - (reduce - (fn [[changes parent-of-swapped] orig-child-touched] - (let [;; The switched shape itself relates to the root of the new one - root? (= (:id orig-child-touched) (:id original-shape)) + ;; Each touched child of the original-shape, with the shape it refers + ;; to in the main and the child of the new-shape that has the same + ;; shape-path; the switched shape itself relates to the new root + pairs + (keep (fn [old] + (let [root? (= (:id old) (:id original-shape)) + old-ref (if root? + orig-base-ref-shape + (find-shape-ref-child-of container libraries old (:id orig-base-ref-shape))) + new (get new-shapes-map (get o-ref-shapes-p-map (:id old-ref)))] + (when new + {:old old :old-ref old-ref :new new + :swapped? (and (not root?) (ctk/swapped? old))}))) + orig-touched) - swapped? (and (not root?) (ctk/swapped? orig-child-touched)) - - ;; orig-child-touched is in a copy. Get the referenced shape on the main component - orig-ref-shape (if root? - orig-base-ref-shape - (find-shape-ref-child-of container libraries orig-child-touched (:id orig-base-ref-shape))) - - orig-ref-id (:id orig-ref-shape) - - ;; Get the shape path of the referenced main - shape-path (get o-ref-shapes-p-map orig-ref-id) - - ;; Get its related shape in the children of new-shape: the one that - ;; has the same shape-path - related-shape-in-new (get new-shapes-map shape-path) - - parents-of-swapped (if related-shape-in-new - (conj parent-of-swapped (:parent-id related-shape-in-new)) - parent-of-swapped) - ;; If there is a related shape, keep its data - changes - (if related-shape-in-new - (if swapped? - ;; If the orig-child-touched was swapped, keep it - (keep-swapped-item changes related-shape-in-new orig-child-touched - ldata page libraries) - ;; If the orig-child-touched wasn't swapped, copy - ;; the touched attributes into it - (clsw/update-attrs-on-switch - changes related-shape-in-new orig-child-touched - new-shape original-shape orig-ref-shape container)) - changes)] - [changes parents-of-swapped])) - [changes []] - orig-touched)] - [changes parents-of-swapped])) + ;; A swapped child is kept as it is, and the others carry their + ;; touched attributes into their new child + changes + (reduce (fn [changes {:keys [old old-ref new swapped?]}] + (if swapped? + (keep-swapped-item changes new old ldata page libraries) + (clsw/update-attrs-on-switch changes new old new-shape original-shape old-ref container))) + changes + pairs)] + [changes (mapv (comp :parent-id :new) pairs)])) (defn- shape-index "Position of `shape-id` among the children of `parent-id`; 0 when it is not diff --git a/common/src/app/common/types/file.cljc b/common/src/app/common/types/file.cljc index 3f6dbb5c3b..ae5eaa0332 100644 --- a/common/src/app/common/types/file.cljc +++ b/common/src/app/common/types/file.cljc @@ -326,6 +326,17 @@ file (get libraries component-file))) +(defn head-component + "The file data and the component of the head `head`, found in the local + `file` or in `libraries`, as `[file-data component]`; nil when they are + not there." + [file libraries head & {:keys [include-deleted?]}] + (let [file-data (:data (find-component-file file libraries (:component-file head))) + component (when (some? file-data) + (ctkl/get-component file-data (:component-id head) include-deleted?))] + (when (some? component) + [file-data component]))) + (defn get-component "Retrieve a component from a library." [libraries library-id component-id & {:keys [include-deleted?] :or {include-deleted? false}}] @@ -373,7 +384,7 @@ (ctn/get-shape (:main-instance-id component))) (ctk/get-deleted-component-root component))) -(defn get-component-shape +(defn get-component-child "Retrieve one shape in the component by id. If with-context? is true, add the file and container where the shape resides in its metadata." [file-data component shape-id & {:keys [with-context?] :or {with-context? false}}] @@ -400,7 +411,7 @@ "Retrieve the shape in the component that is referenced by the instance shape." [file-data component shape & {:keys [with-context?] :or {with-context? false}}] (when (:shape-ref shape) - (get-component-shape file-data component (:shape-ref shape) :with-context? with-context?))) + (get-component-child file-data component (:shape-ref shape) :with-context? with-context?))) (defn get-content-ref-shape "Retrieve the shape in the component whose content the instance shape @@ -421,31 +432,25 @@ "Locate the nearest component in the local file or libraries, and retrieve the shape referenced by the instance shape." [file container libraries shape & {:keys [include-deleted? with-context?] :or {include-deleted? false with-context? false}}] - (let [find-ref-shape-in-head - (fn [head-shape] - (let [component-file (find-component-file file libraries (:component-file head-shape)) - component (when (some? component-file) - (ctkl/get-component (:data component-file) (:component-id head-shape) include-deleted?))] - (when (some? component) - (get-ref-shape (:data component-file) component shape :with-context? with-context?))))] - (some find-ref-shape-in-head (ctn/get-parent-heads (:objects container) shape)))) + (some (fn [head] + (when-let [[file-data component] (head-component file libraries head + :include-deleted? include-deleted?)] + (get-ref-shape file-data component shape :with-context? with-context?))) + (ctn/get-parent-heads (:objects container) shape))) (defn find-content-ref-shape "Retrieve the shape whose content the instance shape follows: the main root of its own component for a swapped head, the referenced shape otherwise." [file container libraries shape & {:keys [include-deleted? with-context?] :or {include-deleted? false with-context? false}}] (if (ctk/swapped? shape) - (let [component-file (find-component-file file libraries (:component-file shape)) - file-data (:data component-file) - component (when (some? component-file) - (ctkl/get-component file-data (:component-id shape) include-deleted?)) - root (when (some? component) - (get-component-root file-data component))] - (cond-> root - (and (some? root) with-context?) - (with-meta {:file {:id (:id file-data) - :data file-data} - :container (get-component-container file-data component)}))) + (when-let [[file-data component] (head-component file libraries shape + :include-deleted? include-deleted?)] + (let [root (get-component-root file-data component)] + (cond-> root + (and (some? root) with-context?) + (with-meta {:file {:id (:id file-data) + :data file-data} + :container (get-component-container file-data component)})))) (find-ref-shape file container libraries shape :include-deleted? include-deleted? :with-context? with-context?))) @@ -523,18 +528,12 @@ "Locate the nearest component in the local file or libraries that is referenced by the instance shape." [file page libraries shape & {:keys [include-deleted?] :or {include-deleted? false}}] - (let [find-ref-component-in-head - (fn [head-shape] - (let [component-file (find-component-file file libraries (:component-file head-shape)) - component (when (some? component-file) - (ctkl/get-component (:data component-file) - (:component-id head-shape) - include-deleted?))] - (when (some? component) - (when (get-ref-shape (:data component-file) component shape) - component))))] - - (some find-ref-component-in-head (ctn/get-parent-copy-heads (:objects page) shape)))) + (some (fn [head] + (when-let [[file-data component] (head-component file libraries head + :include-deleted? include-deleted?)] + (when (get-ref-shape file-data component shape) + component))) + (ctn/get-parent-copy-heads (:objects page) shape))) (declare find-remote-shape*) diff --git a/common/test/common_tests/types/file_test.cljc b/common/test/common_tests/types/file_test.cljc index 6a6539006e..f6bb368d8c 100644 --- a/common/test/common_tests/types/file_test.cljc +++ b/common/test/common_tests/types/file_test.cljc @@ -249,7 +249,7 @@ (t/is (= #{(thi/id :main) (thi/id :main-child)} (set (map :id (ctf/get-component-shapes data component))))) (t/testing "a shape of the component, with the component as its container" - (let [child (ctf/get-component-shape data component (thi/id :main-child) + (let [child (ctf/get-component-child data component (thi/id :main-child) :with-context? true)] (t/is (= (thi/id :main-child) (:id child))) (t/is (= :component (:type (:container (meta child)))))))