♻️ Refactor commit-changes and undo actions

This commit is contained in:
alonso.torres 2021-04-27 17:57:00 +02:00
parent da8a32047c
commit 59187f9ff4
30 changed files with 508 additions and 457 deletions

View file

@ -7,7 +7,6 @@
(ns app.main.data.workspace (ns app.main.data.workspace
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.exceptions :as ex]
[app.common.geom.align :as gal] [app.common.geom.align :as gal]
[app.common.geom.matrix :as gmt] [app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
@ -19,37 +18,31 @@
[app.common.spec :as us] [app.common.spec :as us]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.config :as cfg] [app.config :as cfg]
[app.main.constants :as c]
[app.main.data.workspace.colors :as mdc]
[app.main.data.messages :as dm] [app.main.data.messages :as dm]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.drawing :as dwd] [app.main.data.workspace.drawing :as dwd]
[app.main.data.workspace.path :as dwdp]
[app.main.data.workspace.groups :as dwg] [app.main.data.workspace.groups :as dwg]
[app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.notifications :as dwn] [app.main.data.workspace.notifications :as dwn]
[app.main.data.workspace.path :as dwdp]
[app.main.data.workspace.persistence :as dwp] [app.main.data.workspace.persistence :as dwp]
[app.main.data.workspace.selection :as dws] [app.main.data.workspace.selection :as dws]
[app.main.data.workspace.transforms :as dwt]
[app.main.data.workspace.svg-upload :as svg] [app.main.data.workspace.svg-upload :as svg]
[app.main.data.workspace.transforms :as dwt]
[app.main.data.workspace.undo :as dwu]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.main.store :as st]
[app.main.streams :as ms] [app.main.streams :as ms]
[app.main.worker :as uw]
[app.util.dom :as dom]
[app.util.http :as http] [app.util.http :as http]
[app.util.i18n :refer [tr] :as i18n] [app.util.i18n :as i18n]
[app.util.logging :as log] [app.util.logging :as log]
[app.util.object :as obj]
[app.util.router :as rt] [app.util.router :as rt]
[app.util.timers :as ts]
[app.util.transit :as t] [app.util.transit :as t]
[app.util.webapi :as wapi] [app.util.webapi :as wapi]
[beicon.core :as rx] [beicon.core :as rx]
[cljs.spec.alpha :as s] [cljs.spec.alpha :as s]
[clojure.set :as set] [clojure.set :as set]
[cuerdas.core :as str] [cuerdas.core :as str]
[goog.string.path :as path]
[potok.core :as ptk])) [potok.core :as ptk]))
;; (log/set-level! :trace) ;; (log/set-level! :trace)
@ -269,7 +262,7 @@
:name name} :name name}
uchange {:type :del-page uchange {:type :del-page
:id id}] :id id}]
(rx/of (dwc/commit-changes [rchange] [uchange] {:commit-local? true})))))) (rx/of (dch/commit-changes [rchange] [uchange] {:commit-local? true}))))))
(defn duplicate-page [page-id] (defn duplicate-page [page-id]
(ptk/reify ::duplicate-page (ptk/reify ::duplicate-page
@ -287,7 +280,7 @@
:page page} :page page}
uchange {:type :del-page uchange {:type :del-page
:id id}] :id id}]
(rx/of (dwc/commit-changes [rchange] [uchange] {:commit-local? true})))))) (rx/of (dch/commit-changes [rchange] [uchange] {:commit-local? true}))))))
(s/def ::rename-page (s/def ::rename-page
(s/keys :req-un [::id ::name])) (s/keys :req-un [::id ::name]))
@ -306,7 +299,7 @@
uchg {:type :mod-page uchg {:type :mod-page
:id id :id id
:name (:name page)}] :name (:name page)}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true})))))) (rx/of (dch/commit-changes [rchg] [uchg] {:commit-local? true}))))))
(declare purge-page) (declare purge-page)
(declare go-to-file) (declare go-to-file)
@ -323,7 +316,7 @@
:id id} :id id}
uchg {:type :add-page uchg {:type :add-page
:page page}] :page page}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true}) (rx/of (dch/commit-changes [rchg] [uchg] {:commit-local? true})
(when (= id (:current-page-id state)) (when (= id (:current-page-id state))
go-to-file)))))) go-to-file))))))
@ -604,7 +597,7 @@
(ptk/reify ::update-shape (ptk/reify ::update-shape
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(rx/of (dwc/update-shapes [id] #(merge % attrs)))))) (rx/of (dch/update-shapes [id] #(merge % attrs))))))
(defn start-rename-shape (defn start-rename-shape
[id] [id]
@ -712,7 +705,7 @@
:index (cp/position-on-parent id objects)})) :index (cp/position-on-parent id objects)}))
selected)] selected)]
;; TODO: maybe missing the :reg-objects event? ;; TODO: maybe missing the :reg-objects event?
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true}))))))
;; --- Change Shape Order (D&D Ordering) ;; --- Change Shape Order (D&D Ordering)
@ -986,7 +979,7 @@
shapes-to-detach shapes-to-detach
shapes-to-reroot shapes-to-reroot
shapes-to-deroot)] shapes-to-deroot)]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true})
(dwc/expand-collapse parent-id)))))) (dwc/expand-collapse parent-id))))))
(defn relocate-selected-shapes (defn relocate-selected-shapes
@ -1039,7 +1032,7 @@
uchg {:type :mov-page uchg {:type :mov-page
:id id :id id
:index cidx}] :index cidx}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true})))))) (rx/of (dch/commit-changes [rchg] [uchg] {:commit-local? true}))))))
;; --- Shape / Selection Alignment and Distribution ;; --- Shape / Selection Alignment and Distribution
@ -1141,7 +1134,7 @@
(assoc shape :proportion-lock false) (assoc shape :proportion-lock false)
(-> (assoc shape :proportion-lock true) (-> (assoc shape :proportion-lock true)
(gpr/assign-proportions))))] (gpr/assign-proportions))))]
(rx/of (dwc/update-shapes [id] assign-proportions)))))) (rx/of (dch/update-shapes [id] assign-proportions))))))
;; --- Update Shape Position ;; --- Update Shape Position
@ -1183,7 +1176,7 @@
(cond-> obj (cond-> obj
(boolean? blocked) (assoc :blocked blocked) (boolean? blocked) (assoc :blocked blocked)
(boolean? hidden) (assoc :hidden hidden)))] (boolean? hidden) (assoc :hidden hidden)))]
(rx/of (dwc/update-shapes-recursive [id] update-fn)))))) (rx/of (dch/update-shapes-recursive [id] update-fn))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -1410,7 +1403,7 @@
(catch :default e (catch :default e
(let [data (ex-data e)] (let [data (ex-data e)]
(if (:not-implemented data) (if (:not-implemented data)
(rx/of (dm/warn (tr "errors.clipboard-not-implemented"))) (rx/of (dm/warn (i18n/tr "errors.clipboard-not-implemented")))
(js/console.error "ERROR" e)))))))) (js/console.error "ERROR" e))))))))
(defn paste-from-event (defn paste-from-event
@ -1582,7 +1575,7 @@
(map #(get-in % [:obj :id])) (map #(get-in % [:obj :id]))
(into (d/ordered-set)))] (into (d/ordered-set)))]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true})
(dwc/select-shapes selected))))] (dwc/select-shapes selected))))]
(ptk/reify ::paste-shape (ptk/reify ::paste-shape
ptk/WatchEvent ptk/WatchEvent
@ -1629,10 +1622,10 @@
:height height :height height
:grow-type (if (> (count text) 100) :auto-height :auto-width) :grow-type (if (> (count text) 100) :auto-height :auto-width)
:content (as-content text)})] :content (as-content text)})]
(rx/of (dwc/start-undo-transaction) (rx/of (dwu/start-undo-transaction)
(dws/deselect-all) (dws/deselect-all)
(dwc/add-shape shape) (dwc/add-shape shape)
(dwc/commit-undo-transaction)))))) (dwu/commit-undo-transaction))))))
(defn- paste-svg (defn- paste-svg
[text] [text]
@ -1743,7 +1736,7 @@
(let [page-id (get state :current-page-id) (let [page-id (get state :current-page-id)
options (dwc/lookup-page-options state page-id) options (dwc/lookup-page-options state page-id)
previus-color (:background options)] previus-color (:background options)]
(rx/of (dwc/commit-changes (rx/of (dch/commit-changes
[{:type :set-option [{:type :set-option
:page-id page-id :page-id page-id
:option :background :option :background

View file

@ -0,0 +1,219 @@
;; 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) UXBOX Labs SL
(ns app.main.data.workspace.changes
(:require
[app.common.data :as d]
[app.common.pages :as cp]
[app.common.pages.spec :as spec]
[app.common.spec :as us]
[app.main.data.workspace.undo :as dwu]
[app.main.worker :as uw]
[app.util.logging :as log]
[beicon.core :as rx]
[cljs.spec.alpha :as s]
[clojure.set :as set]
[potok.core :as ptk]))
;; Change this to :info :debug or :trace to debug this module
(log/set-level! :warn)
(s/def ::coll-of-uuid
(s/every ::us/uuid))
(defonce page-change? #{:add-page :mod-page :del-page :mov-page})
(declare commit-changes)
(def commit-changes? (ptk/type? ::commit-changes))
(defn- generate-operations
([ma mb] (generate-operations ma mb false))
([ma mb undo?]
(let [ops (let [ma-keys (set (keys ma))
mb-keys (set (keys mb))
added (set/difference mb-keys ma-keys)
removed (set/difference ma-keys mb-keys)
both (set/intersection ma-keys mb-keys)]
(d/concat
(mapv #(array-map :type :set :attr % :val (get mb %)) added)
(mapv #(array-map :type :set :attr % :val nil) removed)
(loop [items (seq both)
result []]
(if items
(let [k (first items)
vma (get ma k)
vmb (get mb k)]
(if (= vma vmb)
(recur (next items) result)
(recur (next items)
(conj result {:type :set
:attr k
:val vmb
:ignore-touched undo?}))))
result))))]
(if undo?
(conj ops {:type :set-touched :touched (:touched mb)})
ops))))
(defn update-shapes
([ids f] (update-shapes ids f nil))
([ids f {:keys [reg-objects?] :or {reg-objects? false}}]
(us/assert ::coll-of-uuid ids)
(us/assert fn? f)
(ptk/reify ::update-shapes
ptk/WatchEvent
(watch [_ state stream]
(let [page-id (:current-page-id state)
objects (get-in state [:workspace-data :pages-index page-id :objects])]
(loop [ids (seq ids)
rch []
uch []]
(if (nil? ids)
(rx/of (commit-changes
(cond-> rch reg-objects? (conj {:type :reg-objects :page-id page-id :shapes (vec ids)}))
(cond-> uch reg-objects? (conj {:type :reg-objects :page-id page-id :shapes (vec ids)}))
{:commit-local? true}))
(let [id (first ids)
obj1 (get objects id)
obj2 (f obj1)
rch-operations (generate-operations obj1 obj2)
uch-operations (generate-operations obj2 obj1 true)
rchg {:type :mod-obj
:page-id page-id
:operations rch-operations
:id id}
uchg {:type :mod-obj
:page-id page-id
:operations uch-operations
:id id}]
(recur (next ids)
(if (empty? rch-operations) rch (conj rch rchg))
(if (empty? uch-operations) uch (conj uch uchg)))))))))))
(defn update-shapes-recursive
[ids f]
(us/assert ::coll-of-uuid ids)
(us/assert fn? f)
(letfn [(impl-get-children [objects id]
(cons id (cp/get-children id objects)))
(impl-gen-changes [objects page-id ids]
(loop [sids (seq ids)
cids (seq (impl-get-children objects (first sids)))
rchanges []
uchanges []]
(cond
(nil? sids)
[rchanges uchanges]
(nil? cids)
(recur (next sids)
(seq (impl-get-children objects (first (next sids))))
rchanges
uchanges)
:else
(let [id (first cids)
obj1 (get objects id)
obj2 (f obj1)
rops (generate-operations obj1 obj2)
uops (generate-operations obj2 obj1 true)
rchg {:type :mod-obj
:page-id page-id
:operations rops
:id id}
uchg {:type :mod-obj
:page-id page-id
:operations uops
:id id}]
(recur sids
(next cids)
(conj rchanges rchg)
(conj uchanges uchg))))))]
(ptk/reify ::update-shapes-recursive
ptk/WatchEvent
(watch [_ state stream]
(let [page-id (:current-page-id state)
objects (get-in state [:workspace-data :pages-index page-id :objects])
[rchanges uchanges] (impl-gen-changes objects page-id (seq ids))]
(rx/of (commit-changes rchanges uchanges {:commit-local? true})))))))
(defn update-indices
[page-id changes]
(ptk/reify ::update-indices
ptk/EffectEvent
(effect [_ state stream]
(uw/ask! {:cmd :update-page-indices
:page-id page-id
:changes changes}))))
(defn commit-changes
([changes undo-changes]
(commit-changes changes undo-changes {}))
([changes undo-changes {:keys [save-undo?
commit-local?
file-id]
:or {save-undo? true
commit-local? false}
:as opts}]
(us/verify ::cp/changes changes)
(us/verify ::cp/changes undo-changes)
(log/debug :msg "commit-changes"
:js/changes changes
:js/undo-changes undo-changes)
(let [error (volatile! nil)]
(ptk/reify ::commit-changes
cljs.core/IDeref
(-deref [_] {:file-id file-id :changes changes})
ptk/UpdateEvent
(update [_ state]
(let [current-file-id (get state :current-file-id)
file-id (or file-id current-file-id)
path1 (if (= file-id current-file-id)
[:workspace-file :data]
[:workspace-libraries file-id :data])
path2 (if (= file-id current-file-id)
[:workspace-data]
[:workspace-libraries file-id :data])]
(try
(us/verify ::spec/changes changes)
(let [state (update-in state path1 cp/process-changes changes false)]
(cond-> state
commit-local? (update-in path2 cp/process-changes changes false)))
(catch :default e
(vreset! error e)
state))))
ptk/WatchEvent
(watch [_ state stream]
(when-not @error
(let [;; adds page-id to page changes (that have the `id` field instead)
add-page-id
(fn [{:keys [id type page] :as change}]
(cond-> change
(page-change? type)
(assoc :page-id (or id (:id page)))))
changes-by-pages
(->> changes
(map add-page-id)
(remove #(nil? (:page-id %)))
(group-by :page-id))
process-page-changes
(fn [[page-id changes]]
(update-indices page-id changes))]
(rx/concat
(rx/from (map process-page-changes changes-by-pages))
(when (and save-undo? (seq undo-changes))
(let [entry {:undo-changes undo-changes
:redo-changes changes}]
(rx/of (dwu/append-undo entry))))))))))))

View file

@ -13,6 +13,7 @@
[app.main.data.modal :as md] [app.main.data.modal :as md]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.texts :as dwt] [app.main.data.workspace.texts :as dwt]
[app.main.data.workspace.changes :as dch]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.main.store :as st] [app.main.store :as st]
[app.main.streams :as ms] [app.main.streams :as ms]
@ -150,7 +151,7 @@
(rx/concat (rx/concat
(rx/from (map #(dwt/update-text-attrs {:id % :attrs attrs}) text-ids)) (rx/from (map #(dwt/update-text-attrs {:id % :attrs attrs}) text-ids))
(rx/of (dwc/update-shapes shape-ids (fn [shape] (d/merge shape attrs))))))))) (rx/of (dch/update-shapes shape-ids (fn [shape] (d/merge shape attrs)))))))))
(defn change-stroke (defn change-stroke
[ids color] [ids color]
@ -176,7 +177,7 @@
(contains? color :opacity) (contains? color :opacity)
(assoc :stroke-opacity (:opacity color)))] (assoc :stroke-opacity (:opacity color)))]
(rx/of (dwc/update-shapes ids (fn [shape] (rx/of (dch/update-shapes ids (fn [shape]
(cond-> (d/merge shape attrs) (cond-> (d/merge shape attrs)
(= (:stroke-style shape) :none) (= (:stroke-style shape) :none)
(assoc :stroke-style :solid (assoc :stroke-style :solid

View file

@ -10,17 +10,15 @@
[app.common.geom.proportions :as gpr] [app.common.geom.proportions :as gpr]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.pages :as cp] [app.common.pages :as cp]
[app.common.pages.spec :as spec]
[app.common.spec :as us] [app.common.spec :as us]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.worker :as uw] [app.main.data.workspace.changes :as dch]
[app.main.data.workspace.undo :as dwu]
[app.main.streams :as ms] [app.main.streams :as ms]
[app.main.worker :as uw]
[app.util.logging :as log] [app.util.logging :as log]
[app.util.timers :as ts]
[beicon.core :as rx] [beicon.core :as rx]
[cljs.spec.alpha :as s] [cljs.spec.alpha :as s]
[clojure.set :as set]
[cuerdas.core :as str]
[potok.core :as ptk])) [potok.core :as ptk]))
;; Change this to :info :debug or :trace to debug this module ;; Change this to :info :debug or :trace to debug this module
@ -58,121 +56,6 @@
(get-in state [:workspace-data :components component-id :objects]))) (get-in state [:workspace-data :components component-id :objects])))
;; --- Changes Handling
(defonce page-change? #{:add-page :mod-page :del-page :mov-page})
(defn commit-changes
([changes undo-changes]
(commit-changes changes undo-changes {}))
([changes undo-changes {:keys [save-undo?
commit-local?
file-id]
:or {save-undo? true
commit-local? false}
:as opts}]
(us/verify ::cp/changes changes)
(us/verify ::cp/changes undo-changes)
(log/debug :msg "commit-changes"
:js/changes changes
:js/undo-changes undo-changes)
(let [error (volatile! nil)]
(ptk/reify ::commit-changes
cljs.core/IDeref
(-deref [_] {:file-id file-id :changes changes})
ptk/UpdateEvent
(update [_ state]
(let [current-file-id (get state :current-file-id)
file-id (or file-id current-file-id)
path1 (if (= file-id current-file-id)
[:workspace-file :data]
[:workspace-libraries file-id :data])
path2 (if (= file-id current-file-id)
[:workspace-data]
[:workspace-libraries file-id :data])]
(try
(us/verify ::spec/changes changes)
(let [state (update-in state path1 cp/process-changes changes false)]
(cond-> state
commit-local? (update-in path2 cp/process-changes changes false)))
(catch :default e
(vreset! error e)
state))))
ptk/WatchEvent
(watch [_ state stream]
(when-not @error
(let [;; adds page-id to page changes (that have the `id` field instead)
add-page-id
(fn [{:keys [id type page] :as change}]
(cond-> change
(page-change? type)
(assoc :page-id (or id (:id page)))))
changes-by-pages
(->> changes
(map add-page-id)
(remove #(nil? (:page-id %)))
(group-by :page-id))
process-page-changes
(fn [[page-id changes]]
(update-indices page-id changes))]
(rx/concat
(rx/from (map process-page-changes changes-by-pages))
(when (and save-undo? (seq undo-changes))
(let [entry {:undo-changes undo-changes
:redo-changes changes}]
(rx/of (append-undo entry))))))))))))
(defn generate-operations
([ma mb] (generate-operations ma mb false))
([ma mb undo?]
(let [ops (let [ma-keys (set (keys ma))
mb-keys (set (keys mb))
added (set/difference mb-keys ma-keys)
removed (set/difference ma-keys mb-keys)
both (set/intersection ma-keys mb-keys)]
(d/concat
(mapv #(array-map :type :set :attr % :val (get mb %)) added)
(mapv #(array-map :type :set :attr % :val nil) removed)
(loop [items (seq both)
result []]
(if items
(let [k (first items)
vma (get ma k)
vmb (get mb k)]
(if (= vma vmb)
(recur (next items) result)
(recur (next items)
(conj result {:type :set
:attr k
:val vmb
:ignore-touched undo?}))))
result))))]
(if undo?
(conj ops {:type :set-touched :touched (:touched mb)})
ops))))
(defn generate-changes
[page-id objects1 objects2]
(letfn [(impl-diff [res id]
(let [obj1 (get objects1 id)
obj2 (get objects2 id)
ops (generate-operations (dissoc obj1 :shapes :frame-id)
(dissoc obj2 :shapes :frame-id))]
(if (empty? ops)
res
(conj res {:type :mod-obj
:page-id page-id
:operations ops
:id id}))))]
(reduce impl-diff [] (set/union (set (keys objects1))
(set (keys objects2))))))
;; --- Selection Index Handling ;; --- Selection Index Handling
(defn initialize-indices (defn initialize-indices
@ -186,14 +69,7 @@
(->> (uw/ask! msg) (->> (uw/ask! msg)
(rx/map (constantly ::index-initialized))))))) (rx/map (constantly ::index-initialized)))))))
(defn update-indices
[page-id changes]
(ptk/reify ::update-indices
ptk/EffectEvent
(effect [_ state stream]
(uw/ask! {:cmd :update-page-indices
:page-id page-id
:changes changes}))))
;; --- Common Helpers & Events ;; --- Common Helpers & Events
@ -253,110 +129,8 @@
(update state :workspace-local dissoc :expanded)))) (update state :workspace-local dissoc :expanded))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; These functions should've been in `src/app/main/data/workspace/undo.cljs` but doing that causes
;; Undo / Redo ;; a circular dependency with `src/app/main/data/workspace/changes.cljs`
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(s/def ::undo-changes ::cp/changes)
(s/def ::redo-changes ::cp/changes)
(s/def ::undo-entry
(s/keys :req-un [::undo-changes ::redo-changes]))
(def MAX-UNDO-SIZE 50)
(defn- conj-undo-entry
[undo data]
(let [undo (conj undo data)
cnt (count undo)]
(if (> cnt MAX-UNDO-SIZE)
(subvec undo (- cnt MAX-UNDO-SIZE))
undo)))
(defn- materialize-undo
[changes index]
(ptk/reify ::materialize-undo
ptk/UpdateEvent
(update [_ state]
(-> state
(update :workspace-data cp/process-changes changes)
(assoc-in [:workspace-undo :index] index)))))
(defn- reset-undo
[index]
(ptk/reify ::reset-undo
ptk/UpdateEvent
(update [_ state]
(-> state
(update :workspace-undo dissoc :undo-index)
(update-in [:workspace-undo :items] (fn [queue] (into [] (take (inc index) queue))))))))
(defn- add-undo-entry
[state entry]
(if (and entry
(not-empty (:undo-changes entry))
(not-empty (:redo-changes entry)))
(let [index (get-in state [:workspace-undo :index] -1)
items (get-in state [:workspace-undo :items] [])
items (->> items (take (inc index)) (into []))
items (conj-undo-entry items entry)]
(-> state
(update :workspace-undo assoc :items items
:index (min (inc index)
(dec MAX-UNDO-SIZE)))))
state))
(defn- accumulate-undo-entry
[state {:keys [undo-changes redo-changes]}]
(-> state
(update-in [:workspace-undo :transaction :undo-changes] #(into undo-changes %))
(update-in [:workspace-undo :transaction :redo-changes] #(into % redo-changes))))
(defn- append-undo
[entry]
(us/verify ::undo-entry entry)
(ptk/reify ::append-undo
ptk/UpdateEvent
(update [_ state]
(if (get-in state [:workspace-undo :transaction])
(accumulate-undo-entry state entry)
(add-undo-entry state entry)))))
(defonce empty-tx {:undo-changes [] :redo-changes []})
(defn start-undo-transaction []
(ptk/reify ::start-undo-transaction
ptk/UpdateEvent
(update [_ state]
;; We commit the old transaction before starting the new one
(let [current-tx (get-in state [:workspace-undo :transaction])]
(cond-> state
(nil? current-tx) (assoc-in [:workspace-undo :transaction] empty-tx))))))
(defn discard-undo-transaction []
(ptk/reify ::discard-undo-transaction
ptk/UpdateEvent
(update [_ state]
(update state :workspace-undo dissoc :transaction))))
(defn commit-undo-transaction []
(ptk/reify ::commit-undo-transaction
ptk/UpdateEvent
(update [_ state]
(-> state
(add-undo-entry (get-in state [:workspace-undo :transaction]))
(update :workspace-undo dissoc :transaction)))))
(def pop-undo-into-transaction
(ptk/reify ::last-undo-into-transaction
ptk/UpdateEvent
(update [_ state]
(let [index (get-in state [:workspace-undo :index] -1)]
(cond-> state
(>= index 0) (accumulate-undo-entry (get-in state [:workspace-undo :items index]))
(>= index 0) (update-in [:workspace-undo :index] dec))))))
;; If these functions change modules review /src/app/main/data/workspace/path/undo.cljs
(def undo (def undo
(ptk/reify ::undo (ptk/reify ::undo
ptk/WatchEvent ptk/WatchEvent
@ -370,8 +144,8 @@
index (or (:index undo) (dec (count items)))] index (or (:index undo) (dec (count items)))]
(when-not (or (empty? items) (= index -1)) (when-not (or (empty? items) (= index -1))
(let [changes (get-in items [index :undo-changes])] (let [changes (get-in items [index :undo-changes])]
(rx/of (materialize-undo changes (dec index)) (rx/of (dwu/materialize-undo changes (dec index))
(commit-changes changes [] {:save-undo? false})))))))))) (dch/commit-changes changes [] {:save-undo? false}))))))))))
(def redo (def redo
(ptk/reify ::redo (ptk/reify ::redo
@ -385,16 +159,8 @@
index (or (:index undo) (dec (count items)))] index (or (:index undo) (dec (count items)))]
(when-not (or (empty? items) (= index (dec (count items)))) (when-not (or (empty? items) (= index (dec (count items))))
(let [changes (get-in items [(inc index) :redo-changes])] (let [changes (get-in items [(inc index) :redo-changes])]
(rx/of (materialize-undo changes (inc index)) (rx/of (dwu/materialize-undo changes (inc index))
(commit-changes changes [] {:save-undo? false})))))))))) (dch/commit-changes changes [] {:save-undo? false}))))))))))
(def reinitialize-undo
(ptk/reify ::reset-undo
ptk/UpdateEvent
(update [_ state]
(assoc state :workspace-undo {}))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Shapes ;; Shapes
@ -420,93 +186,6 @@
;; NOTE: This is a generic implementation for update multiple shapes ;; NOTE: This is a generic implementation for update multiple shapes
;; in one single commit/undo entry. ;; in one single commit/undo entry.
(s/def ::coll-of-uuid
(s/every ::us/uuid))
(defn update-shapes
([ids f] (update-shapes ids f nil))
([ids f {:keys [reg-objects?] :or {reg-objects? false}}]
(us/assert ::coll-of-uuid ids)
(us/assert fn? f)
(ptk/reify ::update-shapes
ptk/WatchEvent
(watch [_ state stream]
(let [page-id (:current-page-id state)
objects (lookup-page-objects state page-id)]
(loop [ids (seq ids)
rch []
uch []]
(if (nil? ids)
(rx/of (commit-changes
(cond-> rch reg-objects? (conj {:type :reg-objects :page-id page-id :shapes (vec ids)}))
(cond-> uch reg-objects? (conj {:type :reg-objects :page-id page-id :shapes (vec ids)}))
{:commit-local? true}))
(let [id (first ids)
obj1 (get objects id)
obj2 (f obj1)
rch-operations (generate-operations obj1 obj2)
uch-operations (generate-operations obj2 obj1 true)
rchg {:type :mod-obj
:page-id page-id
:operations rch-operations
:id id}
uchg {:type :mod-obj
:page-id page-id
:operations uch-operations
:id id}]
(recur (next ids)
(if (empty? rch-operations) rch (conj rch rchg))
(if (empty? uch-operations) uch (conj uch uchg)))))))))))
(defn update-shapes-recursive
[ids f]
(us/assert ::coll-of-uuid ids)
(us/assert fn? f)
(letfn [(impl-get-children [objects id]
(cons id (cp/get-children id objects)))
(impl-gen-changes [objects page-id ids]
(loop [sids (seq ids)
cids (seq (impl-get-children objects (first sids)))
rchanges []
uchanges []]
(cond
(nil? sids)
[rchanges uchanges]
(nil? cids)
(recur (next sids)
(seq (impl-get-children objects (first (next sids))))
rchanges
uchanges)
:else
(let [id (first cids)
obj1 (get objects id)
obj2 (f obj1)
rops (generate-operations obj1 obj2)
uops (generate-operations obj2 obj1 true)
rchg {:type :mod-obj
:page-id page-id
:operations rops
:id id}
uchg {:type :mod-obj
:page-id page-id
:operations uops
:id id}]
(recur sids
(next cids)
(conj rchanges rchg)
(conj uchanges uchg))))))]
(ptk/reify ::update-shapes-recursive
ptk/WatchEvent
(watch [_ state stream]
(let [page-id (:current-page-id state)
objects (lookup-page-objects state page-id)
[rchanges uchanges] (impl-gen-changes objects page-id (seq ids))]
(rx/of (commit-changes rchanges uchanges {:commit-local? true})))))))
(defn select-shapes (defn select-shapes
[ids] [ids]
@ -639,7 +318,7 @@
(assoc :name name)))] (assoc :name name)))]
(rx/concat (rx/concat
(rx/of (commit-changes rchanges uchanges {:commit-local? true}) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true})
(select-shapes (d/ordered-set id))) (select-shapes (d/ordered-set id)))
(when (= :text (:type attrs)) (when (= :text (:type attrs))
(->> (rx/of (start-edition-mode id)) (->> (rx/of (start-edition-mode id))
@ -672,7 +351,7 @@
:page-id page-id :page-id page-id
:index index :index index
:shapes [shape-id]})))] :shapes [shape-id]})))]
(rx/of (commit-changes rchanges uchanges {:commit-local? true})))))) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true}))))))
(defn delete-shapes (defn delete-shapes
@ -779,7 +458,7 @@
;; (cljs.pprint/pprint rchanges) ;; (cljs.pprint/pprint rchanges)
;; (println "================ uchanges") ;; (println "================ uchanges")
;; (cljs.pprint/pprint uchanges) ;; (cljs.pprint/pprint uchanges)
(rx/of (commit-changes rchanges uchanges {:commit-local? true})))))) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true}))))))
;; --- Add shape to Workspace ;; --- Add shape to Workspace

