mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
🎉 Split text and its properties on components updates
This commit is contained in:
@@ -80,6 +80,7 @@ A non exhaustive list of changes:
|
|||||||
- Deselect layers (and path nodes) with Ctrl+Shift+Drag [Github #2509](https://github.com/penpot/penpot/issues/2509)
|
- Deselect layers (and path nodes) with Ctrl+Shift+Drag [Github #2509](https://github.com/penpot/penpot/issues/2509)
|
||||||
- Copy to SVG from contextual menu [Github #838](https://github.com/penpot/penpot/issues/838)
|
- Copy to SVG from contextual menu [Github #838](https://github.com/penpot/penpot/issues/838)
|
||||||
- Add styles for Inkeep Chat at workspace [Taiga #10708](https://tree.taiga.io/project/penpot/us/10708)
|
- Add styles for Inkeep Chat at workspace [Taiga #10708](https://tree.taiga.io/project/penpot/us/10708)
|
||||||
|
- On components overrides, separate the content of the text from the rest of properties [Taiga #7434](https://tree.taiga.io/project/penpot/us/7434)
|
||||||
- Add configuration for air gapped installations with Docker
|
- Add configuration for air gapped installations with Docker
|
||||||
- Support system color scheme [Github #5030](https://github.com/penpot/penpot/issues/5030)
|
- Support system color scheme [Github #5030](https://github.com/penpot/penpot/issues/5030)
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
[app.common.types.shape :as cts]
|
[app.common.types.shape :as cts]
|
||||||
[app.common.types.shape.interactions :as ctsi]
|
[app.common.types.shape.interactions :as ctsi]
|
||||||
[app.common.types.shape.shadow :as ctss]
|
[app.common.types.shape.shadow :as ctss]
|
||||||
|
[app.common.types.text :as cttx]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
@@ -1327,6 +1328,33 @@
|
|||||||
(update :pages-index d/update-vals update-container)
|
(update :pages-index d/update-vals update-container)
|
||||||
(d/update-when :components d/update-vals update-container))))
|
(d/update-when :components d/update-vals update-container))))
|
||||||
|
|
||||||
|
|
||||||
|
(defmethod migrate-data "0004-add-partial-text-touched-flags"
|
||||||
|
[data _]
|
||||||
|
(letfn [(update-object [page object]
|
||||||
|
(if (and (cfh/text-shape? object)
|
||||||
|
(ctk/in-component-copy? object))
|
||||||
|
(let [file {:id (:id data) :data data}
|
||||||
|
libs (when (:libs data)
|
||||||
|
(deref (:libs data)))
|
||||||
|
ref-shape (ctf/find-ref-shape file page libs object
|
||||||
|
{:include-deleted? true :with-context? true})
|
||||||
|
partial-touched (when ref-shape
|
||||||
|
(cttx/get-diff-type (:content object) (:content ref-shape)))]
|
||||||
|
(if (seq partial-touched)
|
||||||
|
(update object :touched (fn [touched]
|
||||||
|
(reduce #(ctk/set-touched-group %1 %2)
|
||||||
|
touched
|
||||||
|
partial-touched)))
|
||||||
|
object))
|
||||||
|
object))
|
||||||
|
|
||||||
|
(update-page [page]
|
||||||
|
(d/update-when page :objects d/update-vals (partial update-object page)))]
|
||||||
|
|
||||||
|
(update data :pages-index d/update-vals update-page)))
|
||||||
|
|
||||||
|
|
||||||
(def available-migrations
|
(def available-migrations
|
||||||
(into (d/ordered-set)
|
(into (d/ordered-set)
|
||||||
["legacy-2"
|
["legacy-2"
|
||||||
@@ -1385,4 +1413,5 @@
|
|||||||
"0002-normalize-bool-content"
|
"0002-normalize-bool-content"
|
||||||
"0002-clean-shape-interactions"
|
"0002-clean-shape-interactions"
|
||||||
"0003-fix-root-shape"
|
"0003-fix-root-shape"
|
||||||
"0003-convert-path-content"]))
|
"0003-convert-path-content"
|
||||||
|
"0004-add-partial-text-touched-flags"]))
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
[app.common.types.shape-tree :as ctst]
|
[app.common.types.shape-tree :as ctst]
|
||||||
[app.common.types.shape.interactions :as ctsi]
|
[app.common.types.shape.interactions :as ctsi]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
|
[app.common.types.text :as cttx]
|
||||||
[app.common.types.token :as cto]
|
[app.common.types.token :as cto]
|
||||||
[app.common.types.typography :as cty]
|
[app.common.types.typography :as cty]
|
||||||
[app.common.types.variant :as ctv]
|
[app.common.types.variant :as ctv]
|
||||||
@@ -1663,24 +1664,46 @@
|
|||||||
{:type :reg-objects
|
{:type :reg-objects
|
||||||
:shapes all-parents})]))))
|
:shapes all-parents})]))))
|
||||||
|
|
||||||
|
|
||||||
(defn- add-update-attr-operations
|
(defn- add-update-attr-operations
|
||||||
[attr dest-shape origin-shape roperations uoperations touched]
|
[attr dest-shape origin-shape roperations uoperations touched is-text-partial-change?]
|
||||||
(let [;; position-data is a special case because can be affected by :geometry-group and :content-group
|
(let [orig-value (get origin-shape attr)
|
||||||
|
dest-value (get dest-shape attr)
|
||||||
|
;; position-data is a special case because can be affected by :geometry-group and :content-group
|
||||||
;; so, if the position-data changes but the geometry is touched we need to reset the position-data
|
;; so, if the position-data changes but the geometry is touched we need to reset the position-data
|
||||||
;; so it's calculated again
|
;; so it's calculated again
|
||||||
reset-pos-data?
|
reset-pos-data?
|
||||||
(and (cfh/text-shape? origin-shape)
|
(and (cfh/text-shape? origin-shape)
|
||||||
(= attr :position-data)
|
(= attr :position-data)
|
||||||
(not= (get origin-shape attr) (get dest-shape attr))
|
(not= orig-value dest-value)
|
||||||
(touched :geometry-group))
|
(touched :geometry-group))
|
||||||
|
|
||||||
|
;; We want to split the changes on the text itself and on its properties
|
||||||
|
text-value
|
||||||
|
(when is-text-partial-change?
|
||||||
|
(cond
|
||||||
|
(touched :text-content-structure-same-attrs)
|
||||||
|
;; Keep the dest structure and texts, update its attrs to make them like the origin
|
||||||
|
(cttx/copy-attrs-keys dest-value (cttx/get-first-paragraph-text-attrs orig-value))
|
||||||
|
|
||||||
|
(touched :text-content-text)
|
||||||
|
;; Keep the texts touched in dest: copy the texts from dest over the attrs of origin
|
||||||
|
(cttx/copy-text-keys dest-value orig-value)
|
||||||
|
|
||||||
|
(touched :text-content-attribute)
|
||||||
|
;; Keep the attrs touched in dest: copy the texts from origin over the attrs of dest
|
||||||
|
(cttx/copy-text-keys orig-value dest-value)))
|
||||||
|
|
||||||
|
val (cond
|
||||||
|
;; If position data changes and the geometry group is touched
|
||||||
|
;; we need to put to nil so we can regenerate it
|
||||||
|
reset-pos-data? nil
|
||||||
|
is-text-partial-change? text-value
|
||||||
|
:else orig-value)
|
||||||
|
|
||||||
roperation {:type :set
|
roperation {:type :set
|
||||||
:attr attr
|
:attr attr
|
||||||
:val (cond
|
:val val
|
||||||
;; If position data changes and the geometry group is touched
|
|
||||||
;; we need to put to nil so we can regenerate it
|
|
||||||
reset-pos-data? nil
|
|
||||||
:else (get origin-shape attr))
|
|
||||||
:ignore-touched true}
|
:ignore-touched true}
|
||||||
uoperation {:type :set
|
uoperation {:type :set
|
||||||
:attr attr
|
:attr attr
|
||||||
@@ -1689,6 +1712,33 @@
|
|||||||
[(conj roperations roperation)
|
[(conj roperations roperation)
|
||||||
(conj uoperations uoperation)]))
|
(conj uoperations uoperation)]))
|
||||||
|
|
||||||
|
(defn- is-text-partial-change?
|
||||||
|
"Check if the attr update is a text partial change"
|
||||||
|
[origin-shape dest-shape attr touched]
|
||||||
|
(let [partial-text-keys [:text-content-attribute :text-content-text]
|
||||||
|
active-keys (filter touched partial-text-keys)
|
||||||
|
orig-content (get origin-shape attr)
|
||||||
|
orig-attrs (cttx/get-first-paragraph-text-attrs orig-content)
|
||||||
|
|
||||||
|
equal-orig-attrs? (cttx/equal-attrs? orig-content orig-attrs)]
|
||||||
|
(and
|
||||||
|
(or
|
||||||
|
;; One and only one of the keys is pressent
|
||||||
|
(= 1 (count active-keys))
|
||||||
|
(and
|
||||||
|
(not (touched :text-content-attribute))
|
||||||
|
(touched :text-content-structure-same-attrs)))
|
||||||
|
|
||||||
|
(or
|
||||||
|
;; Both has the same structure
|
||||||
|
(cttx/equal-structure? (:content origin-shape) (:content dest-shape))
|
||||||
|
|
||||||
|
;; The origin and destiny have different structures, but each have the same attrs
|
||||||
|
;; for all the items on its content tree
|
||||||
|
(and
|
||||||
|
equal-orig-attrs?
|
||||||
|
(touched :text-content-structure-same-attrs))))))
|
||||||
|
|
||||||
(defn- update-attrs
|
(defn- update-attrs
|
||||||
"The main function that implements the attribute sync algorithm. Copy
|
"The main function that implements the attribute sync algorithm. Copy
|
||||||
attributes that have changed in the origin shape to the dest shape.
|
attributes that have changed in the origin shape to the dest shape.
|
||||||
@@ -1731,12 +1781,30 @@
|
|||||||
:always
|
:always
|
||||||
(generate-update-tokens container dest-shape origin-shape touched omit-touched?))
|
(generate-update-tokens container dest-shape origin-shape touched omit-touched?))
|
||||||
|
|
||||||
(let [attr-group (get ctk/sync-attrs attr)
|
(let [attr-group (get ctk/sync-attrs attr)
|
||||||
|
;; On texts, when we want to omit the touched attrs, both text (the actual letters)
|
||||||
|
;; and attrs (bold, font, etc) are in the same attr :content.
|
||||||
|
;; If only one of them is touched, we want to adress this case and
|
||||||
|
;; only update the untouched one
|
||||||
|
text-partial-change? (when (and
|
||||||
|
omit-touched?
|
||||||
|
(= :text (:type origin-shape))
|
||||||
|
(= :content attr)
|
||||||
|
(touched attr-group))
|
||||||
|
(is-text-partial-change? origin-shape dest-shape attr touched))
|
||||||
|
|
||||||
|
skip-operations? (or (= (get origin-shape attr) (get dest-shape attr))
|
||||||
|
(and (touched attr-group)
|
||||||
|
omit-touched?
|
||||||
|
;; When it is a text-partial-change, we should generate operations
|
||||||
|
;; even when omit-touched? is true, but updating only the text or
|
||||||
|
;; the attributes, omiting the other part
|
||||||
|
(not text-partial-change?)))
|
||||||
|
|
||||||
[roperations' uoperations']
|
[roperations' uoperations']
|
||||||
(if (or (= (get origin-shape attr) (get dest-shape attr))
|
(if skip-operations?
|
||||||
(and (touched attr-group) omit-touched?))
|
|
||||||
[roperations uoperations]
|
[roperations uoperations]
|
||||||
(add-update-attr-operations attr dest-shape origin-shape roperations uoperations touched))]
|
(add-update-attr-operations attr dest-shape origin-shape roperations uoperations touched text-partial-change?))]
|
||||||
(recur (next attrs)
|
(recur (next attrs)
|
||||||
roperations'
|
roperations'
|
||||||
uoperations')))))))
|
uoperations')))))))
|
||||||
@@ -1771,7 +1839,7 @@
|
|||||||
;; If the attr is not touched in the origin shape, don't copy it
|
;; If the attr is not touched in the origin shape, don't copy it
|
||||||
(not (touched-origin attr-group)))
|
(not (touched-origin attr-group)))
|
||||||
[roperations uoperations]
|
[roperations uoperations]
|
||||||
(add-update-attr-operations attr dest-shape origin-shape roperations uoperations touched))]
|
(add-update-attr-operations attr dest-shape origin-shape roperations uoperations touched false))]
|
||||||
(recur (next attrs)
|
(recur (next attrs)
|
||||||
roperations'
|
roperations'
|
||||||
uoperations'))
|
uoperations'))
|
||||||
|
|||||||
@@ -14,7 +14,9 @@
|
|||||||
[app.common.test-helpers.components :as thc]
|
[app.common.test-helpers.components :as thc]
|
||||||
[app.common.test-helpers.files :as thf]
|
[app.common.test-helpers.files :as thf]
|
||||||
[app.common.test-helpers.shapes :as ths]
|
[app.common.test-helpers.shapes :as ths]
|
||||||
[app.common.types.container :as ctn]))
|
[app.common.text :as txt]
|
||||||
|
[app.common.types.container :as ctn]
|
||||||
|
[app.common.types.shape :as cts]))
|
||||||
|
|
||||||
;; ----- File building
|
;; ----- File building
|
||||||
|
|
||||||
@@ -58,6 +60,18 @@
|
|||||||
:parent-label frame-label}
|
:parent-label frame-label}
|
||||||
child-params))))
|
child-params))))
|
||||||
|
|
||||||
|
(defn add-frame-with-text
|
||||||
|
[file frame-label child-label text & {:keys [frame-params child-params]}]
|
||||||
|
(let [shape (-> (cts/setup-shape {:type :text :x 0 :y 0 :grow-type :auto-width})
|
||||||
|
(txt/change-text text)
|
||||||
|
(assoc :position-data nil
|
||||||
|
:parent-label frame-label))]
|
||||||
|
(-> file
|
||||||
|
(add-frame frame-label frame-params)
|
||||||
|
(ths/add-sample-shape child-label
|
||||||
|
(merge shape
|
||||||
|
child-params)))))
|
||||||
|
|
||||||
(defn add-minimal-component
|
(defn add-minimal-component
|
||||||
[file component-label root-label
|
[file component-label root-label
|
||||||
& {:keys [component-params root-params]}]
|
& {:keys [component-params root-params]}]
|
||||||
|
|||||||
@@ -18,8 +18,10 @@
|
|||||||
[app.common.types.plugins :as ctpg]
|
[app.common.types.plugins :as ctpg]
|
||||||
[app.common.types.shape-tree :as ctst]
|
[app.common.types.shape-tree :as ctst]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
|
[app.common.types.text :as cttx]
|
||||||
[app.common.types.token :as ctt]
|
[app.common.types.token :as ctt]
|
||||||
[app.common.uuid :as uuid]))
|
[app.common.uuid :as uuid]
|
||||||
|
[clojure.set :as set]))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; SCHEMA
|
;; SCHEMA
|
||||||
@@ -534,8 +536,6 @@
|
|||||||
indicating if shape is touched or not."
|
indicating if shape is touched or not."
|
||||||
[shape attr val & {:keys [ignore-touched ignore-geometry]}]
|
[shape attr val & {:keys [ignore-touched ignore-geometry]}]
|
||||||
(let [group (get ctk/sync-attrs attr)
|
(let [group (get ctk/sync-attrs attr)
|
||||||
token-groups (when (= attr :applied-tokens)
|
|
||||||
(get-token-groups shape val))
|
|
||||||
shape-val (get shape attr)
|
shape-val (get shape attr)
|
||||||
|
|
||||||
ignore?
|
ignore?
|
||||||
@@ -566,22 +566,33 @@
|
|||||||
(gsh/close-attrs? attr val shape-val))
|
(gsh/close-attrs? attr val shape-val))
|
||||||
|
|
||||||
touched?
|
touched?
|
||||||
(and group (not equal?) (not (and ignore-geometry is-geometry?)))]
|
(and group
|
||||||
|
(not equal?)
|
||||||
|
(not (and ignore-geometry is-geometry?)))
|
||||||
|
|
||||||
|
content-diff-type (when (and (= (:type shape) :text) (= attr :content))
|
||||||
|
(cttx/get-diff-type (:content shape) val))
|
||||||
|
|
||||||
|
token-groups (if (= attr :applied-tokens)
|
||||||
|
(get-token-groups shape val)
|
||||||
|
#{})
|
||||||
|
|
||||||
|
groups (cond-> token-groups
|
||||||
|
(and group (not equal?))
|
||||||
|
(set/union #{group} content-diff-type))]
|
||||||
(cond-> shape
|
(cond-> shape
|
||||||
;; Depending on the origin of the attribute change, we need or not to
|
;; Depending on the origin of the attribute change, we need or not to
|
||||||
;; set the "touched" flag for the group the attribute belongs to.
|
;; set the "touched" flag for the group the attribute belongs to.
|
||||||
;; In some cases we need to ignore touched only if the attribute is
|
;; In some cases we need to ignore touched only if the attribute is
|
||||||
;; geometric (position, width or transformation).
|
;; geometric (position, width or transformation).
|
||||||
(and in-copy?
|
(and in-copy?
|
||||||
(or (and group (not equal?)) (seq token-groups))
|
(not-empty groups)
|
||||||
(not ignore?) (not (and ignore-geometry is-geometry?)))
|
(not ignore?)
|
||||||
|
(not (and ignore-geometry is-geometry?)))
|
||||||
(-> (update :touched (fn [touched]
|
(-> (update :touched (fn [touched]
|
||||||
(reduce #(ctk/set-touched-group %1 %2)
|
(reduce #(ctk/set-touched-group %1 %2)
|
||||||
touched
|
touched
|
||||||
(if group
|
groups)))
|
||||||
(cons group token-groups)
|
|
||||||
token-groups))))
|
|
||||||
(dissoc :remote-synced))
|
(dissoc :remote-synced))
|
||||||
|
|
||||||
(nil? val)
|
(nil? val)
|
||||||
|
|||||||
@@ -299,7 +299,6 @@
|
|||||||
(ctkl/get-component (:data component-file) (:component-id head-shape) include-deleted?))]
|
(ctkl/get-component (:data component-file) (:component-id head-shape) include-deleted?))]
|
||||||
(when (some? component)
|
(when (some? component)
|
||||||
(get-ref-shape (:data component-file) component shape :with-context? with-context?))))]
|
(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 find-ref-shape-in-head (ctn/get-parent-heads (:objects container) shape))))
|
||||||
|
|
||||||
(defn advance-shape-ref
|
(defn advance-shape-ref
|
||||||
|
|||||||
144
common/src/app/common/types/text.cljc
Normal file
144
common/src/app/common/types/text.cljc
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.common.types.text
|
||||||
|
(:require
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[clojure.set :as set]))
|
||||||
|
|
||||||
|
(defn- compare-text-content
|
||||||
|
"Given two content text structures, conformed by maps and vectors,
|
||||||
|
compare them, and returns a set with the type of differences.
|
||||||
|
The possibilities are :text-content-text :text-content-attribute and :text-content-structure."
|
||||||
|
[a b]
|
||||||
|
(cond
|
||||||
|
;; If a and b are equal, there is no diff
|
||||||
|
(= a b)
|
||||||
|
#{}
|
||||||
|
|
||||||
|
;; If types are different, the structure is different
|
||||||
|
(not= (type a) (type b))
|
||||||
|
#{:text-content-structure}
|
||||||
|
|
||||||
|
;; If they are maps, check the keys
|
||||||
|
(map? a)
|
||||||
|
(let [keys (-> (set/union (set (keys a)) (set (keys b)))
|
||||||
|
(disj :key))] ;; We have to ignore :key because it is a draft artifact
|
||||||
|
(reduce
|
||||||
|
(fn [acc k]
|
||||||
|
(let [v1 (get a k)
|
||||||
|
v2 (get b k)]
|
||||||
|
(cond
|
||||||
|
;; If the key is :children, keep digging
|
||||||
|
(= k :children)
|
||||||
|
(if (not= (count v1) (count v2))
|
||||||
|
#{:text-content-structure}
|
||||||
|
(into acc
|
||||||
|
(apply set/union
|
||||||
|
(map #(compare-text-content %1 %2) v1 v2))))
|
||||||
|
|
||||||
|
;; If the key is :text, and they are different, it is a text differece
|
||||||
|
(= k :text)
|
||||||
|
(if (not= v1 v2)
|
||||||
|
(conj acc :text-content-text)
|
||||||
|
acc)
|
||||||
|
|
||||||
|
:else
|
||||||
|
;; If the key is not :text, and they are different, it is an attribute differece
|
||||||
|
(if (not= v1 v2)
|
||||||
|
(conj acc :text-content-attribute)
|
||||||
|
acc))))
|
||||||
|
#{}
|
||||||
|
keys))
|
||||||
|
|
||||||
|
:else
|
||||||
|
#{:text-content-structure}))
|
||||||
|
|
||||||
|
|
||||||
|
(defn equal-attrs?
|
||||||
|
"Given a text structure, and a map of attrs, check that all the internal attrs in
|
||||||
|
paragraphs and sentences have the same attrs"
|
||||||
|
[item attrs]
|
||||||
|
(let [item-attrs (dissoc item :text :type :key :children)]
|
||||||
|
(and
|
||||||
|
(or (empty? item-attrs)
|
||||||
|
(= attrs (dissoc item :text :type :key :children)))
|
||||||
|
(every? #(equal-attrs? % attrs) (:children item)))))
|
||||||
|
|
||||||
|
(defn get-first-paragraph-text-attrs
|
||||||
|
"Given a content text structure, extract it's first paragraph
|
||||||
|
text attrs"
|
||||||
|
[content]
|
||||||
|
(-> content
|
||||||
|
(dm/get-in [:children 0 :children 0])
|
||||||
|
(dissoc :text :type :key :children)))
|
||||||
|
|
||||||
|
(defn get-diff-type
|
||||||
|
"Given two content text structures, conformed by maps and vectors,
|
||||||
|
compare them, and returns a set with the type of differences.
|
||||||
|
The possibilities are :text-content-text :text-content-attribute,
|
||||||
|
:text-content-structure and :text-content-structure-same-attrs."
|
||||||
|
[a b]
|
||||||
|
(let [diff-type (compare-text-content a b)]
|
||||||
|
(if-not (contains? diff-type :text-content-structure)
|
||||||
|
diff-type
|
||||||
|
(let [;; get attrs of the first paragraph of the first paragraph-set
|
||||||
|
attrs (get-first-paragraph-text-attrs a)]
|
||||||
|
(if (and (equal-attrs? a attrs)
|
||||||
|
(equal-attrs? b attrs))
|
||||||
|
#{:text-content-structure :text-content-structure-same-attrs}
|
||||||
|
diff-type)))))
|
||||||
|
|
||||||
|
;; TODO We know that there are cases that the blocks of texts are separated
|
||||||
|
;; differently: ["one" " " "two"], ["one " "two"], ["one" " two"]
|
||||||
|
;; so this won't work for 100% of the situations. But it's good enough for now,
|
||||||
|
;; we can iterate on the solution again in the future if needed.
|
||||||
|
(defn equal-structure?
|
||||||
|
"Given two content text structures, check that the structures are equal.
|
||||||
|
This means that all the :children keys at any level has the same number of
|
||||||
|
entries"
|
||||||
|
[a b]
|
||||||
|
(cond
|
||||||
|
(not= (type a) (type b))
|
||||||
|
false
|
||||||
|
|
||||||
|
(map? a)
|
||||||
|
(let [children-a (:children a)
|
||||||
|
children-b (:children b)]
|
||||||
|
(if (not= (count children-a) (count children-b))
|
||||||
|
false
|
||||||
|
(every? true?
|
||||||
|
(map equal-structure? children-a children-b))))
|
||||||
|
|
||||||
|
:else
|
||||||
|
true))
|
||||||
|
|
||||||
|
|
||||||
|
(defn copy-text-keys
|
||||||
|
"Given two equal content text structures, deep copy all the keys :text
|
||||||
|
from origin to destiny"
|
||||||
|
[origin destiny]
|
||||||
|
(cond
|
||||||
|
(map? origin)
|
||||||
|
(into {}
|
||||||
|
(for [k (keys origin) :when (not= k :key)] ;; We ignore :key because it is a draft artifact
|
||||||
|
(cond
|
||||||
|
(= :children k)
|
||||||
|
[k (vec (map #(copy-text-keys %1 %2) (get origin k) (get destiny k)))]
|
||||||
|
(= :text k)
|
||||||
|
[k (:text origin)]
|
||||||
|
:else
|
||||||
|
[k (get destiny k)])))))
|
||||||
|
|
||||||
|
(defn copy-attrs-keys
|
||||||
|
"Given a content text structure and a list of attrs, copy that
|
||||||
|
attrs values on all the content tree"
|
||||||
|
[content attrs]
|
||||||
|
(into {}
|
||||||
|
(for [[k v] content]
|
||||||
|
(if (= :children k)
|
||||||
|
[k (vec (map #(copy-attrs-keys %1 attrs) v))]
|
||||||
|
[k (get attrs k v)]))))
|
||||||
881
common/test/common_tests/logic/text_sync_test.cljc
Normal file
881
common/test/common_tests/logic/text_sync_test.cljc
Normal file
@@ -0,0 +1,881 @@
|
|||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns common-tests.logic.text-sync-test
|
||||||
|
(:require
|
||||||
|
[app.common.files.changes-builder :as pcb]
|
||||||
|
[app.common.logic.libraries :as cll]
|
||||||
|
[app.common.logic.shapes :as cls]
|
||||||
|
[app.common.test-helpers.components :as thc]
|
||||||
|
[app.common.test-helpers.compositions :as tho]
|
||||||
|
[app.common.test-helpers.files :as thf]
|
||||||
|
[app.common.test-helpers.ids-map :as thi]
|
||||||
|
[app.common.test-helpers.shapes :as ths]
|
||||||
|
[clojure.test :as t]))
|
||||||
|
|
||||||
|
(t/use-fixtures :each thi/test-fixture)
|
||||||
|
|
||||||
|
|
||||||
|
(t/deftest test-sync-unchanged-copy-when-changed-attribute
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page (thf/current-page file)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :font-size] "32"))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
(t/is (= "32" (:font-size line)))
|
||||||
|
(t/is (= "hello world" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-unchanged-copy-when-changed-text
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page (thf/current-page file)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :text] "Bye"))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
(t/is (= "14" (:font-size line)))
|
||||||
|
(t/is (= "Bye" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-unchanged-copy-when-changed-both
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page (thf/current-page file)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(-> shape
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :font-size] "32")
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :text] "Bye")))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
(t/is (= "32" (:font-size line)))
|
||||||
|
(t/is (= "Bye" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-attr-copy-when-changed-attribute
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :font-weight] "700"))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :font-size] "32"))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
;; The attr doesn't change, because it was touched
|
||||||
|
(t/is (= "14" (:font-size line)))
|
||||||
|
(t/is (= "hello world" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-attr-copy-when-changed-text
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :font-weight] "700"))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :text] "Bye"))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
(t/is (= "14" (:font-size line)))
|
||||||
|
;; The text is updated because only attrs were touched
|
||||||
|
(t/is (= "Bye" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-attr-copy-when-changed-both
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :font-weight] "700"))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(-> shape
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :font-size] "32")
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :text] "Bye")))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
;; The attr doesn't change, because it was touched
|
||||||
|
(t/is (= "14" (:font-size line)))
|
||||||
|
;; The text is updated because only attrs were touched
|
||||||
|
(t/is (= "Bye" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-text-copy-when-changed-attribute
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :text] "Hi"))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :font-size] "32"))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
;; The attr is updated because only text were touched
|
||||||
|
(t/is (= "32" (:font-size line)))
|
||||||
|
(t/is (= "Hi" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-text-copy-when-changed-text
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :text] "Hi"))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :text] "Bye"))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
(t/is (= "14" (:font-size line)))
|
||||||
|
;; The text doesn't change, because it was touched
|
||||||
|
(t/is (= "Hi" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-text-copy-when-changed-both
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :text] "Hi"))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(-> shape
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :font-size] "32")
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :text] "Bye")))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
;; The attr is updated because only text were touched
|
||||||
|
(t/is (= "32" (:font-size line)))
|
||||||
|
;; The text doesn't change, because it was touched
|
||||||
|
(t/is (= "Hi" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-both-copy-when-changed-attribute
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(-> shape
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :font-weight] "700")
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :text] "Hi")))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :font-size] "32"))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
;; The attr doesn't change, because it was touched
|
||||||
|
(t/is (= "14" (:font-size line)))
|
||||||
|
(t/is (= "Hi" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-both-copy-when-changed-text
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(-> shape
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :font-weight] "700")
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :text] "Hi")))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :text] "Bye"))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
(t/is (= "14" (:font-size line)))
|
||||||
|
;; The text doesn't change, because it was touched
|
||||||
|
(t/is (= "Hi" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-both-copy-when-changed-both
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(-> shape
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :font-weight] "700")
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :text] "Hi")))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(-> shape
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :font-size] "32")
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :text] "Bye")))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
;; The attr doesn't change, because it was touched
|
||||||
|
(t/is (= "14" (:font-size line)))
|
||||||
|
;; The text doesn't change, because it was touched
|
||||||
|
(t/is (= "Hi" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-structure-same-attrs-copy-when-changed-attribute
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(let [line (get-in shape [:content :children 0 :children 0 :children 0])]
|
||||||
|
(update-in shape [:content :children 0 :children 0 :children]
|
||||||
|
#(conj % line))))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
;; Update the attrs on all the content tree
|
||||||
|
(-> shape
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :font-size] "32")
|
||||||
|
(assoc-in [:content :children 0 :children 0 :font-size] "32")))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
;; The attr is updated because all the attrs on the structure are equal
|
||||||
|
(t/is (= "32" (:font-size line)))
|
||||||
|
(t/is (= "hello world" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-structure-same-attrs-copy-when-changed-text
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(let [line (get-in shape [:content :children 0 :children 0 :children 0])]
|
||||||
|
(update-in shape [:content :children 0 :children 0 :children]
|
||||||
|
#(conj % line))))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :text] "Bye"))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
(t/is (= "14" (:font-size line)))
|
||||||
|
;; The text doesn't change, because the structure was touched
|
||||||
|
(t/is (= "hello world" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-structure-same-attrs-copy-when-changed-both
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(let [line (get-in shape [:content :children 0 :children 0 :children 0])]
|
||||||
|
(update-in shape [:content :children 0 :children 0 :children]
|
||||||
|
#(conj % line))))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
;; Update the attrs on all the content tree
|
||||||
|
(-> shape
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :font-size] "32")
|
||||||
|
(assoc-in [:content :children 0 :children 0 :font-size] "32")
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :text] "Bye")))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
;; The attr is updated because all the attrs on the structure are equal
|
||||||
|
(t/is (= "32" (:font-size line)))
|
||||||
|
;; The text doesn't change, because the structure was touched
|
||||||
|
(t/is (= "hello world" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-structure-diff-attrs-copy-when-changed-attribute
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(let [line (-> (get-in shape [:content :children 0 :children 0 :children 0])
|
||||||
|
(assoc :font-weight "700"))]
|
||||||
|
(update-in shape [:content :children 0 :children 0 :children]
|
||||||
|
#(conj % line))))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
;; Update the attrs on all the content tree
|
||||||
|
(-> shape
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :font-size] "32")
|
||||||
|
(assoc-in [:content :children 0 :children 0 :font-size] "32")))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
;; The attr doesn't change, because not all the attrs on the structure are equal
|
||||||
|
(t/is (= "14" (:font-size line)))
|
||||||
|
(t/is (= "hello world" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-structure-diff-attrs-copy-when-changed-text
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(let [line (-> (get-in shape [:content :children 0 :children 0 :children 0])
|
||||||
|
(assoc :font-weight "700"))]
|
||||||
|
(update-in shape [:content :children 0 :children 0 :children]
|
||||||
|
#(conj % line))))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :children 0 :text] "Bye"))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
(t/is (= "14" (:font-size line)))
|
||||||
|
;; The text doesn't change, because the structure was touched
|
||||||
|
(t/is (= "hello world" (:text line)))))
|
||||||
|
|
||||||
|
(t/deftest test-sync-updated-structure-diff-attrs-copy-when-changed-both
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file0 (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page0 (thf/current-page file0)
|
||||||
|
copy-child (ths/get-shape file0 :copy-child)
|
||||||
|
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page0))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(let [line (-> (get-in shape [:content :children 0 :children 0 :children 0])
|
||||||
|
(assoc :font-weight "700"))]
|
||||||
|
(update-in shape [:content :children 0 :children 0 :children]
|
||||||
|
#(conj % line))))
|
||||||
|
(:objects (thf/current-page file0))
|
||||||
|
{})
|
||||||
|
file (thf/apply-changes file0 changes)
|
||||||
|
main-child (ths/get-shape file :main-child)
|
||||||
|
page (thf/current-page file)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes1 (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id main-child)}
|
||||||
|
(fn [shape]
|
||||||
|
;; Update the attrs on all the content tree
|
||||||
|
(-> shape
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :font-size] "32")
|
||||||
|
(assoc-in [:content :children 0 :children 0 :font-size] "32")
|
||||||
|
(assoc-in [:content :children 0 :children 0 :children 0 :text] "Bye")))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
updated-file (thf/apply-changes file changes1)
|
||||||
|
|
||||||
|
changes2 (cll/generate-sync-file-changes (pcb/empty-changes)
|
||||||
|
nil
|
||||||
|
:components
|
||||||
|
(:id updated-file)
|
||||||
|
(thi/id :component1)
|
||||||
|
(:id updated-file)
|
||||||
|
{(:id updated-file) updated-file}
|
||||||
|
(:id updated-file))
|
||||||
|
|
||||||
|
file' (thf/apply-changes updated-file changes2)
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)
|
||||||
|
line (get-in copy-child' [:content :children 0 :children 0 :children 0])]
|
||||||
|
;; The attr doesn't change, because not all the attrs on the structure are equal
|
||||||
|
(t/is (= "14" (:font-size line)))
|
||||||
|
;; The text doesn't change, because the structure was touched
|
||||||
|
(t/is (= "hello world" (:text line)))))
|
||||||
132
common/test/common_tests/logic/text_touched_test.cljc
Normal file
132
common/test/common_tests/logic/text_touched_test.cljc
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns common-tests.logic.text-touched-test
|
||||||
|
(:require
|
||||||
|
[app.common.files.changes-builder :as pcb]
|
||||||
|
[app.common.logic.shapes :as cls]
|
||||||
|
[app.common.test-helpers.components :as thc]
|
||||||
|
[app.common.test-helpers.compositions :as tho]
|
||||||
|
[app.common.test-helpers.files :as thf]
|
||||||
|
[app.common.test-helpers.ids-map :as thi]
|
||||||
|
[app.common.test-helpers.shapes :as ths]
|
||||||
|
[clojure.test :as t]))
|
||||||
|
|
||||||
|
(t/use-fixtures :each thi/test-fixture)
|
||||||
|
|
||||||
|
(t/deftest test-text-copy-changed-attribute
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page (thf/current-page file)
|
||||||
|
copy-child (ths/get-shape file :copy-child)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :font-size] "32"))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
file' (thf/apply-changes file changes)
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)]
|
||||||
|
(t/is (= #{:content-group :text-content-attribute} (:touched copy-child')))))
|
||||||
|
|
||||||
|
(t/deftest test-text-copy-changed-text
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page (thf/current-page file)
|
||||||
|
copy-child (ths/get-shape file :copy-child)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(assoc-in shape [:content :children 0 :children 0 :text] "Bye"))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
file' (thf/apply-changes file changes)
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)]
|
||||||
|
(t/is (= #{:content-group :text-content-text} (:touched copy-child')))))
|
||||||
|
|
||||||
|
(t/deftest test-text-copy-changed-both
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page (thf/current-page file)
|
||||||
|
copy-child (ths/get-shape file :copy-child)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(-> shape
|
||||||
|
(assoc-in [:content :children 0 :children 0 :font-size] "32")
|
||||||
|
(assoc-in [:content :children 0 :children 0 :text] "Bye")))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
file' (thf/apply-changes file changes)
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)]
|
||||||
|
(t/is (= #{:content-group :text-content-attribute :text-content-text} (:touched copy-child')))))
|
||||||
|
|
||||||
|
(t/deftest test-text-copy-changed-structure-same-attrs
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page (thf/current-page file)
|
||||||
|
copy-child (ths/get-shape file :copy-child)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(let [line (get-in shape [:content :children 0 :children 0])]
|
||||||
|
(update-in shape [:content :children 0 :children]
|
||||||
|
#(conj % line))))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
file' (thf/apply-changes file changes)
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)]
|
||||||
|
(t/is (= #{:content-group :text-content-structure :text-content-structure-same-attrs} (:touched copy-child')))))
|
||||||
|
|
||||||
|
(t/deftest test-text-copy-changed-structure-diff-attrs
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file (-> (thf/sample-file :file1)
|
||||||
|
(tho/add-frame-with-text :main-root :main-child "hello world")
|
||||||
|
(thc/make-component :component1 :main-root)
|
||||||
|
(thc/instantiate-component :component1 :copy-root {:children-labels [:copy-child]}))
|
||||||
|
page (thf/current-page file)
|
||||||
|
copy-child (ths/get-shape file :copy-child)
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes (cls/generate-update-shapes (pcb/empty-changes nil (:id page))
|
||||||
|
#{(:id copy-child)}
|
||||||
|
(fn [shape]
|
||||||
|
(let [line (-> shape
|
||||||
|
(get-in [:content :children 0 :children 0])
|
||||||
|
(assoc :font-size "32"))]
|
||||||
|
(update-in shape [:content :children 0 :children]
|
||||||
|
#(conj % line))))
|
||||||
|
(:objects page)
|
||||||
|
{})
|
||||||
|
|
||||||
|
file' (thf/apply-changes file changes)
|
||||||
|
copy-child' (ths/get-shape file' :copy-child)]
|
||||||
|
(t/is (= #{:content-group :text-content-structure} (:touched copy-child')))))
|
||||||
|
|
||||||
88
common/test/common_tests/types/text_test.cljc
Normal file
88
common/test/common_tests/types/text_test.cljc
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns common-tests.types.text-test
|
||||||
|
(:require
|
||||||
|
|
||||||
|
[app.common.text :as txt]
|
||||||
|
[app.common.types.shape :as cts]
|
||||||
|
[app.common.types.text :as cttx]
|
||||||
|
[clojure.test :as t :include-macros true]))
|
||||||
|
|
||||||
|
(def content-base (-> (cts/setup-shape {:type :text :x 0 :y 0 :grow-type :auto-width})
|
||||||
|
(txt/change-text "hello world")
|
||||||
|
(assoc :position-data nil)
|
||||||
|
:content))
|
||||||
|
|
||||||
|
(def content-changed-text (assoc-in content-base [:children 0 :children 0 :children 0 :text] "changed"))
|
||||||
|
(def content-changed-attr (assoc-in content-base [:children 0 :children 0 :children 0 :font-size] "32"))
|
||||||
|
(def content-changed-both (-> content-base
|
||||||
|
(assoc-in [:children 0 :children 0 :children 0 :text] "changed")
|
||||||
|
(assoc-in [:children 0 :children 0 :children 0 :font-size] "32")))
|
||||||
|
(def line (get-in content-base [:children 0 :children 0 :children 0]))
|
||||||
|
(def content-changed-structure (update-in content-base [:children 0 :children 0 :children]
|
||||||
|
#(conj % (assoc line :font-weight "700"))))
|
||||||
|
(def content-changed-structure-same-attrs (update-in content-base [:children 0 :children 0 :children]
|
||||||
|
#(conj % line)))
|
||||||
|
|
||||||
|
(t/deftest test-get-diff-type
|
||||||
|
(let [diff-text (cttx/get-diff-type content-base content-changed-text)
|
||||||
|
diff-attr (cttx/get-diff-type content-base content-changed-attr)
|
||||||
|
diff-both (cttx/get-diff-type content-base content-changed-both)
|
||||||
|
diff-structure (cttx/get-diff-type content-base content-changed-structure)
|
||||||
|
diff-structure-same-attrs (cttx/get-diff-type content-base content-changed-structure-same-attrs)]
|
||||||
|
(t/is (= #{:text-content-text} diff-text))
|
||||||
|
(t/is (= #{:text-content-attribute} diff-attr))
|
||||||
|
(t/is (= #{:text-content-text :text-content-attribute} diff-both))
|
||||||
|
(t/is (= #{:text-content-structure} diff-structure))
|
||||||
|
(t/is (= #{:text-content-structure :text-content-structure-same-attrs} diff-structure-same-attrs))))
|
||||||
|
|
||||||
|
|
||||||
|
(t/deftest test-equal-structure
|
||||||
|
(t/is (true? (cttx/equal-structure? content-base content-changed-text)))
|
||||||
|
(t/is (true? (cttx/equal-structure? content-base content-changed-attr)))
|
||||||
|
(t/is (true? (cttx/equal-structure? content-base content-changed-both)))
|
||||||
|
(t/is (false? (cttx/equal-structure? content-base content-changed-structure))))
|
||||||
|
|
||||||
|
|
||||||
|
(t/deftest test-copy-text-keys
|
||||||
|
(let [copy-base-to-changed-text (cttx/copy-text-keys content-base content-changed-text)
|
||||||
|
copy-changed-text-to-base (cttx/copy-text-keys content-changed-text content-base)
|
||||||
|
|
||||||
|
copy-base-to-changed-attr (cttx/copy-text-keys content-base content-changed-attr)
|
||||||
|
|
||||||
|
copy-changes-text-to-changed-attr (cttx/copy-text-keys content-changed-text content-changed-attr)
|
||||||
|
updates-text-in-changed-attr (assoc-in content-changed-attr [:children 0 :children 0 :children 0 :text] "changed")]
|
||||||
|
|
||||||
|
;; If we copy the text of the base to the content-changed-text, the result is equal than the base
|
||||||
|
(t/is (= copy-base-to-changed-text content-base))
|
||||||
|
|
||||||
|
;; If we copy the text of the content-changed-text to the base, the result is equal than the content-changed-text
|
||||||
|
(t/is (= copy-changed-text-to-base content-changed-text))
|
||||||
|
|
||||||
|
;; If we copy the text of the base to the content-changed-attr, it doesn't nothing because the text were equal
|
||||||
|
(t/is (= copy-base-to-changed-attr content-changed-attr))
|
||||||
|
|
||||||
|
;; If we copy the text of the content-changed-text to the content-changed-attr, it keeps the changes on the attrs
|
||||||
|
;; and the changes on the texts
|
||||||
|
(t/is (= copy-changes-text-to-changed-attr updates-text-in-changed-attr))))
|
||||||
|
|
||||||
|
|
||||||
|
(t/deftest test-copy-attrs-keys
|
||||||
|
(let [attrs (-> (cttx/get-first-paragraph-text-attrs content-changed-structure-same-attrs)
|
||||||
|
(assoc :font-size "32"))
|
||||||
|
updated (cttx/copy-attrs-keys content-changed-structure-same-attrs attrs)
|
||||||
|
get-font-sizes (fn get-font-sizes [fonts item]
|
||||||
|
(let [font-size (:font-size item)
|
||||||
|
fonts (if font-size (conj fonts font-size) fonts)]
|
||||||
|
(if (seq (:children item))
|
||||||
|
(reduce get-font-sizes fonts (:children item))
|
||||||
|
fonts)))
|
||||||
|
original-font-sizes (get-font-sizes [] content-changed-structure-same-attrs)
|
||||||
|
updated-font-sizes (get-font-sizes [] updated)]
|
||||||
|
|
||||||
|
(t/is (every? #(= % "14") original-font-sizes))
|
||||||
|
(t/is (every? #(= % "32") updated-font-sizes))))
|
||||||
Reference in New Issue
Block a user