diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index 9a4ec0fb0e..fac003ebef 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -1697,6 +1697,68 @@ (update :pages-index d/update-vals update-container) (d/update-when :components d/update-vals update-container)))) +;; Copy fills from position-data to text nodes when all text nodes lack fills, +;; all position-data have fills, and the counts match +(defmethod migrate-data "0016-copy-fills-from-position-data-to-text-node" + [data _] + (letfn [(get-text-nodes [content] + ;; Get all leaf text nodes from the content tree + (when content + (->> (types.text/node-seq types.text/is-text-node? content) + (seq)))) + + (update-content [content fills-map] + ;; Transform the content tree to update text nodes with their corresponding fills + ;; fills-map is a map from text node to its fills + (types.text/transform-nodes + types.text/is-text-node? + (fn [text-node] + (if-let [fills (get fills-map text-node)] + (assoc text-node :fills fills) + text-node)) + content)) + + (update-object [object] + (if (cfh/text-shape? object) + (let [content (:content object) + position-data (:position-data object) + text-nodes (get-text-nodes content)] + + ;; Check if conditions are met: + ;; 1. Has at least one text node + ;; 2. All text nodes have no fills or empty fills + ;; 3. Has at least one position-data entry + ;; 4. All position-data have fills + ;; 5. The number of text nodes matches the number of position-data + (if (and (seq text-nodes) + (seq position-data) + (= (count text-nodes) (count position-data)) + (every? (fn [text-node] + (let [fills (:fills text-node)] + (or (nil? fills) (empty? fills)))) + text-nodes) + (every? (fn [pd] + (let [fills (:fills pd)] + (and (some? fills) (seq fills)))) + position-data)) + + ;; Apply the migration: create a map from each text node to its corresponding fills + (let [fills-map (zipmap text-nodes (map :fills position-data))] + (update object :content #(update-content % fills-map))) + + ;; Don't modify if conditions aren't met + object)) + + ;; Not a text shape, return as-is + object)) + + (update-container [container] + (d/update-when container :objects d/update-vals update-object))] + + (-> data + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) + (def available-migrations (into (d/ordered-set) ["legacy-2" @@ -1769,4 +1831,5 @@ "0013-clear-invalid-strokes-and-fills" "0014-fix-tokens-lib-duplicate-ids" "0014-clear-components-nil-objects" - "0015-fix-text-attrs-blank-strings"])) + "0015-fix-text-attrs-blank-strings" + "0016-copy-fills-from-position-data-to-text-node"]))