View file

@ -12,6 +12,7 @@
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.selection :as dws] [app.main.data.workspace.selection :as dws]
[app.main.data.workspace.undo :as dwu]
[app.main.streams :as ms] [app.main.streams :as ms]
[app.main.worker :as uw])) [app.main.worker :as uw]))
@ -54,7 +55,7 @@
;; Add & select the created shape to the workspace ;; Add & select the created shape to the workspace
(rx/concat (rx/concat
(if (= :text (:type shape)) (if (= :text (:type shape))
(rx/of (dwc/start-undo-transaction)) (rx/of (dwu/start-undo-transaction))
(rx/empty)) (rx/empty))
(rx/of (dwc/add-shape shape)) (rx/of (dwc/add-shape shape))

View file

@ -10,7 +10,7 @@
[potok.core :as ptk] [potok.core :as ptk]
[app.common.data :as d] [app.common.data :as d]
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.workspace.common :as dwc])) [app.main.data.workspace.changes :as dch]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Grid ;; Grid
@ -48,7 +48,7 @@
grid {:type :square grid {:type :square
:params params :params params
:display true}] :display true}]
(rx/of (dwc/update-shapes [frame-id] (rx/of (dch/update-shapes [frame-id]
(fn [obj] (update obj :grids (fnil #(conj % grid) []))))))))) (fn [obj] (update obj :grids (fnil #(conj % grid) [])))))))))
@ -57,14 +57,14 @@
(ptk/reify ::set-frame-grid (ptk/reify ::set-frame-grid
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(rx/of (dwc/update-shapes [frame-id] (fn [o] (update o :grids (fnil #(d/remove-at-index % index) [])))))))) (rx/of (dch/update-shapes [frame-id] (fn [o] (update o :grids (fnil #(d/remove-at-index % index) []))))))))
(defn set-frame-grid (defn set-frame-grid
[frame-id index data] [frame-id index data]
(ptk/reify ::set-frame-grid (ptk/reify ::set-frame-grid
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(rx/of (dwc/update-shapes [frame-id] #(assoc-in % [:grids index] data)))))) (rx/of (dch/update-shapes [frame-id] #(assoc-in % [:grids index] data))))))
(defn set-default-grid (defn set-default-grid
[type params] [type params]
@ -73,7 +73,7 @@
(watch [_ state stream] (watch [_ state stream]
(let [pid (:current-page-id state) (let [pid (:current-page-id state)
prev-value (get-in state [:workspace-data :pages-index pid :options :saved-grids type])] prev-value (get-in state [:workspace-data :pages-index pid :options :saved-grids type])]
(rx/of (dwc/commit-changes [{:type :set-option (rx/of (dch/commit-changes [{:type :set-option
:page-id pid :page-id pid
:option [:saved-grids type] :option [:saved-grids type]
:value params}] :value params}]

View file

@ -4,6 +4,7 @@
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.pages :as cp] [app.common.pages :as cp]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.selection :as dws] [app.main.data.workspace.selection :as dws]
[beicon.core :as rx] [beicon.core :as rx]
[potok.core :as ptk])) [potok.core :as ptk]))
@ -106,7 +107,7 @@
shapes (shapes-for-grouping objects selected)] shapes (shapes-for-grouping objects selected)]
(when-not (empty? shapes) (when-not (empty? shapes)
(let [[group rchanges uchanges] (prepare-create-group page-id shapes "Group-" false)] (let [[group rchanges uchanges] (prepare-create-group page-id shapes "Group-" false)]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true})
(dwc/select-shapes (d/ordered-set (:id group)))))))))) (dwc/select-shapes (d/ordered-set (:id group))))))))))
(def ungroup-selected (def ungroup-selected
@ -122,7 +123,7 @@
(= (:type group) :group)) (= (:type group) :group))
(let [[rchanges uchanges] (let [[rchanges uchanges]
(prepare-remove-group page-id group objects)] (prepare-remove-group page-id group objects)]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))))) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true}))))))))
(def mask-group (def mask-group
(ptk/reify ::mask-group (ptk/reify ::mask-group
@ -176,7 +177,7 @@
:page-id page-id :page-id page-id
:shapes [(:id group)]})] :shapes [(:id group)]})]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true})
(dwc/select-shapes (d/ordered-set (:id group)))))))))) (dwc/select-shapes (d/ordered-set (:id group))))))))))
(def unmask-group (def unmask-group
@ -209,7 +210,7 @@
:page-id page-id :page-id page-id
:shapes [(:id group)]}]] :shapes [(:id group)]}]]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true})
(dwc/select-shapes (d/ordered-set (:id group)))))))))) (dwc/select-shapes (d/ordered-set (:id group))))))))))

View file

@ -14,6 +14,7 @@
[app.common.geom.shapes :as geom] [app.common.geom.shapes :as geom]
[app.main.data.messages :as dm] [app.main.data.messages :as dm]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.libraries-helpers :as dwlh] [app.main.data.workspace.libraries-helpers :as dwlh]
[app.common.pages :as cp] [app.common.pages :as cp]
[app.main.repo :as rp] [app.main.repo :as rp]
@ -90,7 +91,7 @@
uchg {:type :del-color uchg {:type :del-color
:id id}] :id id}]
(rx/of #(assoc-in % [:workspace-local :color-for-rename] id) (rx/of #(assoc-in % [:workspace-local :color-for-rename] id)
(dwc/commit-changes [rchg] [uchg] {:commit-local? true}))))))) (dch/commit-changes [rchg] [uchg] {:commit-local? true})))))))
(defn add-recent-color (defn add-recent-color
[color] [color]
@ -100,7 +101,7 @@
(watch [_ state s] (watch [_ state s]
(let [rchg {:type :add-recent-color (let [rchg {:type :add-recent-color
:color color}] :color color}]
(rx/of (dwc/commit-changes [rchg] [] {:commit-local? true})))))) (rx/of (dch/commit-changes [rchg] [] {:commit-local? true}))))))
(def clear-color-for-rename (def clear-color-for-rename
(ptk/reify ::clear-color-for-rename (ptk/reify ::clear-color-for-rename
@ -120,7 +121,7 @@
:color color} :color color}
uchg {:type :mod-color uchg {:type :mod-color
:color prev}] :color prev}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true}) (rx/of (dch/commit-changes [rchg] [uchg] {:commit-local? true})
(sync-file (:current-file-id state) file-id)))))) (sync-file (:current-file-id state) file-id))))))
(defn delete-color (defn delete-color
@ -134,7 +135,7 @@
:id id} :id id}
uchg {:type :add-color uchg {:type :add-color
:color prev}] :color prev}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true})))))) (rx/of (dch/commit-changes [rchg] [uchg] {:commit-local? true}))))))
(defn add-media (defn add-media
[{:keys [id] :as media}] [{:keys [id] :as media}]
@ -147,7 +148,7 @@
:object obj} :object obj}
uchg {:type :del-media uchg {:type :del-media
:id id}] :id id}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true})))))) (rx/of (dch/commit-changes [rchg] [uchg] {:commit-local? true}))))))
(defn rename-media (defn rename-media
[id new-name] [id new-name]
@ -169,7 +170,7 @@
:name (:name object) :name (:name object)
:path (:path object)}}]] :path (:path object)}}]]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true}))))))
(defn delete-media (defn delete-media
[{:keys [id] :as params}] [{:keys [id] :as params}]
@ -182,7 +183,7 @@
:id id} :id id}
uchg {:type :add-media uchg {:type :add-media
:object prev}] :object prev}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true})))))) (rx/of (dch/commit-changes [rchg] [uchg] {:commit-local? true}))))))
(defn add-typography (defn add-typography
([typography] (add-typography typography true)) ([typography] (add-typography typography true))
@ -196,7 +197,7 @@
:typography typography} :typography typography}
uchg {:type :del-typography uchg {:type :del-typography
:id (:id typography)}] :id (:id typography)}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true}) (rx/of (dch/commit-changes [rchg] [uchg] {:commit-local? true})
#(cond-> % #(cond-> %
edit? edit?
(assoc-in [:workspace-local :rename-typography] (:id typography)))))))))) (assoc-in [:workspace-local :rename-typography] (:id typography))))))))))
@ -213,7 +214,7 @@
:typography typography} :typography typography}
uchg {:type :mod-typography uchg {:type :mod-typography
:typography prev}] :typography prev}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true}) (rx/of (dch/commit-changes [rchg] [uchg] {:commit-local? true})
(sync-file (:current-file-id state) file-id)))))) (sync-file (:current-file-id state) file-id))))))
(defn delete-typography (defn delete-typography
@ -227,7 +228,7 @@
:id id} :id id}
uchg {:type :add-typography uchg {:type :add-typography
:typography prev}] :typography prev}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true})))))) (rx/of (dch/commit-changes [rchg] [uchg] {:commit-local? true}))))))
(def add-component (def add-component
"Add a new component to current file library, from the currently selected shapes." "Add a new component to current file library, from the currently selected shapes."
@ -242,7 +243,7 @@
(let [[group rchanges uchanges] (let [[group rchanges uchanges]
(dwlh/generate-add-component selected objects page-id file-id)] (dwlh/generate-add-component selected objects page-id file-id)]
(when-not (empty? rchanges) (when-not (empty? rchanges)
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true})
(dwc/select-shapes (d/ordered-set (:id group)))))))))) (dwc/select-shapes (d/ordered-set (:id group))))))))))
(defn rename-component (defn rename-component
@ -273,7 +274,7 @@
:path (:path component) :path (:path component)
:objects objects}]] :objects objects}]]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true}))))))
(defn duplicate-component (defn duplicate-component
"Create a new component copied from the one with the given id." "Create a new component copied from the one with the given id."
@ -301,7 +302,7 @@
uchanges [{:type :del-component uchanges [{:type :del-component
:id (:id new-shape)}]] :id (:id new-shape)}]]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true}))))))
(defn delete-component (defn delete-component
"Delete the component with the given id, from the current file library." "Delete the component with the given id, from the current file library."
@ -321,7 +322,7 @@
:path (:path component) :path (:path component)
:shapes (vals (:objects component))}]] :shapes (vals (:objects component))}]]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true}))))))
(defn instantiate-component (defn instantiate-component
"Create a new shape in the current page, from the component with the given id "Create a new shape in the current page, from the component with the given id
@ -398,7 +399,7 @@
:ignore-touched true}) :ignore-touched true})
new-shapes)] new-shapes)]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true})
(dwc/select-shapes (d/ordered-set (:id new-shape)))))))) (dwc/select-shapes (d/ordered-set (:id new-shape))))))))
(defn detach-component (defn detach-component
@ -461,7 +462,7 @@
:val (:touched obj)}]}) :val (:touched obj)}]})
shapes)] shapes)]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true}))))))
(defn nav-to-component-file (defn nav-to-component-file
[file-id] [file-id]
@ -514,7 +515,7 @@
rchanges rchanges
local-library)) local-library))
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true}))))))
(defn update-component (defn update-component
"Modify the component linked to the shape with the given id, in the "Modify the component linked to the shape with the given id, in the
@ -569,11 +570,11 @@
file)) file))
(rx/of (when (seq local-rchanges) (rx/of (when (seq local-rchanges)
(dwc/commit-changes local-rchanges local-uchanges (dch/commit-changes local-rchanges local-uchanges
{:commit-local? true {:commit-local? true
:file-id (:id local-library)})) :file-id (:id local-library)}))
(when (seq rchanges) (when (seq rchanges)
(dwc/commit-changes rchanges uchanges (dch/commit-changes rchanges uchanges
{:commit-local? true {:commit-local? true
:file-id file-id}))))))) :file-id file-id})))))))
@ -623,7 +624,7 @@
(rx/concat (rx/concat
(rx/of (dm/hide-tag :sync-dialog)) (rx/of (dm/hide-tag :sync-dialog))
(when rchanges (when rchanges
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true
:file-id file-id}))) :file-id file-id})))
(when (not= file-id library-id) (when (not= file-id library-id)
;; When we have just updated the library file, give some time for the ;; When we have just updated the library file, give some time for the
@ -666,7 +667,7 @@
(log/debug :msg "SYNC-FILE (2nd stage) finished" :js/rchanges (log-changes (log/debug :msg "SYNC-FILE (2nd stage) finished" :js/rchanges (log-changes
rchanges rchanges
file)) file))
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true
:file-id file-id}))))))) :file-id file-id})))))))
(def ignore-sync (def ignore-sync

View file

@ -7,7 +7,7 @@
(ns app.main.data.workspace.path.changes (ns app.main.data.workspace.path.changes
(:require (:require
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.changes :as dch]
[app.main.data.workspace.path.helpers :as helpers] [app.main.data.workspace.path.helpers :as helpers]
[app.main.data.workspace.path.spec :as spec] [app.main.data.workspace.path.spec :as spec]
[app.main.data.workspace.path.state :as st] [app.main.data.workspace.path.state :as st]
@ -67,7 +67,7 @@
(let [shape (get-in state (st/get-path state)) (let [shape (get-in state (st/get-path state))
page-id (:current-page-id state) page-id (:current-page-id state)
[rch uch] (generate-path-changes page-id shape old-content (:content shape))] [rch uch] (generate-path-changes page-id shape old-content (:content shape))]
(rx/of (dwc/commit-changes rch uch {:commit-local? true}))) (rx/of (dch/commit-changes rch uch {:commit-local? true})))
(rx/empty))))))) (rx/empty)))))))

View file

@ -9,7 +9,7 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.math :as mth] [app.common.math :as mth]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.changes :as dch]
[app.main.data.workspace.path.changes :as changes] [app.main.data.workspace.path.changes :as changes]
[app.main.data.workspace.path.common :as common] [app.main.data.workspace.path.common :as common]
[app.main.data.workspace.path.helpers :as helpers] [app.main.data.workspace.path.helpers :as helpers]
@ -60,7 +60,7 @@
[rch uch] (changes/generate-path-changes page-id shape (:content shape) new-content)] [rch uch] (changes/generate-path-changes page-id shape (:content shape) new-content)]
(rx/of (dwc/commit-changes rch uch {:commit-local? true}) (rx/of (dch/commit-changes rch uch {:commit-local? true})
(selection/update-selection point-change) (selection/update-selection point-change)
(fn [state] (update-in state [:workspace-local :edit-path id] dissoc :content-modifiers :moving-nodes :moving-handler))))))) (fn [state] (update-in state [:workspace-local :edit-path id] dissoc :content-modifiers :moving-nodes :moving-handler)))))))

View file

@ -6,7 +6,7 @@
(ns app.main.data.workspace.path.tools (ns app.main.data.workspace.path.tools
(:require (:require
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.changes :as dch]
[app.main.data.workspace.path.changes :as changes] [app.main.data.workspace.path.changes :as changes]
[app.main.data.workspace.path.common :as common] [app.main.data.workspace.path.common :as common]
[app.main.data.workspace.path.state :as st] [app.main.data.workspace.path.state :as st]
@ -32,7 +32,7 @@
new-content (-> (tool-fn (:content shape) points) new-content (-> (tool-fn (:content shape) points)
(ups/close-subpaths)) (ups/close-subpaths))
[rch uch] (changes/generate-path-changes page-id shape (:content shape) new-content)] [rch uch] (changes/generate-path-changes page-id shape (:content shape) new-content)]
(rx/of (dwc/commit-changes rch uch {:commit-local? true}))))))) (rx/of (dch/commit-changes rch uch {:commit-local? true})))))))
(defn make-corner (defn make-corner
([] ([]

View file

@ -17,6 +17,7 @@
[app.main.data.media :as di] [app.main.data.media :as di]
[app.main.data.messages :as dm] [app.main.data.messages :as dm]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.selection :as dws] [app.main.data.workspace.selection :as dws]
[app.main.data.workspace.svg-upload :as svg] [app.main.data.workspace.svg-upload :as svg]
@ -51,7 +52,7 @@
(let [stoper (rx/filter #(= ::finalize %) stream) (let [stoper (rx/filter #(= ::finalize %) stream)
forcer (rx/filter #(= ::force-persist %) stream) forcer (rx/filter #(= ::force-persist %) stream)
notifier (->> stream notifier (->> stream
(rx/filter (ptk/type? ::dwc/commit-changes)) (rx/filter dch/commit-changes?)
(rx/debounce 2000) (rx/debounce 2000)
(rx/merge stoper forcer)) (rx/merge stoper forcer))
@ -79,7 +80,7 @@
(st/emit! (update-persistence-status {:status :saved})))] (st/emit! (update-persistence-status {:status :saved})))]
(->> (rx/merge (->> (rx/merge
(->> stream (->> stream
(rx/filter (ptk/type? ::dwc/commit-changes)) (rx/filter dch/commit-changes?)
(rx/map deref) (rx/map deref)
(rx/filter local-file?) (rx/filter local-file?)
(rx/tap on-dirty) (rx/tap on-dirty)
@ -91,7 +92,7 @@
(rx/tap on-saving) (rx/tap on-saving)
(rx/take-until (rx/delay 100 stoper))) (rx/take-until (rx/delay 100 stoper)))
(->> stream (->> stream
(rx/filter (ptk/type? ::dwc/commit-changes)) (rx/filter dch/commit-changes?)
(rx/map deref) (rx/map deref)
(rx/filter library-file?) (rx/filter library-file?)
(rx/filter (complement #(empty? (:changes %)))) (rx/filter (complement #(empty? (:changes %))))

View file

@ -18,6 +18,7 @@
[app.common.spec :as us] [app.common.spec :as us]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.changes :as dch]
[app.main.data.modal :as md] [app.main.data.modal :as md]
[app.main.streams :as ms] [app.main.streams :as ms]
[app.main.worker :as uw])) [app.main.worker :as uw]))
@ -395,7 +396,7 @@
(map #(get-in % [:obj :id])) (map #(get-in % [:obj :id]))
(into (d/ordered-set)))] (into (d/ordered-set)))]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true})
(select-shapes selected)))))) (select-shapes selected))))))
(defn change-hover-state (defn change-hover-state

View file

@ -10,6 +10,7 @@
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.data.workspace.colors :as mdc] [app.main.data.workspace.colors :as mdc]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.undo :as dwu]
[app.main.data.workspace.drawing :as dwd] [app.main.data.workspace.drawing :as dwd]
[app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.texts :as dwtxt] [app.main.data.workspace.texts :as dwtxt]
@ -123,7 +124,7 @@
:clear-undo {:tooltip (ds/meta "Q") :clear-undo {:tooltip (ds/meta "Q")
:command (ds/c-mod "q") :command (ds/c-mod "q")
:fn #(st/emit! dwc/reinitialize-undo)} :fn #(st/emit! dwu/reinitialize-undo)}
:draw-frame {:tooltip "A" :draw-frame {:tooltip "A"
:command "a" :command "a"

View file

@ -14,6 +14,7 @@
[app.common.pages :as cp] [app.common.pages :as cp]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.changes :as dch]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.util.color :as uc] [app.util.color :as uc]
[app.util.path.parser :as upp] [app.util.path.parser :as upp]
@ -462,7 +463,7 @@
rchanges (conj rchanges reg-objects-action)] rchanges (conj rchanges reg-objects-action)]
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}) (rx/of (dch/commit-changes rchanges uchanges {:commit-local? true})
(dwc/select-shapes (d/ordered-set root-id)))) (dwc/select-shapes (d/ordered-set root-id))))
(catch :default e (catch :default e

View file

@ -15,6 +15,8 @@
[app.main.data.workspace.selection :as dws] [app.main.data.workspace.selection :as dws]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.transforms :as dwt] [app.main.data.workspace.transforms :as dwt]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.undo :as dwu]
[app.main.fonts :as fonts] [app.main.fonts :as fonts]
[app.util.object :as obj] [app.util.object :as obj]
[app.util.text-editor :as ted] [app.util.text-editor :as ted]
@ -77,8 +79,8 @@
(when (and (not= content (:content shape)) (when (and (not= content (:content shape))
(some? (:current-page-id state))) (some? (:current-page-id state)))
(rx/of (rx/of
(dwc/update-shapes [id] #(assoc % :content content)) (dch/update-shapes [id] #(assoc % :content content))
(dwc/commit-undo-transaction))))) (dwu/commit-undo-transaction)))))
(rx/of (dws/deselect-shape id) (rx/of (dws/deselect-shape id)
(dwc/delete-shapes [id]))))))) (dwc/delete-shapes [id])))))))
@ -141,7 +143,7 @@
shape-ids (cond (= (:type shape) :text) [id] shape-ids (cond (= (:type shape) :text) [id]
(= (:type shape) :group) (cp/get-children id objects))] (= (:type shape) :group) (cp/get-children id objects))]
(rx/of (dwc/update-shapes shape-ids update-fn)))))) (rx/of (dch/update-shapes shape-ids update-fn))))))
(defn update-paragraph-attrs (defn update-paragraph-attrs
[{:keys [id attrs]}] [{:keys [id attrs]}]
@ -169,7 +171,7 @@
shape-ids (cond (= (:type shape) :text) [id] shape-ids (cond (= (:type shape) :text) [id]
(= (:type shape) :group) (cp/get-children id objects))] (= (:type shape) :group) (cp/get-children id objects))]
(rx/of (dwc/update-shapes shape-ids update-fn)))))))) (rx/of (dch/update-shapes shape-ids update-fn))))))))
(defn update-text-attrs (defn update-text-attrs
[{:keys [id attrs]}] [{:keys [id attrs]}]
@ -187,7 +189,7 @@
update-fn #(update-shape % txt/is-text-node? attrs/merge attrs) update-fn #(update-shape % txt/is-text-node? attrs/merge attrs)
shape-ids (cond (= (:type shape) :text) [id] shape-ids (cond (= (:type shape) :text) [id]
(= (:type shape) :group) (cp/get-children id objects))] (= (:type shape) :group) (cp/get-children id objects))]
(rx/of (dwc/update-shapes shape-ids update-fn))))))) (rx/of (dch/update-shapes shape-ids update-fn)))))))
;; --- RESIZE UTILS ;; --- RESIZE UTILS

View file

@ -14,7 +14,9 @@
[app.common.pages :as cp] [app.common.pages :as cp]
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.selection :as dws] [app.main.data.workspace.selection :as dws]
[app.main.data.workspace.undo :as dwu]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.snap :as snap] [app.main.snap :as snap]
[app.main.store :as st] [app.main.store :as st]
@ -140,7 +142,7 @@
(filter #(= :text (:type %))) (filter #(= :text (:type %)))
(map :id))] (map :id))]
(rx/concat (rx/concat
(rx/of (dwc/update-shapes text-shapes-ids #(assoc % :grow-type :fixed))) (rx/of (dch/update-shapes text-shapes-ids #(assoc % :grow-type :fixed)))
(->> ms/mouse-position (->> ms/mouse-position
(rx/with-latest vector ms/mouse-position-shift) (rx/with-latest vector ms/mouse-position-shift)
(rx/map normalize-proportion-lock) (rx/map normalize-proportion-lock)
@ -259,9 +261,9 @@
:shapes [(:id shape)]})))] :shapes [(:id shape)]})))]
(when-not (empty? rch) (when-not (empty? rch)
(rx/of dwc/pop-undo-into-transaction (rx/of dwu/pop-undo-into-transaction
(dwc/commit-changes rch uch {:commit-local? true}) (dch/commit-changes rch uch {:commit-local? true})
(dwc/commit-undo-transaction) (dwu/commit-undo-transaction)
(dwc/expand-collapse frame-id))))))) (dwc/expand-collapse frame-id)))))))
(defn start-move (defn start-move

View file

@ -0,0 +1,134 @@
;; 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) UXBOX Labs SL
(ns app.main.data.workspace.undo
(:require
[app.common.data :as d]
[app.common.geom.proportions :as gpr]
[app.common.geom.shapes :as gsh]
[app.common.pages :as cp]
[app.common.pages.spec :as spec]
[app.common.spec :as us]
[app.common.uuid :as uuid]
[app.main.worker :as uw]
[app.main.streams :as ms]
[app.util.logging :as log]
[app.util.timers :as ts]
[beicon.core :as rx]
[cljs.spec.alpha :as s]
[clojure.set :as set]
[cuerdas.core :as str]
[potok.core :as ptk]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Undo / Redo
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(s/def ::undo-changes ::cp/changes)
(s/def ::redo-changes ::cp/changes)
(s/def ::undo-entry
(s/keys :req-un [::undo-changes ::redo-changes]))
(def MAX-UNDO-SIZE 50)
(defn- conj-undo-entry
[undo data]
(let [undo (conj undo data)
cnt (count undo)]
(if (> cnt MAX-UNDO-SIZE)
(subvec undo (- cnt MAX-UNDO-SIZE))
undo)))
(defn- materialize-undo
[changes index]
(ptk/reify ::materialize-undo
ptk/UpdateEvent
(update [_ state]
(-> state
(update :workspace-data cp/process-changes changes)
(assoc-in [:workspace-undo :index] index)))))
(defn- reset-undo
[index]
(ptk/reify ::reset-undo
ptk/UpdateEvent
(update [_ state]
(-> state
(update :workspace-undo dissoc :undo-index)
(update-in [:workspace-undo :items] (fn [queue] (into [] (take (inc index) queue))))))))
(defn- add-undo-entry
[state entry]
(if (and entry
(not-empty (:undo-changes entry))
(not-empty (:redo-changes entry)))
(let [index (get-in state [:workspace-undo :index] -1)
items (get-in state [:workspace-undo :items] [])
items (->> items (take (inc index)) (into []))
items (conj-undo-entry items entry)]
(-> state
(update :workspace-undo assoc :items items
:index (min (inc index)
(dec MAX-UNDO-SIZE)))))
state))
(defn- accumulate-undo-entry
[state {:keys [undo-changes redo-changes]}]
(-> state
(update-in [:workspace-undo :transaction :undo-changes] #(into undo-changes %))
(update-in [:workspace-undo :transaction :redo-changes] #(into % redo-changes))))
(defn- append-undo
[entry]
(us/verify ::undo-entry entry)
(ptk/reify ::append-undo
ptk/UpdateEvent
(update [_ state]
(if (get-in state [:workspace-undo :transaction])
(accumulate-undo-entry state entry)
(add-undo-entry state entry)))))
(defonce empty-tx {:undo-changes [] :redo-changes []})
(defn start-undo-transaction []
(ptk/reify ::start-undo-transaction
ptk/UpdateEvent
(update [_ state]
;; We commit the old transaction before starting the new one
(let [current-tx (get-in state [:workspace-undo :transaction])]
(cond-> state
(nil? current-tx) (assoc-in [:workspace-undo :transaction] empty-tx))))))
(defn discard-undo-transaction []
(ptk/reify ::discard-undo-transaction
ptk/UpdateEvent
(update [_ state]
(update state :workspace-undo dissoc :transaction))))
(defn commit-undo-transaction []
(ptk/reify ::commit-undo-transaction
ptk/UpdateEvent
(update [_ state]
(-> state
(add-undo-entry (get-in state [:workspace-undo :transaction]))
(update :workspace-undo dissoc :transaction)))))
(def pop-undo-into-transaction
(ptk/reify ::last-undo-into-transaction
ptk/UpdateEvent
(update [_ state]
(let [index (get-in state [:workspace-undo :index] -1)]
(cond-> state
(>= index 0) (accumulate-undo-entry (get-in state [:workspace-undo :items index]))
(>= index 0) (update-in [:workspace-undo :index] dec))))))
(def reinitialize-undo
(ptk/reify ::reset-undo
ptk/UpdateEvent
(update [_ state]
(assoc state :workspace-undo {}))))

View file

@ -10,6 +10,7 @@
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.undo :as dwu]
[app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.shortcuts :as sc] [app.main.data.workspace.shortcuts :as sc]
[app.main.refs :as refs] [app.main.refs :as refs]
@ -83,10 +84,10 @@
;; We defer the execution so the mouse event won't close the editor ;; We defer the execution so the mouse event won't close the editor
(timers/schedule #(st/emit! (dw/start-editing-selected)))) (timers/schedule #(st/emit! (dw/start-editing-selected))))
do-update-component (st/emitf do-update-component (st/emitf
(dwc/start-undo-transaction) (dwu/start-undo-transaction)
(dwl/update-component id) (dwl/update-component id)
(dwl/sync-file current-file-id (:component-file shape)) (dwl/sync-file current-file-id (:component-file shape))
(dwc/commit-undo-transaction)) (dwu/commit-undo-transaction))
confirm-update-remote-component (st/emitf confirm-update-remote-component (st/emitf
(dwl/update-component id) (dwl/update-component id)
(dwl/sync-file current-file-id (dwl/sync-file current-file-id

View file

@ -19,6 +19,7 @@
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.undo :as dwu]
[app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.texts :as dwt] [app.main.data.workspace.texts :as dwt]
[app.main.exports :as exports] [app.main.exports :as exports]
@ -142,9 +143,9 @@
(if (empty? selected-components) (if (empty? selected-components)
(st/emit! (dwl/duplicate-component {:id (:component-id @state)})) (st/emit! (dwl/duplicate-component {:id (:component-id @state)}))
(do (do
(st/emit! (dwc/start-undo-transaction)) (st/emit! (dwu/start-undo-transaction))
(apply st/emit! (map #(dwl/duplicate-component {:id %}) selected-components)) (apply st/emit! (map #(dwl/duplicate-component {:id %}) selected-components))
(st/emit! (dwc/commit-undo-transaction)))))) (st/emit! (dwu/commit-undo-transaction))))))
on-delete on-delete
(mf/use-callback (mf/use-callback
@ -195,7 +196,7 @@
(mf/deps components selected-components on-clear-selection) (mf/deps components selected-components on-clear-selection)
(fn [name] (fn [name]
(on-clear-selection) (on-clear-selection)
(st/emit! (dwc/start-undo-transaction)) (st/emit! (dwu/start-undo-transaction))
(apply st/emit! (apply st/emit!
(->> components (->> components
(filter #(contains? selected-components (:id %))) (filter #(contains? selected-components (:id %)))
@ -203,7 +204,7 @@
(:id %) (:id %)
(str name " / " (str name " / "
(cp/merge-path-item (:path %) (:name %))))))) (cp/merge-path-item (:path %) (:name %)))))))
(st/emit! (dwc/commit-undo-transaction)))) (st/emit! (dwu/commit-undo-transaction))))
on-fold-group on-fold-group
(mf/use-callback (mf/use-callback
@ -383,7 +384,7 @@
(mf/deps objects selected-objects on-clear-selection) (mf/deps objects selected-objects on-clear-selection)
(fn [name] (fn [name]
(on-clear-selection) (on-clear-selection)
(st/emit! (dwc/start-undo-transaction)) (st/emit! (dwu/start-undo-transaction))
(apply st/emit! (apply st/emit!
(->> objects (->> objects
(filter #(contains? selected-objects (:id %))) (filter #(contains? selected-objects (:id %)))
@ -391,7 +392,7 @@
(:id %) (:id %)
(str name " / " (str name " / "
(cp/merge-path-item (:path %) (:name %))))))) (cp/merge-path-item (:path %) (:name %)))))))
(st/emit! (dwc/commit-undo-transaction)))) (st/emit! (dwu/commit-undo-transaction))))
on-fold-group on-fold-group
(mf/use-callback (mf/use-callback
@ -975,7 +976,7 @@
(mf/deps @selected-assets) (mf/deps @selected-assets)
(fn [] (fn []
(do (do
(st/emit! (dwc/start-undo-transaction)) (st/emit! (dwu/start-undo-transaction))
(apply st/emit! (map #(dwl/delete-component {:id %}) (apply st/emit! (map #(dwl/delete-component {:id %})
(:components @selected-assets))) (:components @selected-assets)))
(apply st/emit! (map #(dwl/delete-media {:id %}) (apply st/emit! (map #(dwl/delete-media {:id %})
@ -984,7 +985,7 @@
(:colors @selected-assets))) (:colors @selected-assets)))
(apply st/emit! (map #(dwl/delete-typography %) (apply st/emit! (map #(dwl/delete-typography %)
(:typographies @selected-assets))) (:typographies @selected-assets)))
(st/emit! (dwc/commit-undo-transaction)))))] (st/emit! (dwu/commit-undo-transaction)))))]
[:div.tool-window {:on-context-menu #(dom/prevent-default %) [:div.tool-window {:on-context-menu #(dom/prevent-default %)
:on-click unselect-all} :on-click unselect-all}

View file

@ -10,6 +10,7 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.changes :as dch]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.workspace.sidebar.options.common :refer [advanced-options]] [app.main.ui.workspace.sidebar.options.common :refer [advanced-options]]
@ -32,7 +33,7 @@
has-value? (not (nil? blur)) has-value? (not (nil? blur))
multiple? (= blur :multiple) multiple? (= blur :multiple)
change! (fn [update-fn] (st/emit! (dwc/update-shapes ids update-fn))) change! (fn [update-fn] (st/emit! (dch/update-shapes ids update-fn)))
handle-add handle-add
(fn [] (fn []

View file

@ -16,6 +16,7 @@
[app.main.ui.components.context-menu :refer [context-menu]] [app.main.ui.components.context-menu :refer [context-menu]]
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.undo :as dwu]
[app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.libraries :as dwl]
[app.util.i18n :as i18n :refer [t]] [app.util.i18n :as i18n :refer [t]]
[app.util.dom :as dom])) [app.util.dom :as dom]))
@ -50,10 +51,10 @@
do-detach-component (st/emitf (dwl/detach-component id)) do-detach-component (st/emitf (dwl/detach-component id))
do-reset-component (st/emitf (dwl/reset-component id)) do-reset-component (st/emitf (dwl/reset-component id))
do-update-component (st/emitf do-update-component (st/emitf
(dwc/start-undo-transaction) (dwu/start-undo-transaction)
(dwl/update-component id) (dwl/update-component id)
(dwl/sync-file current-file-id current-file-id) (dwl/sync-file current-file-id current-file-id)
(dwc/commit-undo-transaction)) (dwu/commit-undo-transaction))
confirm-update-remote-component (st/emitf confirm-update-remote-component (st/emitf
(dwl/update-component id) (dwl/update-component id)
(dwl/sync-file current-file-id (dwl/sync-file current-file-id

View file

@ -9,6 +9,7 @@
[app.common.pages :as cp] [app.common.pages :as cp]
[app.main.data.workspace.colors :as dc] [app.main.data.workspace.colors :as dc]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.undo :as dwu]
[app.main.data.workspace.texts :as dwt] [app.main.data.workspace.texts :as dwt]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.store :as st] [app.main.store :as st]
@ -78,13 +79,13 @@
(mf/use-callback (mf/use-callback
(mf/deps ids) (mf/deps ids)
(fn [value opacity id file-id] (fn [value opacity id file-id]
(st/emit! (dwc/start-undo-transaction)))) (st/emit! (dwu/start-undo-transaction))))
on-close-picker on-close-picker
(mf/use-callback (mf/use-callback
(mf/deps ids) (mf/deps ids)
(fn [value opacity id file-id] (fn [value opacity id file-id]
(st/emit! (dwc/commit-undo-transaction))))] (st/emit! (dwu/commit-undo-transaction))))]
(if show? (if show?
[:div.element-set [:div.element-set

View file

@ -9,6 +9,7 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.math :as mth] [app.common.math :as mth]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.changes :as dch]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.numeric-input :refer [numeric-input]] [app.main.ui.components.numeric-input :refer [numeric-input]]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
@ -34,7 +35,7 @@
(mf/use-callback (mf/use-callback
(mf/deps ids) (mf/deps ids)
(fn [prop value] (fn [prop value]
(st/emit! (dwc/update-shapes ids #(assoc % prop value))))) (st/emit! (dch/update-shapes ids #(assoc % prop value)))))
handle-change-blend-mode handle-change-blend-mode
(mf/use-callback (mf/use-callback

View file

@ -17,6 +17,7 @@
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.main.data.workspace :as udw] [app.main.data.workspace :as udw]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.changes :as dch]
[app.main.ui.components.numeric-input :refer [numeric-input]] [app.main.ui.components.numeric-input :refer [numeric-input]]
[app.common.math :as math] [app.common.math :as math]
[app.util.i18n :refer [t] :as i18n])) [app.util.i18n :refer [t] :as i18n]))
@ -106,7 +107,7 @@
(:r1 shape) (:r1 shape)
(-> (assoc :rx 0 :ry 0) (-> (assoc :rx 0 :ry 0)
(dissoc :r1 :r2 :r3 :r4))))] (dissoc :r1 :r2 :r3 :r4))))]
(st/emit! (dwc/update-shapes ids-with-children radius-update))))) (st/emit! (dch/update-shapes ids-with-children radius-update)))))
on-switch-to-radius-4 on-switch-to-radius-4
(mf/use-callback (mf/use-callback
@ -118,7 +119,7 @@
(:rx shape) (:rx shape)
(-> (assoc :r1 0 :r2 0 :r3 0 :r4 0) (-> (assoc :r1 0 :r2 0 :r3 0 :r4 0)
(dissoc :rx :ry))))] (dissoc :rx :ry))))]
(st/emit! (dwc/update-shapes ids-with-children radius-update))))) (st/emit! (dch/update-shapes ids-with-children radius-update)))))
on-radius-1-change on-radius-1-change
(mf/use-callback (mf/use-callback
@ -134,7 +135,7 @@
(or (:rx shape) (:r1 shape)) (or (:rx shape) (:r1 shape))
(assoc :rx value :ry value)))] (assoc :rx value :ry value)))]
(st/emit! (dwc/update-shapes ids-with-children radius-update))))) (st/emit! (dch/update-shapes ids-with-children radius-update)))))
on-radius-4-change on-radius-4-change
(mf/use-callback (mf/use-callback
@ -150,7 +151,7 @@
(attr shape) (attr shape)
(assoc attr value)))] (assoc attr value)))]
(st/emit! (dwc/update-shapes ids-with-children radius-update))))) (st/emit! (dch/update-shapes ids-with-children radius-update)))))
on-width-change #(on-size-change % :width) on-width-change #(on-size-change % :width)
on-height-change #(on-size-change % :height) on-height-change #(on-size-change % :height)

View file

@ -10,6 +10,8 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.undo :as dwu]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.components.numeric-input :refer [numeric-input]] [app.main.ui.components.numeric-input :refer [numeric-input]]
@ -56,7 +58,7 @@
on-remove-shadow on-remove-shadow
(fn [index] (fn [index]
(fn [] (fn []
(st/emit! (dwc/update-shapes ids #(update % :shadow remove-shadow-by-index index) )))) (st/emit! (dch/update-shapes ids #(update % :shadow remove-shadow-by-index index) ))))
select-text select-text
(fn [ref] (fn [event] (dom/select-text! (mf/ref-val ref)))) (fn [ref] (fn [event] (dom/select-text! (mf/ref-val ref))))
@ -69,14 +71,14 @@
([index attr valid? update-ref] ([index attr valid? update-ref]
(fn [value] (fn [value]
(when (or (not valid?) (valid? value)) (when (or (not valid?) (valid? value))
(do (st/emit! (dwc/update-shapes ids #(assoc-in % [:shadow index attr] value))) (do (st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index attr] value)))
(when update-ref (dom/set-value! (mf/ref-val update-ref) value))))))) (when update-ref (dom/set-value! (mf/ref-val update-ref) value)))))))
update-color update-color
(fn [index] (fn [index]
(fn [color opacity] (fn [color opacity]
(let [color (d/without-keys color [:id :file-id :gradient])] (let [color (d/without-keys color [:id :file-id :gradient])]
(st/emit! (dwc/update-shapes (st/emit! (dch/update-shapes
ids ids
#(-> % #(-> %
(assoc-in [:shadow index :color] color) (assoc-in [:shadow index :color] color)
@ -86,7 +88,7 @@
(fn [index] (fn [index]
(fn [color opacity] (fn [color opacity]
(if-not (string? (:color value)) (if-not (string? (:color value))
(st/emit! (dwc/update-shapes (st/emit! (dch/update-shapes
ids ids
#(assoc-in % [:shadow index :color] #(assoc-in % [:shadow index :color]
(dissoc (:color value) :id :file-id))))))) (dissoc (:color value) :id :file-id)))))))
@ -94,7 +96,7 @@
toggle-visibility toggle-visibility
(fn [index] (fn [index]
(fn [] (fn []
(st/emit! (dwc/update-shapes ids #(update-in % [:shadow index :hidden] not)))))] (st/emit! (dch/update-shapes ids #(update-in % [:shadow index :hidden] not)))))]
[:* [:*
[:div.element-set-options-group [:div.element-set-options-group
@ -129,7 +131,7 @@
{:default-value (str (:style value)) {:default-value (str (:style value))
:on-change (fn [event] :on-change (fn [event]
(let [value (-> event dom/get-target dom/get-value d/read-string)] (let [value (-> event dom/get-target dom/get-value d/read-string)]
(st/emit! (dwc/update-shapes ids #(assoc-in % [:shadow index :style] value)))))} (st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index :style] value)))))}
[:option {:value ":drop-shadow"} (t locale "workspace.options.shadow-options.drop-shadow")] [:option {:value ":drop-shadow"} (t locale "workspace.options.shadow-options.drop-shadow")]
[:option {:value ":inner-shadow"} (t locale "workspace.options.shadow-options.inner-shadow")]]] [:option {:value ":inner-shadow"} (t locale "workspace.options.shadow-options.inner-shadow")]]]
@ -181,18 +183,18 @@
:disable-gradient true :disable-gradient true
:on-change (update-color index) :on-change (update-color index)
:on-detach (detach-color index) :on-detach (detach-color index)
:on-open #(st/emit! (dwc/start-undo-transaction)) :on-open #(st/emit! (dwu/start-undo-transaction))
:on-close #(st/emit! (dwc/commit-undo-transaction))}]]]])) :on-close #(st/emit! (dwu/commit-undo-transaction))}]]]]))
(mf/defc shadow-menu (mf/defc shadow-menu
[{:keys [ids type values] :as props}] [{:keys [ids type values] :as props}]
(let [locale (i18n/use-locale) (let [locale (i18n/use-locale)
on-remove-all-shadows on-remove-all-shadows
(fn [event] (fn [event]
(st/emit! (dwc/update-shapes ids #(dissoc % :shadow) ))) (st/emit! (dch/update-shapes ids #(dissoc % :shadow) )))
on-add-shadow on-add-shadow
(fn [] (fn []
(st/emit! (dwc/update-shapes ids #(update % :shadow (fnil conj []) (create-shadow)) )))] (st/emit! (dch/update-shapes ids #(update % :shadow (fnil conj []) (create-shadow)) )))]
[:div.element-set.shadow-options [:div.element-set.shadow-options
[:div.element-set-title [:div.element-set-title
[:span [:span

View file

@ -11,6 +11,8 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.math :as math] [app.common.math :as math]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.undo :as dwu]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.colors :as dc] [app.main.data.workspace.colors :as dc]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
@ -78,7 +80,7 @@
(let [value (-> (dom/get-target event) (let [value (-> (dom/get-target event)
(dom/get-value) (dom/get-value)
(d/read-string))] (d/read-string))]
(st/emit! (dwc/update-shapes ids #(assoc % :stroke-style value))))) (st/emit! (dch/update-shapes ids #(assoc % :stroke-style value)))))
on-stroke-alignment-change on-stroke-alignment-change
(fn [event] (fn [event]
@ -86,7 +88,7 @@
(dom/get-value) (dom/get-value)
(d/read-string))] (d/read-string))]
(when-not (str/empty? value) (when-not (str/empty? value)
(st/emit! (dwc/update-shapes ids #(assoc % :stroke-alignment value)))))) (st/emit! (dch/update-shapes ids #(assoc % :stroke-alignment value))))))
on-stroke-width-change on-stroke-width-change
(fn [event] (fn [event]
@ -94,11 +96,11 @@
(dom/get-value) (dom/get-value)
(d/parse-integer 0))] (d/parse-integer 0))]
(when-not (str/empty? value) (when-not (str/empty? value)
(st/emit! (dwc/update-shapes ids #(assoc % :stroke-width value)))))) (st/emit! (dch/update-shapes ids #(assoc % :stroke-width value))))))
on-add-stroke on-add-stroke
(fn [event] (fn [event]
(st/emit! (dwc/update-shapes ids #(assoc % (st/emit! (dch/update-shapes ids #(assoc %
:stroke-style :solid :stroke-style :solid
:stroke-color "#000000" :stroke-color "#000000"
:stroke-opacity 1 :stroke-opacity 1
@ -106,19 +108,19 @@
on-del-stroke on-del-stroke
(fn [event] (fn [event]
(st/emit! (dwc/update-shapes ids #(assoc % :stroke-style :none)))) (st/emit! (dch/update-shapes ids #(assoc % :stroke-style :none))))
on-open-picker on-open-picker
(mf/use-callback (mf/use-callback
(mf/deps ids) (mf/deps ids)
(fn [value opacity id file-id] (fn [value opacity id file-id]
(st/emit! (dwc/start-undo-transaction)))) (st/emit! (dwu/start-undo-transaction))))
on-close-picker on-close-picker
(mf/use-callback (mf/use-callback
(mf/deps ids) (mf/deps ids)
(fn [value opacity id file-id] (fn [value opacity id file-id]
(st/emit! (dwc/commit-undo-transaction))))] (st/emit! (dwu/commit-undo-transaction))))]
(if show-options (if show-options
[:div.element-set [:div.element-set

View file

@ -9,6 +9,7 @@
[cuerdas.core :as str] [cuerdas.core :as str]
[app.common.data :as d] [app.common.data :as d]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.changes :as dch]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]] [app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]]
[app.util.dom :as dom] [app.util.dom :as dom]
@ -61,7 +62,7 @@
(fn [attr value] (fn [attr value]
(let [update-fn (let [update-fn
(fn [shape] (assoc-in shape (concat [:svg-attrs] attr) value))] (fn [shape] (assoc-in shape (concat [:svg-attrs] attr) value))]
(st/emit! (dwc/update-shapes ids update-fn))))) (st/emit! (dch/update-shapes ids update-fn)))))
handle-delete handle-delete
(mf/use-callback (mf/use-callback
@ -76,7 +77,7 @@
(empty? (get-in shape [:svg-attrs :style])) (empty? (get-in shape [:svg-attrs :style]))
(update :svg-attrs dissoc :style))] (update :svg-attrs dissoc :style))]
shape))] shape))]
(st/emit! (dwc/update-shapes ids update-fn))))) (st/emit! (dch/update-shapes ids update-fn)))))
] ]

View file

@ -10,6 +10,7 @@
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.common.text :as txt] [app.common.text :as txt]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.texts :as dwt] [app.main.data.workspace.texts :as dwt]
[app.main.fonts :as fonts] [app.main.fonts :as fonts]
@ -159,7 +160,7 @@
grow-type (->> values :grow-type) grow-type (->> values :grow-type)
handle-change-grow handle-change-grow
(fn [event grow-type] (fn [event grow-type]
(st/emit! (dwc/update-shapes ids #(assoc % :grow-type grow-type))))] (st/emit! (dch/update-shapes ids #(assoc % :grow-type grow-type))))]
[:div.align-icons [:div.align-icons
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom

View file

@ -13,6 +13,7 @@
[app.main.store :as st] [app.main.store :as st]
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.undo :as dwu]
[app.util.i18n :as i18n :refer [t]] [app.util.i18n :as i18n :refer [t]]
[app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]])) [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]]))
@ -31,12 +32,12 @@
on-open on-open
(mf/use-callback (mf/use-callback
(mf/deps page-id) (mf/deps page-id)
#(st/emit! (dwc/start-undo-transaction))) #(st/emit! (dwu/start-undo-transaction)))
on-close on-close
(mf/use-callback (mf/use-callback
(mf/deps page-id) (mf/deps page-id)
#(st/emit! (dwc/commit-undo-transaction)))] #(st/emit! (dwu/commit-undo-transaction)))]
[:div.element-set [:div.element-set
[:div.element-set-title (t locale "workspace.options.canvas-background")] [:div.element-set-title (t locale "workspace.options.canvas-background")]