mirror of
https://github.com/penpot/penpot.git
synced 2025-05-04 01:05:53 +02:00
♻️ Refactor persistence layer
This commit is contained in:
parent
d679001955
commit
6436ef334b
62 changed files with 1030 additions and 1070 deletions
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
(def registry (atom {}))
|
(def registry (atom {}))
|
||||||
|
|
||||||
|
|
||||||
(defn potok-reify
|
(defn potok-reify
|
||||||
[{:keys [:node :filename] :as params}]
|
[{:keys [:node :filename] :as params}]
|
||||||
(let [[rnode rtype & other] (:children node)
|
(let [[rnode rtype & other] (:children node)
|
||||||
|
|
|
@ -9,9 +9,11 @@
|
||||||
### :heart: Community contributions (Thank you!)
|
### :heart: Community contributions (Thank you!)
|
||||||
|
|
||||||
### :sparkles: New features
|
### :sparkles: New features
|
||||||
- Improve auth process [Taiga #Change Auth Process](https://tree.taiga.io/project/penpot/us/7094)
|
|
||||||
- Add locking degrees increment (hold shift) on path edition [Taiga #7761](https://tree.taiga.io/project/penpot/issue/7761)
|
- Improve auth process [Taiga #7094](https://tree.taiga.io/project/penpot/us/7094)
|
||||||
- Allow library colors as recent colors [Taiga issue #7640](https://tree.taiga.io/project/penpot/issue/7640)
|
- Add locking degrees increment (hold shift) on path edition [Taiga Issue #7761](https://tree.taiga.io/project/penpot/issue/7761)
|
||||||
|
- Persistence & Concurrent Edition Enhancements [Taiga #5657](https://tree.taiga.io/project/penpot/us/5657)
|
||||||
|
- Allow library colors as recent colors [Taiga Issue #7640](https://tree.taiga.io/project/penpot/issue/7640)
|
||||||
|
|
||||||
### :bug: Bugs fixed
|
### :bug: Bugs fixed
|
||||||
|
|
||||||
|
|
|
@ -262,8 +262,8 @@
|
||||||
;; Send asynchronous notifications
|
;; Send asynchronous notifications
|
||||||
(send-notifications! cfg params)
|
(send-notifications! cfg params)
|
||||||
|
|
||||||
;; Retrieve and return lagged data
|
{:revn (:revn file)
|
||||||
(get-lagged-changes conn params))))
|
:lagged (get-lagged-changes conn params)})))
|
||||||
|
|
||||||
(defn- soft-validate-file-schema!
|
(defn- soft-validate-file-schema!
|
||||||
[file]
|
[file]
|
||||||
|
|
166
frontend/src/app/main/data/changes.cljs
Normal file
166
frontend/src/app/main/data/changes.cljs
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
;; 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.main.data.changes
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.common.files.changes :as cpc]
|
||||||
|
[app.common.logging :as log]
|
||||||
|
[app.common.types.shape-tree :as ctst]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
|
[app.main.features :as features]
|
||||||
|
[app.main.worker :as uw]
|
||||||
|
[app.util.time :as dt]
|
||||||
|
[beicon.v2.core :as rx]
|
||||||
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
|
;; Change this to :info :debug or :trace to debug this module
|
||||||
|
(log/set-level! :debug)
|
||||||
|
|
||||||
|
(def page-change?
|
||||||
|
#{:add-page :mod-page :del-page :mov-page})
|
||||||
|
(def update-layout-attr?
|
||||||
|
#{:hidden})
|
||||||
|
|
||||||
|
(def commit?
|
||||||
|
(ptk/type? ::commit))
|
||||||
|
|
||||||
|
(defn update-indexes
|
||||||
|
"Given a commit, send the changes to the worker for updating the
|
||||||
|
indexes."
|
||||||
|
[{:keys [changes] :as commit}]
|
||||||
|
(ptk/reify ::update-indexes
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ _ _]
|
||||||
|
(let [changes (->> changes
|
||||||
|
(map (fn [{:keys [id type page] :as change}]
|
||||||
|
(cond-> change
|
||||||
|
(and (page-change? type) (nil? (:page-id change)))
|
||||||
|
(assoc :page-id (or id (:id page))))))
|
||||||
|
(filter :page-id)
|
||||||
|
(group-by :page-id))]
|
||||||
|
|
||||||
|
(->> (rx/from changes)
|
||||||
|
(rx/merge-map (fn [[page-id changes]]
|
||||||
|
(log/debug :hint "update-indexes" :page-id page-id :changes (count changes))
|
||||||
|
(uw/ask! {:cmd :update-page-index
|
||||||
|
:page-id page-id
|
||||||
|
:changes changes})))
|
||||||
|
(rx/ignore))))))
|
||||||
|
|
||||||
|
(defn- get-pending-commits
|
||||||
|
[{:keys [persistence]}]
|
||||||
|
(->> (:queue persistence)
|
||||||
|
(map (d/getf (:index persistence)))
|
||||||
|
(not-empty)))
|
||||||
|
|
||||||
|
(defn commit
|
||||||
|
"Create a commit event instance"
|
||||||
|
[{:keys [commit-id redo-changes undo-changes origin save-undo? features
|
||||||
|
file-id file-revn undo-group tags stack-undo? source]}]
|
||||||
|
|
||||||
|
(dm/assert!
|
||||||
|
"expect valid vector of changes"
|
||||||
|
(and (cpc/check-changes! redo-changes)
|
||||||
|
(cpc/check-changes! undo-changes)))
|
||||||
|
|
||||||
|
(let [commit-id (or commit-id (uuid/next))
|
||||||
|
commit {:id commit-id
|
||||||
|
:created-at (dt/now)
|
||||||
|
:source (d/nilv source :local)
|
||||||
|
:origin (ptk/type origin)
|
||||||
|
:features features
|
||||||
|
:file-id file-id
|
||||||
|
:file-revn file-revn
|
||||||
|
:changes redo-changes
|
||||||
|
:redo-changes redo-changes
|
||||||
|
:undo-changes undo-changes
|
||||||
|
:save-undo? save-undo?
|
||||||
|
:undo-group undo-group
|
||||||
|
:tags tags
|
||||||
|
:stack-undo? stack-undo?}]
|
||||||
|
|
||||||
|
(ptk/reify ::commit
|
||||||
|
cljs.core/IDeref
|
||||||
|
(-deref [_] commit)
|
||||||
|
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(let [current-file-id (get state :current-file-id)
|
||||||
|
path (if (= file-id current-file-id)
|
||||||
|
[:workspace-data]
|
||||||
|
[:workspace-libraries file-id :data])
|
||||||
|
|
||||||
|
not-local? (not= source :local)
|
||||||
|
pending (if not-local?
|
||||||
|
(get-pending-commits state)
|
||||||
|
nil)
|
||||||
|
|
||||||
|
undo-changes (if pending
|
||||||
|
(->> pending
|
||||||
|
(map :undo-changes)
|
||||||
|
(reverse)
|
||||||
|
(mapcat identity)
|
||||||
|
(vec))
|
||||||
|
nil)
|
||||||
|
|
||||||
|
redo-changes (if pending
|
||||||
|
(into redo-changes
|
||||||
|
(comp
|
||||||
|
(map :redo-changes)
|
||||||
|
(mapcat identity))
|
||||||
|
pending)
|
||||||
|
redo-changes)]
|
||||||
|
|
||||||
|
(d/update-in-when state path
|
||||||
|
(fn [file]
|
||||||
|
(let [file (cpc/process-changes file undo-changes false)
|
||||||
|
file (cpc/process-changes file redo-changes false)
|
||||||
|
pids (into #{} (map :page-id) redo-changes)]
|
||||||
|
(reduce #(ctst/update-object-indices %1 %2) file pids)))))))))
|
||||||
|
|
||||||
|
(defn- resolve-file-revn
|
||||||
|
[state file-id]
|
||||||
|
(let [file (:workspace-file state)]
|
||||||
|
(if (= (:id file) file-id)
|
||||||
|
(:revn file)
|
||||||
|
(dm/get-in state [:workspace-libraries file-id :revn]))))
|
||||||
|
|
||||||
|
(defn commit-changes
|
||||||
|
"Schedules a list of changes to execute now, and add the corresponding undo changes to
|
||||||
|
the undo stack.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
- save-undo?: if set to false, do not add undo changes.
|
||||||
|
- undo-group: if some consecutive changes (or even transactions) share the same
|
||||||
|
undo-group, they will be undone or redone in a single step
|
||||||
|
"
|
||||||
|
[{:keys [redo-changes undo-changes save-undo? undo-group tags stack-undo? file-id]
|
||||||
|
:or {save-undo? true
|
||||||
|
stack-undo? false
|
||||||
|
undo-group (uuid/next)
|
||||||
|
tags #{}}
|
||||||
|
:as params}]
|
||||||
|
(ptk/reify ::commit-changes
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(let [file-id (or file-id (:current-file-id state))
|
||||||
|
uchg (vec undo-changes)
|
||||||
|
rchg (vec redo-changes)
|
||||||
|
features (features/get-team-enabled-features state)]
|
||||||
|
|
||||||
|
(rx/of (-> params
|
||||||
|
(assoc :undo-group undo-group)
|
||||||
|
(assoc :features features)
|
||||||
|
(assoc :tags tags)
|
||||||
|
(assoc :stack-undo? stack-undo?)
|
||||||
|
(assoc :save-undo? save-undo?)
|
||||||
|
(assoc :file-id file-id)
|
||||||
|
(assoc :file-revn (resolve-file-revn state file-id))
|
||||||
|
(assoc :undo-changes uchg)
|
||||||
|
(assoc :redo-changes rchg)
|
||||||
|
(commit)))))))
|
|
@ -8,7 +8,7 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.workspace.persistence :as dwp]
|
[app.main.data.persistence :as dwp]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
|
|
230
frontend/src/app/main/data/persistence.cljs
Normal file
230
frontend/src/app/main/data/persistence.cljs
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
;; 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.main.data.persistence
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.common.logging :as log]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
|
[app.main.data.changes :as dch]
|
||||||
|
[app.main.repo :as rp]
|
||||||
|
[app.util.router :as rt]
|
||||||
|
[beicon.v2.core :as rx]
|
||||||
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
|
(declare ^:private run-persistence-task)
|
||||||
|
|
||||||
|
(log/set-level! :warn)
|
||||||
|
|
||||||
|
(def running (atom false))
|
||||||
|
(def revn-data (atom {}))
|
||||||
|
(def queue-conj (fnil conj #queue []))
|
||||||
|
|
||||||
|
(defn- update-status
|
||||||
|
[status]
|
||||||
|
(ptk/reify ::update-status
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(update state :persistence (fn [pstate]
|
||||||
|
(log/trc :hint "update-status"
|
||||||
|
:from (:status pstate)
|
||||||
|
:to status)
|
||||||
|
(let [status (if (and (= status :pending)
|
||||||
|
(= (:status pstate) :saving))
|
||||||
|
(:status pstate)
|
||||||
|
status)]
|
||||||
|
|
||||||
|
(-> (assoc pstate :status status)
|
||||||
|
(cond-> (= status :error)
|
||||||
|
(dissoc :run-id))
|
||||||
|
(cond-> (= status :saved)
|
||||||
|
(dissoc :run-id)))))))))
|
||||||
|
|
||||||
|
(defn- update-file-revn
|
||||||
|
[file-id revn]
|
||||||
|
(ptk/reify ::update-file-revn
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(log/dbg :hint "update-file-revn" :file-id (dm/str file-id) :revn revn)
|
||||||
|
(if-let [current-file-id (:current-file-id state)]
|
||||||
|
(if (= file-id current-file-id)
|
||||||
|
(update-in state [:workspace-file :revn] max revn)
|
||||||
|
(d/update-in-when state [:workspace-libraries file-id :revn] max revn))
|
||||||
|
state))
|
||||||
|
|
||||||
|
ptk/EffectEvent
|
||||||
|
(effect [_ _ _]
|
||||||
|
(swap! revn-data update file-id (fnil max 0) revn))))
|
||||||
|
|
||||||
|
(defn- discard-commit
|
||||||
|
[commit-id]
|
||||||
|
(ptk/reify ::discard-commit
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(update state :persistence (fn [pstate]
|
||||||
|
(-> pstate
|
||||||
|
(update :queue (fn [queue]
|
||||||
|
(if (= commit-id (peek queue))
|
||||||
|
(pop queue)
|
||||||
|
(throw (ex-info "invalid state" {})))))
|
||||||
|
(update :index dissoc commit-id)))))))
|
||||||
|
|
||||||
|
(defn- append-commit
|
||||||
|
"Event used internally to append the current change to the
|
||||||
|
persistence queue."
|
||||||
|
[{:keys [id] :as commit}]
|
||||||
|
(let [run-id (uuid/next)]
|
||||||
|
(ptk/reify ::append-commit
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(log/trc :hint "append-commit" :method "update" :commit-id (dm/str id))
|
||||||
|
(update state :persistence
|
||||||
|
(fn [pstate]
|
||||||
|
(-> pstate
|
||||||
|
(update :run-id d/nilv run-id)
|
||||||
|
(update :queue queue-conj id)
|
||||||
|
(update :index assoc id commit)))))
|
||||||
|
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(let [pstate (:persistence state)]
|
||||||
|
(when (= run-id (:run-id pstate))
|
||||||
|
(rx/of (run-persistence-task)
|
||||||
|
(update-status :saving))))))))
|
||||||
|
|
||||||
|
(defn- persist-commit
|
||||||
|
[commit-id]
|
||||||
|
(ptk/reify ::persist-commit
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(log/dbg :hint "persist-commit" :commit-id (dm/str commit-id))
|
||||||
|
(when-let [{:keys [file-id file-revn changes features] :as commit} (dm/get-in state [:persistence :index commit-id])]
|
||||||
|
(let [sid (:session-id state)
|
||||||
|
revn (max file-revn (get @revn-data file-id 0))
|
||||||
|
params {:id file-id
|
||||||
|
:revn revn
|
||||||
|
:session-id sid
|
||||||
|
:origin (:origin commit)
|
||||||
|
:created-at (:created-at commit)
|
||||||
|
:commit-id commit-id
|
||||||
|
:changes (vec changes)
|
||||||
|
:features features}]
|
||||||
|
|
||||||
|
;; FIXME: handle lagged here !!!!
|
||||||
|
(->> (rp/cmd! :update-file params)
|
||||||
|
(rx/mapcat (fn [{:keys [revn lagged] :as response}]
|
||||||
|
(log/debug :hint "changes persisted" :commit-id (dm/str commit-id) :lagged (count lagged))
|
||||||
|
(rx/of (ptk/data-event ::commit-persisted commit)
|
||||||
|
(update-file-revn file-id revn))))
|
||||||
|
|
||||||
|
(rx/catch (fn [cause]
|
||||||
|
(rx/concat
|
||||||
|
(if (= :authentication (:type cause))
|
||||||
|
(rx/empty)
|
||||||
|
(rx/of (rt/assign-exception cause)
|
||||||
|
(ptk/data-event ::error cause)
|
||||||
|
(update-status :error)))
|
||||||
|
(rx/throw cause))))))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn- run-persistence-task
|
||||||
|
[]
|
||||||
|
(ptk/reify ::run-persistence-task
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [queue (-> state :persistence :queue)]
|
||||||
|
(if-let [commit-id (peek queue)]
|
||||||
|
(let [stoper-s (rx/merge
|
||||||
|
(rx/filter (ptk/type? ::run-persistence-task) stream)
|
||||||
|
(rx/filter (ptk/type? ::error) stream))]
|
||||||
|
|
||||||
|
(log/dbg :hint "run-persistence-task" :commit-id (dm/str commit-id))
|
||||||
|
(->> (rx/merge
|
||||||
|
(rx/of (persist-commit commit-id))
|
||||||
|
(->> stream
|
||||||
|
(rx/filter (ptk/type? ::commit-persisted))
|
||||||
|
(rx/map deref)
|
||||||
|
(rx/filter #(= commit-id (:id %)))
|
||||||
|
(rx/take 1)
|
||||||
|
(rx/mapcat (fn [_]
|
||||||
|
(rx/of (discard-commit commit-id)
|
||||||
|
(run-persistence-task))))))
|
||||||
|
(rx/take-until stoper-s)))
|
||||||
|
(rx/of (update-status :saved)))))))
|
||||||
|
|
||||||
|
(def ^:private xf-mapcat-undo
|
||||||
|
(mapcat :undo-changes))
|
||||||
|
|
||||||
|
(def ^:private xf-mapcat-redo
|
||||||
|
(mapcat :redo-changes))
|
||||||
|
|
||||||
|
(defn- merge-commit
|
||||||
|
[buffer]
|
||||||
|
(->> (rx/from (group-by :file-id buffer))
|
||||||
|
(rx/map (fn [[_ [item :as commits]]]
|
||||||
|
(let [uchg (into [] xf-mapcat-undo commits)
|
||||||
|
rchg (into [] xf-mapcat-redo commits)]
|
||||||
|
(-> item
|
||||||
|
(assoc :undo-changes uchg)
|
||||||
|
(assoc :redo-changes rchg)
|
||||||
|
(assoc :changes rchg)))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn initialize-persistence
|
||||||
|
[]
|
||||||
|
(ptk/reify ::initialize-persistence
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ _ stream]
|
||||||
|
(log/debug :hint "initialize persistence")
|
||||||
|
(let [stoper-s (rx/filter (ptk/type? ::initialize-persistence) stream)
|
||||||
|
|
||||||
|
commits-s
|
||||||
|
(->> stream
|
||||||
|
(rx/filter dch/commit?)
|
||||||
|
(rx/map deref)
|
||||||
|
(rx/filter #(= :local (:source %)))
|
||||||
|
(rx/filter (complement empty?))
|
||||||
|
(rx/share))
|
||||||
|
|
||||||
|
notifier-s
|
||||||
|
(rx/merge
|
||||||
|
(->> commits-s
|
||||||
|
(rx/debounce 3000)
|
||||||
|
(rx/tap #(log/trc :hint "persistence beat")))
|
||||||
|
(->> stream
|
||||||
|
(rx/filter #(= % ::force-persist))))]
|
||||||
|
|
||||||
|
(rx/merge
|
||||||
|
(->> commits-s
|
||||||
|
(rx/debounce 200)
|
||||||
|
(rx/map (fn [_]
|
||||||
|
(update-status :pending)))
|
||||||
|
(rx/take-until stoper-s))
|
||||||
|
|
||||||
|
;; Here we watch for local commits, buffer them in a small
|
||||||
|
;; chunks (very near in time commits) and append them to the
|
||||||
|
;; persistence queue
|
||||||
|
(->> commits-s
|
||||||
|
(rx/buffer-until notifier-s)
|
||||||
|
(rx/mapcat merge-commit)
|
||||||
|
(rx/mapcat (fn [commit]
|
||||||
|
(rx/of (append-commit commit)
|
||||||
|
(dch/update-indexes commit))))
|
||||||
|
(rx/take-until (rx/delay 100 stoper-s))
|
||||||
|
(rx/finalize (fn []
|
||||||
|
(log/debug :hint "finalize persistence: changes watcher"))))
|
||||||
|
|
||||||
|
;; Here we track all incoming remote commits for maintain
|
||||||
|
;; updated the local state with the file revn
|
||||||
|
(->> stream
|
||||||
|
(rx/filter dch/commit?)
|
||||||
|
(rx/map deref)
|
||||||
|
(rx/filter #(= :remote (:source %)))
|
||||||
|
(rx/mapcat (fn [{:keys [file-id file-revn] :as commit}]
|
||||||
|
(rx/of (update-file-revn file-id file-revn)
|
||||||
|
(dch/update-indexes commit))))
|
||||||
|
(rx/take-until stoper-s)))))))
|
|
@ -19,6 +19,7 @@
|
||||||
[app.common.geom.rect :as grc]
|
[app.common.geom.rect :as grc]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.common.geom.shapes.grid-layout :as gslg]
|
[app.common.geom.shapes.grid-layout :as gslg]
|
||||||
|
[app.common.logging :as log]
|
||||||
[app.common.logic.libraries :as cll]
|
[app.common.logic.libraries :as cll]
|
||||||
[app.common.logic.shapes :as cls]
|
[app.common.logic.shapes :as cls]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
@ -34,14 +35,15 @@
|
||||||
[app.common.types.typography :as ctt]
|
[app.common.types.typography :as ctt]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.comments :as dcm]
|
[app.main.data.comments :as dcm]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
[app.main.data.fonts :as df]
|
[app.main.data.fonts :as df]
|
||||||
[app.main.data.messages :as msg]
|
[app.main.data.messages :as msg]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
|
[app.main.data.persistence :as dps]
|
||||||
[app.main.data.users :as du]
|
[app.main.data.users :as du]
|
||||||
[app.main.data.workspace.bool :as dwb]
|
[app.main.data.workspace.bool :as dwb]
|
||||||
[app.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.collapse :as dwco]
|
[app.main.data.workspace.collapse :as dwco]
|
||||||
[app.main.data.workspace.drawing :as dwd]
|
[app.main.data.workspace.drawing :as dwd]
|
||||||
[app.main.data.workspace.edition :as dwe]
|
[app.main.data.workspace.edition :as dwe]
|
||||||
|
@ -59,7 +61,6 @@
|
||||||
[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.path :as dwdp]
|
||||||
[app.main.data.workspace.path.shapes-to-path :as dwps]
|
[app.main.data.workspace.path.shapes-to-path :as dwps]
|
||||||
[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.shape-layout :as dwsl]
|
[app.main.data.workspace.shape-layout :as dwsl]
|
||||||
[app.main.data.workspace.shapes :as dwsh]
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
|
@ -87,6 +88,7 @@
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
(def default-workspace-local {:zoom 1})
|
(def default-workspace-local {:zoom 1})
|
||||||
|
(log/set-level! :debug)
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Workspace Initialization
|
;; Workspace Initialization
|
||||||
|
@ -341,15 +343,32 @@
|
||||||
:workspace-presence {}))
|
:workspace-presence {}))
|
||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ stream]
|
||||||
(rx/of msg/hide
|
(log/debug :hint "initialize-file" :file-id file-id)
|
||||||
(dcm/retrieve-comment-threads file-id)
|
(let [stoper-s (rx/filter (ptk/type? ::finalize-file) stream)]
|
||||||
(dwp/initialize-file-persistence file-id)
|
(rx/merge
|
||||||
(fetch-bundle project-id file-id)))
|
(rx/of msg/hide
|
||||||
|
(features/initialize)
|
||||||
|
(dcm/retrieve-comment-threads file-id)
|
||||||
|
(fetch-bundle project-id file-id))
|
||||||
|
|
||||||
|
(->> stream
|
||||||
|
(rx/filter dch/commit?)
|
||||||
|
(rx/map deref)
|
||||||
|
(rx/mapcat (fn [{:keys [save-undo? undo-changes redo-changes undo-group tags stack-undo?]}]
|
||||||
|
(if (and save-undo? (seq undo-changes))
|
||||||
|
(let [entry {:undo-changes undo-changes
|
||||||
|
:redo-changes redo-changes
|
||||||
|
:undo-group undo-group
|
||||||
|
:tags tags}]
|
||||||
|
(rx/of (dwu/append-undo entry stack-undo?)))
|
||||||
|
(rx/empty))))
|
||||||
|
|
||||||
|
(rx/take-until stoper-s)))))
|
||||||
|
|
||||||
ptk/EffectEvent
|
ptk/EffectEvent
|
||||||
(effect [_ _ _]
|
(effect [_ _ _]
|
||||||
(let [name (str "workspace-" file-id)]
|
(let [name (dm/str "workspace-" file-id)]
|
||||||
(unchecked-set ug/global "name" name)))))
|
(unchecked-set ug/global "name" name)))))
|
||||||
|
|
||||||
(defn finalize-file
|
(defn finalize-file
|
||||||
|
@ -671,7 +690,7 @@
|
||||||
(ptk/reify ::update-shape
|
(ptk/reify ::update-shape
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(rx/of (dch/update-shapes [id] #(merge % attrs))))))
|
(rx/of (dwsh/update-shapes [id] #(merge % attrs))))))
|
||||||
|
|
||||||
(defn start-rename-shape
|
(defn start-rename-shape
|
||||||
"Start shape renaming process"
|
"Start shape renaming process"
|
||||||
|
@ -982,7 +1001,7 @@
|
||||||
(assoc shape :proportion-lock false)
|
(assoc shape :proportion-lock false)
|
||||||
(-> (assoc shape :proportion-lock true)
|
(-> (assoc shape :proportion-lock true)
|
||||||
(gpp/assign-proportions))))]
|
(gpp/assign-proportions))))]
|
||||||
(rx/of (dch/update-shapes [id] assign-proportions))))))
|
(rx/of (dwsh/update-shapes [id] assign-proportions))))))
|
||||||
|
|
||||||
(defn toggle-proportion-lock
|
(defn toggle-proportion-lock
|
||||||
[]
|
[]
|
||||||
|
@ -996,8 +1015,8 @@
|
||||||
multi (attrs/get-attrs-multi selected-obj [:proportion-lock])
|
multi (attrs/get-attrs-multi selected-obj [:proportion-lock])
|
||||||
multi? (= :multiple (:proportion-lock multi))]
|
multi? (= :multiple (:proportion-lock multi))]
|
||||||
(if multi?
|
(if multi?
|
||||||
(rx/of (dch/update-shapes selected #(assoc % :proportion-lock true)))
|
(rx/of (dwsh/update-shapes selected #(assoc % :proportion-lock true)))
|
||||||
(rx/of (dch/update-shapes selected #(update % :proportion-lock not))))))))
|
(rx/of (dwsh/update-shapes selected #(update % :proportion-lock not))))))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Navigation
|
;; Navigation
|
||||||
|
@ -1258,7 +1277,7 @@
|
||||||
(assoc :section section)
|
(assoc :section section)
|
||||||
(some? frame-id)
|
(some? frame-id)
|
||||||
(assoc :frame-id frame-id))]
|
(assoc :frame-id frame-id))]
|
||||||
(rx/of ::dwp/force-persist
|
(rx/of ::dps/force-persist
|
||||||
(rt/nav-new-window* {:rname :viewer
|
(rt/nav-new-window* {:rname :viewer
|
||||||
:path-params pparams
|
:path-params pparams
|
||||||
:query-params qparams
|
:query-params qparams
|
||||||
|
@ -1271,7 +1290,7 @@
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(when-let [team-id (or team-id (:current-team-id state))]
|
(when-let [team-id (or team-id (:current-team-id state))]
|
||||||
(rx/of ::dwp/force-persist
|
(rx/of ::dps/force-persist
|
||||||
(rt/nav :dashboard-projects {:team-id team-id})))))))
|
(rt/nav :dashboard-projects {:team-id team-id})))))))
|
||||||
|
|
||||||
(defn go-to-dashboard-fonts
|
(defn go-to-dashboard-fonts
|
||||||
|
@ -1280,7 +1299,7 @@
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [team-id (:current-team-id state)]
|
(let [team-id (:current-team-id state)]
|
||||||
(rx/of ::dwp/force-persist
|
(rx/of ::dps/force-persist
|
||||||
(rt/nav :dashboard-fonts {:team-id team-id}))))))
|
(rt/nav :dashboard-fonts {:team-id team-id}))))))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,9 @@
|
||||||
[app.common.types.shape :as cts]
|
[app.common.types.shape :as cts]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
|
@ -117,7 +118,7 @@
|
||||||
change-to-bool
|
change-to-bool
|
||||||
(fn [shape] (group->bool shape bool-type objects))]
|
(fn [shape] (group->bool shape bool-type objects))]
|
||||||
(when-not (ctn/has-any-copy-parent? objects (get objects shape-id))
|
(when-not (ctn/has-any-copy-parent? objects (get objects shape-id))
|
||||||
(rx/of (dch/update-shapes [shape-id] change-to-bool {:reg-objects? true})))))))
|
(rx/of (dwsh/update-shapes [shape-id] change-to-bool {:reg-objects? true})))))))
|
||||||
|
|
||||||
(defn bool-to-group
|
(defn bool-to-group
|
||||||
[shape-id]
|
[shape-id]
|
||||||
|
@ -128,7 +129,7 @@
|
||||||
change-to-group
|
change-to-group
|
||||||
(fn [shape] (bool->group shape objects))]
|
(fn [shape] (bool->group shape objects))]
|
||||||
(when-not (ctn/has-any-copy-parent? objects (get objects shape-id))
|
(when-not (ctn/has-any-copy-parent? objects (get objects shape-id))
|
||||||
(rx/of (dch/update-shapes [shape-id] change-to-group {:reg-objects? true})))))))
|
(rx/of (dwsh/update-shapes [shape-id] change-to-group {:reg-objects? true})))))))
|
||||||
|
|
||||||
|
|
||||||
(defn change-bool-type
|
(defn change-bool-type
|
||||||
|
@ -140,4 +141,4 @@
|
||||||
change-type
|
change-type
|
||||||
(fn [shape] (assoc shape :bool-type bool-type))]
|
(fn [shape] (assoc shape :bool-type bool-type))]
|
||||||
(when-not (ctn/has-any-copy-parent? objects (get objects shape-id))
|
(when-not (ctn/has-any-copy-parent? objects (get objects shape-id))
|
||||||
(rx/of (dch/update-shapes [shape-id] change-type {:reg-objects? true})))))))
|
(rx/of (dwsh/update-shapes [shape-id] change-type {:reg-objects? true})))))))
|
||||||
|
|
|
@ -1,264 +0,0 @@
|
||||||
;; 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.main.data.workspace.changes
|
|
||||||
(:require
|
|
||||||
[app.common.data :as d]
|
|
||||||
[app.common.data.macros :as dm]
|
|
||||||
[app.common.exceptions :as ex]
|
|
||||||
[app.common.files.changes :as cpc]
|
|
||||||
[app.common.files.changes-builder :as pcb]
|
|
||||||
[app.common.files.helpers :as cph]
|
|
||||||
[app.common.logging :as log]
|
|
||||||
[app.common.logic.shapes :as cls]
|
|
||||||
[app.common.schema :as sm]
|
|
||||||
[app.common.types.shape-tree :as ctst]
|
|
||||||
[app.common.uuid :as uuid]
|
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
|
||||||
[app.main.data.workspace.undo :as dwu]
|
|
||||||
[app.main.store :as st]
|
|
||||||
[app.main.worker :as uw]
|
|
||||||
[beicon.v2.core :as rx]
|
|
||||||
[potok.v2.core :as ptk]))
|
|
||||||
|
|
||||||
;; Change this to :info :debug or :trace to debug this module
|
|
||||||
(log/set-level! :warn)
|
|
||||||
|
|
||||||
(defonce page-change? #{:add-page :mod-page :del-page :mov-page})
|
|
||||||
(defonce update-layout-attr? #{:hidden})
|
|
||||||
|
|
||||||
(declare commit-changes)
|
|
||||||
|
|
||||||
(defn- add-undo-group
|
|
||||||
[changes state]
|
|
||||||
(let [undo (:workspace-undo state)
|
|
||||||
items (:items undo)
|
|
||||||
index (or (:index undo) (dec (count items)))
|
|
||||||
prev-item (when-not (or (empty? items) (= index -1))
|
|
||||||
(get items index))
|
|
||||||
undo-group (:undo-group prev-item)
|
|
||||||
add-undo-group? (and
|
|
||||||
(not (nil? undo-group))
|
|
||||||
(= (get-in changes [:redo-changes 0 :type]) :mod-obj)
|
|
||||||
(= (get-in prev-item [:redo-changes 0 :type]) :add-obj)
|
|
||||||
(contains? (:tags prev-item) :alt-duplication))] ;; This is a copy-and-move with mouse+alt
|
|
||||||
|
|
||||||
(cond-> changes add-undo-group? (assoc :undo-group undo-group))))
|
|
||||||
|
|
||||||
(def commit-changes? (ptk/type? ::commit-changes))
|
|
||||||
|
|
||||||
(defn update-shapes
|
|
||||||
([ids update-fn] (update-shapes ids update-fn nil))
|
|
||||||
([ids update-fn {:keys [reg-objects? save-undo? stack-undo? attrs ignore-tree page-id ignore-remote? ignore-touched undo-group with-objects?]
|
|
||||||
:or {reg-objects? false save-undo? true stack-undo? false ignore-remote? false ignore-touched false with-objects? false}}]
|
|
||||||
|
|
||||||
(dm/assert!
|
|
||||||
"expected a valid coll of uuid's"
|
|
||||||
(sm/check-coll-of-uuid! ids))
|
|
||||||
|
|
||||||
(dm/assert! (fn? update-fn))
|
|
||||||
|
|
||||||
(ptk/reify ::update-shapes
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [it state _]
|
|
||||||
(let [page-id (or page-id (:current-page-id state))
|
|
||||||
objects (wsh/lookup-page-objects state page-id)
|
|
||||||
ids (into [] (filter some?) ids)
|
|
||||||
|
|
||||||
update-layout-ids
|
|
||||||
(->> ids
|
|
||||||
(map (d/getf objects))
|
|
||||||
(filter #(some update-layout-attr? (pcb/changed-attrs % objects update-fn {:attrs attrs :with-objects? with-objects?})))
|
|
||||||
(map :id))
|
|
||||||
|
|
||||||
changes (-> (pcb/empty-changes it page-id)
|
|
||||||
(pcb/set-save-undo? save-undo?)
|
|
||||||
(pcb/set-stack-undo? stack-undo?)
|
|
||||||
(cls/generate-update-shapes ids
|
|
||||||
update-fn
|
|
||||||
objects
|
|
||||||
{:attrs attrs
|
|
||||||
:ignore-tree ignore-tree
|
|
||||||
:ignore-touched ignore-touched
|
|
||||||
:with-objects? with-objects?})
|
|
||||||
(cond-> undo-group
|
|
||||||
(pcb/set-undo-group undo-group)))
|
|
||||||
|
|
||||||
changes (add-undo-group changes state)]
|
|
||||||
(rx/concat
|
|
||||||
(if (seq (:redo-changes changes))
|
|
||||||
(let [changes (cond-> changes reg-objects? (pcb/resize-parents ids))
|
|
||||||
changes (cond-> changes ignore-remote? (pcb/ignore-remote))]
|
|
||||||
(rx/of (commit-changes changes)))
|
|
||||||
(rx/empty))
|
|
||||||
|
|
||||||
;; Update layouts for properties marked
|
|
||||||
(if (d/not-empty? update-layout-ids)
|
|
||||||
(rx/of (ptk/data-event :layout/update {:ids update-layout-ids}))
|
|
||||||
(rx/empty))))))))
|
|
||||||
|
|
||||||
(defn send-update-indices
|
|
||||||
[]
|
|
||||||
(ptk/reify ::send-update-indices
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ _ _]
|
|
||||||
(->> (rx/of
|
|
||||||
(fn [state]
|
|
||||||
(-> state
|
|
||||||
(dissoc ::update-indices-debounce)
|
|
||||||
(dissoc ::update-changes))))
|
|
||||||
(rx/observe-on :async)))
|
|
||||||
|
|
||||||
ptk/EffectEvent
|
|
||||||
(effect [_ state _]
|
|
||||||
(doseq [[page-id changes] (::update-changes state)]
|
|
||||||
(uw/ask! {:cmd :update-page-index
|
|
||||||
:page-id page-id
|
|
||||||
:changes changes})))))
|
|
||||||
|
|
||||||
;; Update indices will debounce operations so we don't have to update
|
|
||||||
;; the index several times (which is an expensive operation)
|
|
||||||
(defn update-indices
|
|
||||||
[page-id changes]
|
|
||||||
|
|
||||||
(let [start (uuid/next)]
|
|
||||||
(ptk/reify ::update-indices
|
|
||||||
ptk/UpdateEvent
|
|
||||||
(update [_ state]
|
|
||||||
(if (nil? (::update-indices-debounce state))
|
|
||||||
(assoc state ::update-indices-debounce start)
|
|
||||||
(update-in state [::update-changes page-id] (fnil d/concat-vec []) changes)))
|
|
||||||
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state stream]
|
|
||||||
(if (= (::update-indices-debounce state) start)
|
|
||||||
(let [stopper (->> stream (rx/filter (ptk/type? :app.main.data.workspace/finalize)))]
|
|
||||||
(rx/merge
|
|
||||||
(->> stream
|
|
||||||
(rx/filter (ptk/type? ::update-indices))
|
|
||||||
(rx/debounce 50)
|
|
||||||
(rx/take 1)
|
|
||||||
(rx/map #(send-update-indices))
|
|
||||||
(rx/take-until stopper))
|
|
||||||
(rx/of (update-indices page-id changes))))
|
|
||||||
(rx/empty))))))
|
|
||||||
|
|
||||||
(defn changed-frames
|
|
||||||
"Extracts the frame-ids changed in the given changes"
|
|
||||||
[changes objects]
|
|
||||||
|
|
||||||
(let [change->ids
|
|
||||||
(fn [change]
|
|
||||||
(case (:type change)
|
|
||||||
:add-obj
|
|
||||||
[(:parent-id change)]
|
|
||||||
|
|
||||||
(:mod-obj :del-obj)
|
|
||||||
[(:id change)]
|
|
||||||
|
|
||||||
:mov-objects
|
|
||||||
(d/concat-vec (:shapes change) [(:parent-id change)])
|
|
||||||
|
|
||||||
[]))]
|
|
||||||
(into #{}
|
|
||||||
(comp (mapcat change->ids)
|
|
||||||
(keep #(cph/get-shape-id-root-frame objects %))
|
|
||||||
(remove #(= uuid/zero %)))
|
|
||||||
changes)))
|
|
||||||
|
|
||||||
(defn commit-changes
|
|
||||||
"Schedules a list of changes to execute now, and add the corresponding undo changes to
|
|
||||||
the undo stack.
|
|
||||||
|
|
||||||
Options:
|
|
||||||
- save-undo?: if set to false, do not add undo changes.
|
|
||||||
- undo-group: if some consecutive changes (or even transactions) share the same
|
|
||||||
undo-group, they will be undone or redone in a single step
|
|
||||||
"
|
|
||||||
[{:keys [redo-changes undo-changes
|
|
||||||
origin save-undo? file-id undo-group tags stack-undo?]
|
|
||||||
:or {save-undo? true stack-undo? false tags #{} undo-group (uuid/next)}}]
|
|
||||||
(let [error (volatile! nil)
|
|
||||||
page-id (:current-page-id @st/state)
|
|
||||||
frames (changed-frames redo-changes (wsh/lookup-page-objects @st/state))
|
|
||||||
undo-changes (vec undo-changes)
|
|
||||||
redo-changes (vec redo-changes)]
|
|
||||||
(ptk/reify ::commit-changes
|
|
||||||
cljs.core/IDeref
|
|
||||||
(-deref [_]
|
|
||||||
{:file-id file-id
|
|
||||||
:hint-events @st/last-events
|
|
||||||
:hint-origin (ptk/type origin)
|
|
||||||
:changes redo-changes
|
|
||||||
:page-id page-id
|
|
||||||
:frames frames
|
|
||||||
:save-undo? save-undo?
|
|
||||||
:undo-group undo-group
|
|
||||||
:tags tags
|
|
||||||
:stack-undo? stack-undo?})
|
|
||||||
|
|
||||||
ptk/UpdateEvent
|
|
||||||
(update [_ state]
|
|
||||||
(log/info :msg "commit-changes"
|
|
||||||
:js/undo-group (str undo-group)
|
|
||||||
:js/file-id (str (or file-id "nil"))
|
|
||||||
:js/redo-changes redo-changes
|
|
||||||
:js/undo-changes undo-changes)
|
|
||||||
(let [current-file-id (get state :current-file-id)
|
|
||||||
file-id (or file-id current-file-id)
|
|
||||||
path (if (= file-id current-file-id)
|
|
||||||
[:workspace-data]
|
|
||||||
[:workspace-libraries file-id :data])]
|
|
||||||
|
|
||||||
(try
|
|
||||||
(dm/assert!
|
|
||||||
"expect valid vector of changes"
|
|
||||||
(and (cpc/check-changes! redo-changes)
|
|
||||||
(cpc/check-changes! undo-changes)))
|
|
||||||
|
|
||||||
(update-in state path (fn [file]
|
|
||||||
(-> file
|
|
||||||
(cpc/process-changes redo-changes false)
|
|
||||||
(ctst/update-object-indices page-id))))
|
|
||||||
|
|
||||||
(catch :default err
|
|
||||||
(when-let [data (ex-data err)]
|
|
||||||
(js/console.log (ex/explain data)))
|
|
||||||
|
|
||||||
(when (ex/error? err)
|
|
||||||
(js/console.log (.-stack ^js err)))
|
|
||||||
(vreset! error err)
|
|
||||||
state))))
|
|
||||||
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ _ _]
|
|
||||||
(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
|
|
||||||
(and (page-change? type) (nil? (:page-id change)))
|
|
||||||
(assoc :page-id (or id (:id page)))))
|
|
||||||
|
|
||||||
changes-by-pages
|
|
||||||
(->> redo-changes
|
|
||||||
(map add-page-id)
|
|
||||||
(remove #(nil? (:page-id %)))
|
|
||||||
(group-by :page-id))
|
|
||||||
|
|
||||||
process-page-changes
|
|
||||||
(fn [[page-id _changes]]
|
|
||||||
(update-indices page-id redo-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 redo-changes
|
|
||||||
:undo-group undo-group
|
|
||||||
:tags tags}]
|
|
||||||
(rx/of (dwu/append-undo entry stack-undo?)))))))))))
|
|
|
@ -15,9 +15,9 @@
|
||||||
[app.main.broadcast :as mbc]
|
[app.main.broadcast :as mbc]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
[app.main.data.modal :as md]
|
[app.main.data.modal :as md]
|
||||||
[app.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.layout :as layout]
|
[app.main.data.workspace.layout :as layout]
|
||||||
[app.main.data.workspace.libraries :as dwl]
|
[app.main.data.workspace.libraries :as dwl]
|
||||||
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.main.data.workspace.texts :as dwt]
|
[app.main.data.workspace.texts :as dwt]
|
||||||
[app.main.data.workspace.undo :as dwu]
|
[app.main.data.workspace.undo :as dwu]
|
||||||
|
@ -116,7 +116,7 @@
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of (dwu/start-undo-transaction undo-id))
|
(rx/of (dwu/start-undo-transaction undo-id))
|
||||||
(rx/from (map #(dwt/update-text-with-function % transform-attrs) text-ids))
|
(rx/from (map #(dwt/update-text-with-function % transform-attrs) text-ids))
|
||||||
(rx/of (dch/update-shapes shape-ids transform-attrs))
|
(rx/of (dwsh/update-shapes shape-ids transform-attrs))
|
||||||
(rx/of (dwu/commit-undo-transaction undo-id)))))
|
(rx/of (dwu/commit-undo-transaction undo-id)))))
|
||||||
|
|
||||||
(defn swap-attrs [shape attr index new-index]
|
(defn swap-attrs [shape attr index new-index]
|
||||||
|
@ -140,7 +140,7 @@
|
||||||
|
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/from (map #(dwt/update-text-with-function % transform-attrs) text-ids))
|
(rx/from (map #(dwt/update-text-with-function % transform-attrs) text-ids))
|
||||||
(rx/of (dch/update-shapes shape-ids transform-attrs)))))))
|
(rx/of (dwsh/update-shapes shape-ids transform-attrs)))))))
|
||||||
|
|
||||||
(defn change-fill
|
(defn change-fill
|
||||||
[ids color position]
|
[ids color position]
|
||||||
|
@ -203,10 +203,10 @@
|
||||||
is-text? #(= :text (:type (get objects %)))
|
is-text? #(= :text (:type (get objects %)))
|
||||||
shape-ids (filter (complement is-text?) ids)
|
shape-ids (filter (complement is-text?) ids)
|
||||||
attrs {:hide-fill-on-export hide-fill-on-export}]
|
attrs {:hide-fill-on-export hide-fill-on-export}]
|
||||||
(rx/of (dch/update-shapes shape-ids (fn [shape]
|
(rx/of (dwsh/update-shapes shape-ids (fn [shape]
|
||||||
(if (= (:type shape) :frame)
|
(if (= (:type shape) :frame)
|
||||||
(d/merge shape attrs)
|
(d/merge shape attrs)
|
||||||
shape))))))))
|
shape))))))))
|
||||||
(defn change-stroke
|
(defn change-stroke
|
||||||
[ids attrs index]
|
[ids attrs index]
|
||||||
(ptk/reify ::change-stroke
|
(ptk/reify ::change-stroke
|
||||||
|
@ -236,7 +236,7 @@
|
||||||
(dissoc :image)
|
(dissoc :image)
|
||||||
(dissoc :gradient))]
|
(dissoc :gradient))]
|
||||||
|
|
||||||
(rx/of (dch/update-shapes
|
(rx/of (dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(let [new-attrs (merge (get-in shape [:strokes index]) attrs)
|
(let [new-attrs (merge (get-in shape [:strokes index]) attrs)
|
||||||
|
@ -264,7 +264,7 @@
|
||||||
(ptk/reify ::change-shadow
|
(ptk/reify ::change-shadow
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(rx/of (dch/update-shapes
|
(rx/of (dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(let [;; If we try to set a gradient to a shadow (for
|
(let [;; If we try to set a gradient to a shadow (for
|
||||||
|
@ -288,7 +288,7 @@
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(let [add-shadow (fn [shape]
|
(let [add-shadow (fn [shape]
|
||||||
(update shape :shadow #(into [shadow] %)))]
|
(update shape :shadow #(into [shadow] %)))]
|
||||||
(rx/of (dch/update-shapes ids add-shadow))))))
|
(rx/of (dwsh/update-shapes ids add-shadow))))))
|
||||||
|
|
||||||
(defn add-stroke
|
(defn add-stroke
|
||||||
[ids stroke]
|
[ids stroke]
|
||||||
|
@ -296,7 +296,7 @@
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(let [add-stroke (fn [shape] (update shape :strokes #(into [stroke] %)))]
|
(let [add-stroke (fn [shape] (update shape :strokes #(into [stroke] %)))]
|
||||||
(rx/of (dch/update-shapes ids add-stroke))))))
|
(rx/of (dwsh/update-shapes ids add-stroke))))))
|
||||||
|
|
||||||
(defn remove-stroke
|
(defn remove-stroke
|
||||||
[ids position]
|
[ids position]
|
||||||
|
@ -309,7 +309,7 @@
|
||||||
(mapv second)))
|
(mapv second)))
|
||||||
(remove-stroke [shape]
|
(remove-stroke [shape]
|
||||||
(update shape :strokes remove-fill-by-index position))]
|
(update shape :strokes remove-fill-by-index position))]
|
||||||
(rx/of (dch/update-shapes ids remove-stroke))))))
|
(rx/of (dwsh/update-shapes ids remove-stroke))))))
|
||||||
|
|
||||||
(defn remove-all-strokes
|
(defn remove-all-strokes
|
||||||
[ids]
|
[ids]
|
||||||
|
@ -317,14 +317,14 @@
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(let [remove-all #(assoc % :strokes [])]
|
(let [remove-all #(assoc % :strokes [])]
|
||||||
(rx/of (dch/update-shapes ids remove-all))))))
|
(rx/of (dwsh/update-shapes ids remove-all))))))
|
||||||
|
|
||||||
(defn reorder-shadows
|
(defn reorder-shadows
|
||||||
[ids index new-index]
|
[ids index new-index]
|
||||||
(ptk/reify ::reorder-shadow
|
(ptk/reify ::reorder-shadow
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(rx/of (dch/update-shapes
|
(rx/of (dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
#(swap-attrs % :shadow index new-index))))))
|
#(swap-attrs % :shadow index new-index))))))
|
||||||
|
|
||||||
|
@ -333,7 +333,7 @@
|
||||||
(ptk/reify ::reorder-strokes
|
(ptk/reify ::reorder-strokes
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(rx/of (dch/update-shapes
|
(rx/of (dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
#(swap-attrs % :strokes index new-index))))))
|
#(swap-attrs % :strokes index new-index))))))
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.types.shape-tree :as ctst]
|
[app.common.types.shape-tree :as ctst]
|
||||||
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.comments :as dcm]
|
[app.main.data.comments :as dcm]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
[app.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.common :as dwco]
|
[app.main.data.workspace.common :as dwco]
|
||||||
[app.main.data.workspace.drawing :as dwd]
|
[app.main.data.workspace.drawing :as dwd]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
|
|
|
@ -6,14 +6,7 @@
|
||||||
|
|
||||||
(ns app.main.data.workspace.common
|
(ns app.main.data.workspace.common
|
||||||
(:require
|
(:require
|
||||||
[app.common.data.macros :as dm]
|
|
||||||
[app.common.logging :as log]
|
[app.common.logging :as log]
|
||||||
[app.common.types.shape.layout :as ctl]
|
|
||||||
[app.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
|
||||||
[app.main.data.workspace.undo :as dwu]
|
|
||||||
[app.util.router :as rt]
|
|
||||||
[beicon.v2.core :as rx]
|
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.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
|
||||||
|
@ -34,136 +27,11 @@
|
||||||
[e]
|
[e]
|
||||||
(= e :interrupt))
|
(= e :interrupt))
|
||||||
|
|
||||||
(defn- assure-valid-current-page
|
|
||||||
[]
|
|
||||||
(ptk/reify ::assure-valid-current-page
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state _]
|
|
||||||
(let [current_page (:current-page-id state)
|
|
||||||
pages (get-in state [:workspace-data :pages])
|
|
||||||
exists? (some #(= current_page %) pages)
|
|
||||||
|
|
||||||
project-id (:current-project-id state)
|
|
||||||
file-id (:current-file-id state)
|
|
||||||
pparams {:file-id file-id :project-id project-id}
|
|
||||||
qparams {:page-id (first pages)}]
|
|
||||||
(if exists?
|
|
||||||
(rx/empty)
|
|
||||||
(rx/of (rt/nav :workspace pparams qparams)))))))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; UNDO
|
;; UNDO
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(declare undo-to-index)
|
|
||||||
|
|
||||||
;; These functions should've been in
|
|
||||||
;; `src/app/main/data/workspace/undo.cljs` but doing that causes a
|
|
||||||
;; circular dependency with `src/app/main/data/workspace/changes.cljs`
|
|
||||||
|
|
||||||
(def undo
|
|
||||||
(ptk/reify ::undo
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [it state _]
|
|
||||||
(let [objects (wsh/lookup-page-objects state)
|
|
||||||
edition (get-in state [:workspace-local :edition])
|
|
||||||
drawing (get state :workspace-drawing)]
|
|
||||||
|
|
||||||
;; Editors handle their own undo's
|
|
||||||
(when (or (and (nil? edition) (nil? (:object drawing)))
|
|
||||||
(ctl/grid-layout? objects edition))
|
|
||||||
(let [undo (:workspace-undo state)
|
|
||||||
items (:items undo)
|
|
||||||
index (or (:index undo) (dec (count items)))]
|
|
||||||
(when-not (or (empty? items) (= index -1))
|
|
||||||
(let [item (get items index)
|
|
||||||
changes (:undo-changes item)
|
|
||||||
undo-group (:undo-group item)
|
|
||||||
|
|
||||||
find-first-group-idx
|
|
||||||
(fn [index]
|
|
||||||
(if (= (dm/get-in items [index :undo-group]) undo-group)
|
|
||||||
(recur (dec index))
|
|
||||||
(inc index)))
|
|
||||||
|
|
||||||
undo-group-index
|
|
||||||
(when undo-group
|
|
||||||
(find-first-group-idx index))]
|
|
||||||
|
|
||||||
(if undo-group
|
|
||||||
(rx/of (undo-to-index (dec undo-group-index)))
|
|
||||||
(rx/of (dwu/materialize-undo changes (dec index))
|
|
||||||
(dch/commit-changes {:redo-changes changes
|
|
||||||
:undo-changes []
|
|
||||||
:save-undo? false
|
|
||||||
:origin it})
|
|
||||||
(assure-valid-current-page)))))))))))
|
|
||||||
|
|
||||||
(def redo
|
|
||||||
(ptk/reify ::redo
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [it state _]
|
|
||||||
(let [objects (wsh/lookup-page-objects state)
|
|
||||||
edition (get-in state [:workspace-local :edition])
|
|
||||||
drawing (get state :workspace-drawing)]
|
|
||||||
(when (and (or (nil? edition) (ctl/grid-layout? objects edition))
|
|
||||||
(or (empty? drawing) (= :curve (:tool drawing))))
|
|
||||||
(let [undo (:workspace-undo state)
|
|
||||||
items (:items undo)
|
|
||||||
index (or (:index undo) (dec (count items)))]
|
|
||||||
(when-not (or (empty? items) (= index (dec (count items))))
|
|
||||||
(let [item (get items (inc index))
|
|
||||||
changes (:redo-changes item)
|
|
||||||
undo-group (:undo-group item)
|
|
||||||
find-last-group-idx (fn flgidx [index]
|
|
||||||
(let [item (get items index)]
|
|
||||||
(if (= (:undo-group item) undo-group)
|
|
||||||
(flgidx (inc index))
|
|
||||||
(dec index))))
|
|
||||||
|
|
||||||
redo-group-index (when undo-group
|
|
||||||
(find-last-group-idx (inc index)))]
|
|
||||||
(if undo-group
|
|
||||||
(rx/of (undo-to-index redo-group-index))
|
|
||||||
(rx/of (dwu/materialize-undo changes (inc index))
|
|
||||||
(dch/commit-changes {:redo-changes changes
|
|
||||||
:undo-changes []
|
|
||||||
:origin it
|
|
||||||
:save-undo? false})))))))))))
|
|
||||||
|
|
||||||
(defn undo-to-index
|
|
||||||
"Repeat undoing or redoing until dest-index is reached."
|
|
||||||
[dest-index]
|
|
||||||
(ptk/reify ::undo-to-index
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [it state _]
|
|
||||||
(let [objects (wsh/lookup-page-objects state)
|
|
||||||
edition (get-in state [:workspace-local :edition])
|
|
||||||
drawing (get state :workspace-drawing)]
|
|
||||||
(when-not (and (or (some? edition) (some? (:object drawing)))
|
|
||||||
(not (ctl/grid-layout? objects edition)))
|
|
||||||
(let [undo (:workspace-undo state)
|
|
||||||
items (:items undo)
|
|
||||||
index (or (:index undo) (dec (count items)))]
|
|
||||||
(when (and (some? items)
|
|
||||||
(<= -1 dest-index (dec (count items))))
|
|
||||||
(let [changes (vec (apply concat
|
|
||||||
(cond
|
|
||||||
(< dest-index index)
|
|
||||||
(->> (subvec items (inc dest-index) (inc index))
|
|
||||||
(reverse)
|
|
||||||
(map :undo-changes))
|
|
||||||
(> dest-index index)
|
|
||||||
(->> (subvec items (inc index) (inc dest-index))
|
|
||||||
(map :redo-changes))
|
|
||||||
:else [])))]
|
|
||||||
(when (seq changes)
|
|
||||||
(rx/of (dwu/materialize-undo changes dest-index)
|
|
||||||
(dch/commit-changes {:redo-changes changes
|
|
||||||
:undo-changes []
|
|
||||||
:origin it
|
|
||||||
:save-undo? false})))))))))))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Toolbar
|
;; Toolbar
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.changes :as dch]
|
||||||
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
@ -82,9 +83,9 @@
|
||||||
:objects (-> component migrate-component :objects)}))
|
:objects (-> component migrate-component :objects)}))
|
||||||
components)]
|
components)]
|
||||||
|
|
||||||
(rx/of (dch/update-shapes ids #(update-shape % objects) {:reg-objects? false
|
(rx/of (dwsh/update-shapes ids #(update-shape % objects) {:reg-objects? false
|
||||||
:save-undo? false
|
:save-undo? false
|
||||||
:ignore-tree true}))
|
:ignore-tree true}))
|
||||||
|
|
||||||
(if (empty? component-changes)
|
(if (empty? component-changes)
|
||||||
(rx/empty)
|
(rx/empty)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
(ns app.main.data.workspace.fix-broken-shapes
|
(ns app.main.data.workspace.fix-broken-shapes
|
||||||
(:require
|
(:require
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.changes :as dch]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.files.helpers :as cfh]
|
[app.common.files.helpers :as cfh]
|
||||||
[app.common.text :as txt]
|
[app.common.text :as txt]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.changes :as dwc]
|
||||||
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.main.fonts :as fonts]
|
[app.main.fonts :as fonts]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
|
@ -111,19 +112,19 @@
|
||||||
typographies)]
|
typographies)]
|
||||||
|
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of (dch/update-shapes ids #(fix-deleted-font-shape %) {:reg-objects? false
|
(rx/of (dwsh/update-shapes ids #(fix-deleted-font-shape %) {:reg-objects? false
|
||||||
:save-undo? false
|
:save-undo? false
|
||||||
:ignore-tree true}))
|
:ignore-tree true}))
|
||||||
(if (empty? component-changes)
|
(if (empty? component-changes)
|
||||||
(rx/empty)
|
(rx/empty)
|
||||||
(rx/of (dch/commit-changes {:origin it
|
(rx/of (dwc/commit-changes {:origin it
|
||||||
:redo-changes component-changes
|
:redo-changes component-changes
|
||||||
:undo-changes []
|
:undo-changes []
|
||||||
:save-undo? false})))
|
:save-undo? false})))
|
||||||
|
|
||||||
(if (empty? typography-changes)
|
(if (empty? typography-changes)
|
||||||
(rx/empty)
|
(rx/empty)
|
||||||
(rx/of (dch/commit-changes {:origin it
|
(rx/of (dwc/commit-changes {:origin it
|
||||||
:redo-changes typography-changes
|
:redo-changes typography-changes
|
||||||
:undo-changes []
|
:undo-changes []
|
||||||
:save-undo? false}))))))))
|
:save-undo? false}))))))))
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.files.changes-builder :as pcb]
|
[app.common.files.changes-builder :as pcb]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.changes :as dch]
|
||||||
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
@ -51,8 +52,8 @@
|
||||||
grid {:type :square
|
grid {:type :square
|
||||||
:params params
|
:params params
|
||||||
:display true}]
|
:display true}]
|
||||||
(rx/of (dch/update-shapes [frame-id]
|
(rx/of (dwsh/update-shapes [frame-id]
|
||||||
(fn [obj] (update obj :grids (fnil #(conj % grid) [])))))))))
|
(fn [obj] (update obj :grids (fnil #(conj % grid) [])))))))))
|
||||||
|
|
||||||
|
|
||||||
(defn remove-frame-grid
|
(defn remove-frame-grid
|
||||||
|
@ -60,14 +61,14 @@
|
||||||
(ptk/reify ::remove-frame-grid
|
(ptk/reify ::remove-frame-grid
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(rx/of (dch/update-shapes [frame-id] (fn [o] (update o :grids (fnil #(d/remove-at-index % index) []))))))))
|
(rx/of (dwsh/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 [_ _ _]
|
(watch [_ _ _]
|
||||||
(rx/of (dch/update-shapes [frame-id] #(assoc-in % [:grids index] data))))))
|
(rx/of (dwsh/update-shapes [frame-id] #(assoc-in % [:grids index] data))))))
|
||||||
|
|
||||||
(defn set-default-grid
|
(defn set-default-grid
|
||||||
[type params]
|
[type params]
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
(:require
|
(:require
|
||||||
[app.main.data.shortcuts :as ds]
|
[app.main.data.shortcuts :as ds]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.common :as dwc]
|
[app.main.data.workspace.undo :as dwu]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
@ -38,11 +38,11 @@
|
||||||
|
|
||||||
:undo {:tooltip (ds/meta "Z")
|
:undo {:tooltip (ds/meta "Z")
|
||||||
:command (ds/c-mod "z")
|
:command (ds/c-mod "z")
|
||||||
:fn #(st/emit! dwc/undo)}
|
:fn #(st/emit! dwu/undo)}
|
||||||
|
|
||||||
:redo {:tooltip (ds/meta "Y")
|
:redo {:tooltip (ds/meta "Y")
|
||||||
:command [(ds/c-mod "shift+z") (ds/c-mod "y")]
|
:command [(ds/c-mod "shift+z") (ds/c-mod "y")]
|
||||||
:fn #(st/emit! dwc/redo)}
|
:fn #(st/emit! dwu/redo)}
|
||||||
|
|
||||||
;; ZOOM
|
;; ZOOM
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
[app.common.types.shape :as cts]
|
[app.common.types.shape :as cts]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.main.data.workspace.undo :as dwu]
|
[app.main.data.workspace.undo :as dwu]
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.common.types.page :as ctp]
|
[app.common.types.page :as ctp]
|
||||||
|
[app.main.data.changes :as dwc]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
[app.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
(-> (pcb/empty-changes it)
|
(-> (pcb/empty-changes it)
|
||||||
(pcb/with-page page)
|
(pcb/with-page page)
|
||||||
(pcb/update-page-option :guides assoc (:id guide) guide))]
|
(pcb/update-page-option :guides assoc (:id guide) guide))]
|
||||||
(rx/of (dch/commit-changes changes))))))
|
(rx/of (dwc/commit-changes changes))))))
|
||||||
|
|
||||||
(defn remove-guide
|
(defn remove-guide
|
||||||
[guide]
|
[guide]
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
(-> (pcb/empty-changes it)
|
(-> (pcb/empty-changes it)
|
||||||
(pcb/with-page page)
|
(pcb/with-page page)
|
||||||
(pcb/update-page-option :guides dissoc (:id guide)))]
|
(pcb/update-page-option :guides dissoc (:id guide)))]
|
||||||
(rx/of (dch/commit-changes changes))))))
|
(rx/of (dwc/commit-changes changes))))))
|
||||||
|
|
||||||
(defn remove-guides
|
(defn remove-guides
|
||||||
[ids]
|
[ids]
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
[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.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.changes :as dch]
|
||||||
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.main.data.workspace.undo :as dwu]
|
[app.main.data.workspace.undo :as dwu]
|
||||||
[app.main.streams :as ms]
|
[app.main.streams :as ms]
|
||||||
|
@ -125,13 +126,13 @@
|
||||||
:flows] [])
|
:flows] [])
|
||||||
flow (ctp/get-frame-flow flows (:id frame))]
|
flow (ctp/get-frame-flow flows (:id frame))]
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of (dch/update-shapes [(:id shape)]
|
(rx/of (dwsh/update-shapes [(:id shape)]
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(let [new-interaction (-> ctsi/default-interaction
|
(let [new-interaction (-> ctsi/default-interaction
|
||||||
(ctsi/set-destination destination)
|
(ctsi/set-destination destination)
|
||||||
(assoc :position-relative-to (:id shape)))]
|
(assoc :position-relative-to (:id shape)))]
|
||||||
(update shape :interactions
|
(update shape :interactions
|
||||||
ctsi/add-interaction new-interaction)))))
|
ctsi/add-interaction new-interaction)))))
|
||||||
(when (and (not (connected-frame? objects (:id frame)))
|
(when (and (not (connected-frame? objects (:id frame)))
|
||||||
(nil? flow))
|
(nil? flow))
|
||||||
(rx/of (add-flow (:id frame))))))))))
|
(rx/of (add-flow (:id frame))))))))))
|
||||||
|
@ -141,20 +142,19 @@
|
||||||
(ptk/reify ::remove-interaction
|
(ptk/reify ::remove-interaction
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(rx/of (dch/update-shapes [(:id shape)]
|
(rx/of (dwsh/update-shapes [(:id shape)]
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(update shape :interactions
|
(update shape :interactions
|
||||||
ctsi/remove-interaction index)))))))
|
ctsi/remove-interaction index)))))))
|
||||||
|
|
||||||
(defn update-interaction
|
(defn update-interaction
|
||||||
[shape index update-fn]
|
[shape index update-fn]
|
||||||
(ptk/reify ::update-interaction
|
(ptk/reify ::update-interaction
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(rx/of (dch/update-shapes [(:id shape)]
|
(rx/of (dwsh/update-shapes [(:id shape)]
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(update shape :interactions
|
(update shape :interactions
|
||||||
ctsi/update-interaction index update-fn)))))))
|
ctsi/update-interaction index update-fn)))))))
|
||||||
|
|
||||||
(defn remove-all-interactions-nav-to
|
(defn remove-all-interactions-nav-to
|
||||||
"Remove all interactions that navigate to the given frame."
|
"Remove all interactions that navigate to the given frame."
|
||||||
|
@ -171,9 +171,9 @@
|
||||||
new-interactions (ctsi/remove-interactions #(ctsi/navs-to? % frame-id)
|
new-interactions (ctsi/remove-interactions #(ctsi/navs-to? % frame-id)
|
||||||
interactions)]
|
interactions)]
|
||||||
(when (not= (count interactions) (count new-interactions))
|
(when (not= (count interactions) (count new-interactions))
|
||||||
(dch/update-shapes [(:id shape)]
|
(dwsh/update-shapes [(:id shape)]
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(assoc shape :interactions new-interactions))))))]
|
(assoc shape :interactions new-interactions))))))]
|
||||||
|
|
||||||
(rx/from (->> (vals objects)
|
(rx/from (->> (vals objects)
|
||||||
(map remove-interactions-shape)
|
(map remove-interactions-shape)
|
||||||
|
@ -260,20 +260,20 @@
|
||||||
(dwu/start-undo-transaction undo-id)
|
(dwu/start-undo-transaction undo-id)
|
||||||
|
|
||||||
(when (:hide-in-viewer target-frame)
|
(when (:hide-in-viewer target-frame)
|
||||||
; If the target frame is hidden, we need to unhide it so
|
;; If the target frame is hidden, we need to unhide it so
|
||||||
; users can navigate to it.
|
;; users can navigate to it.
|
||||||
(dch/update-shapes [(:id target-frame)]
|
(dwsh/update-shapes [(:id target-frame)]
|
||||||
#(dissoc % :hide-in-viewer)))
|
#(dissoc % :hide-in-viewer)))
|
||||||
|
|
||||||
(cond
|
(cond
|
||||||
(or (nil? shape)
|
(or (nil? shape)
|
||||||
;; Didn't changed the position for the interaction
|
;; Didn't changed the position for the interaction
|
||||||
(= position initial-pos)
|
(= position initial-pos)
|
||||||
;; New interaction but invalid target
|
;; New interaction but invalid target
|
||||||
(and (nil? index) (nil? target-frame)))
|
(and (nil? index) (nil? target-frame)))
|
||||||
nil
|
nil
|
||||||
|
|
||||||
;; Dropped interaction in an invalid target. We remove it
|
;; Dropped interaction in an invalid target. We remove it
|
||||||
(and (some? index) (nil? target-frame))
|
(and (some? index) (nil? target-frame))
|
||||||
(remove-interaction shape index)
|
(remove-interaction shape index)
|
||||||
|
|
||||||
|
@ -364,5 +364,5 @@
|
||||||
(update interactions index
|
(update interactions index
|
||||||
#(ctsi/set-overlay-position % overlay-pos))]
|
#(ctsi/set-overlay-position % overlay-pos))]
|
||||||
|
|
||||||
(rx/of (dch/update-shapes [(:id shape)] #(merge % {:interactions new-interactions})))))))
|
(rx/of (dwsh/update-shapes [(:id shape)] #(merge % {:interactions new-interactions})))))))
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.math :as mth]
|
[app.common.math :as mth]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
shapes (map #(get objects %) selected)
|
shapes (map #(get objects %) selected)
|
||||||
shapes-ids (->> shapes
|
shapes-ids (->> shapes
|
||||||
(map :id))]
|
(map :id))]
|
||||||
(rx/of (dch/update-shapes shapes-ids #(assoc % :opacity opacity)))))))
|
(rx/of (dwsh/update-shapes shapes-ids #(assoc % :opacity opacity)))))))
|
||||||
|
|
||||||
(defn pressed-opacity
|
(defn pressed-opacity
|
||||||
[opacity]
|
[opacity]
|
||||||
|
|
|
@ -24,15 +24,16 @@
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
[app.common.types.typography :as ctt]
|
[app.common.types.typography :as ctt]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.comments :as dc]
|
[app.main.data.comments :as dc]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
[app.main.data.messages :as msg]
|
[app.main.data.messages :as msg]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.workspace :as-alias dw]
|
[app.main.data.workspace :as-alias dw]
|
||||||
[app.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.groups :as dwg]
|
[app.main.data.workspace.groups :as dwg]
|
||||||
[app.main.data.workspace.notifications :as-alias dwn]
|
[app.main.data.workspace.notifications :as-alias dwn]
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.specialized-panel :as dwsp]
|
[app.main.data.workspace.specialized-panel :as dwsp]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.main.data.workspace.thumbnails :as dwt]
|
[app.main.data.workspace.thumbnails :as dwt]
|
||||||
|
@ -54,7 +55,6 @@
|
||||||
;; Change this to :info :debug or :trace to debug this module, or :warn to reset to default
|
;; Change this to :info :debug or :trace to debug this module, or :warn to reset to default
|
||||||
(log/set-level! :warn)
|
(log/set-level! :warn)
|
||||||
|
|
||||||
|
|
||||||
(defn- pretty-file
|
(defn- pretty-file
|
||||||
[file-id state]
|
[file-id state]
|
||||||
(if (= file-id (:current-file-id state))
|
(if (= file-id (:current-file-id state))
|
||||||
|
@ -441,7 +441,7 @@
|
||||||
|
|
||||||
;; NOTE: only when components-v2 is enabled
|
;; NOTE: only when components-v2 is enabled
|
||||||
(when (and shape-id page-id)
|
(when (and shape-id page-id)
|
||||||
(rx/of (dch/update-shapes [shape-id] #(assoc % :name clean-name) {:page-id page-id :stack-undo? true}))))))))))
|
(rx/of (dwsh/update-shapes [shape-id] #(assoc % :name clean-name) {:page-id page-id :stack-undo? 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."
|
||||||
|
@ -1148,7 +1148,7 @@
|
||||||
|
|
||||||
changes-s
|
changes-s
|
||||||
(->> stream
|
(->> stream
|
||||||
(rx/filter #(or (dch/commit-changes? %)
|
(rx/filter #(or (dch/commit? %)
|
||||||
(ptk/type? % ::dwn/handle-file-change)))
|
(ptk/type? % ::dwn/handle-file-change)))
|
||||||
(rx/observe-on :async))
|
(rx/observe-on :async))
|
||||||
|
|
||||||
|
|
|
@ -20,9 +20,9 @@
|
||||||
[app.common.types.shape :as cts]
|
[app.common.types.shape :as cts]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.media :as dmm]
|
[app.main.data.media :as dmm]
|
||||||
[app.main.data.messages :as msg]
|
[app.main.data.messages :as msg]
|
||||||
[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.shapes :as dwsh]
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.constants :refer [zoom-half-pixel-precision]]
|
[app.main.constants :refer [zoom-half-pixel-precision]]
|
||||||
[app.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.comments :as-alias dwcm]
|
[app.main.data.workspace.comments :as-alias dwcm]
|
||||||
[app.main.data.workspace.guides :as-alias dwg]
|
[app.main.data.workspace.guides :as-alias dwg]
|
||||||
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.main.data.workspace.undo :as dwu]
|
[app.main.data.workspace.undo :as dwu]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
|
@ -499,7 +499,7 @@
|
||||||
(rx/empty))
|
(rx/empty))
|
||||||
(rx/of (ptk/event ::dwg/move-frame-guides ids-with-children)
|
(rx/of (ptk/event ::dwg/move-frame-guides ids-with-children)
|
||||||
(ptk/event ::dwcm/move-frame-comment-threads ids-with-children)
|
(ptk/event ::dwcm/move-frame-comment-threads ids-with-children)
|
||||||
(dch/update-shapes
|
(dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(let [modif (get-in object-modifiers [(:id shape) :modifiers])
|
(let [modif (get-in object-modifiers [(:id shape) :modifiers])
|
||||||
|
|
|
@ -11,11 +11,10 @@
|
||||||
[app.common.files.changes :as cpc]
|
[app.common.files.changes :as cpc]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.common :refer [handle-notification]]
|
[app.main.data.common :refer [handle-notification]]
|
||||||
[app.main.data.websocket :as dws]
|
[app.main.data.websocket :as dws]
|
||||||
[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.persistence :as dwp]
|
|
||||||
[app.util.globals :refer [global]]
|
[app.util.globals :refer [global]]
|
||||||
[app.util.mouse :as mse]
|
[app.util.mouse :as mse]
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
|
@ -84,7 +83,7 @@
|
||||||
(->> stream
|
(->> stream
|
||||||
(rx/filter mse/pointer-event?)
|
(rx/filter mse/pointer-event?)
|
||||||
(rx/filter #(= :viewport (mse/get-pointer-source %)))
|
(rx/filter #(= :viewport (mse/get-pointer-source %)))
|
||||||
(rx/pipe (rxs/throttle 100))
|
(rx/pipe (rxs/throttle 50))
|
||||||
(rx/map #(handle-pointer-send file-id (:pt %)))))
|
(rx/map #(handle-pointer-send file-id (:pt %)))))
|
||||||
|
|
||||||
(rx/take-until stopper))]
|
(rx/take-until stopper))]
|
||||||
|
@ -197,9 +196,10 @@
|
||||||
[:changes ::cpc/changes]]))
|
[:changes ::cpc/changes]]))
|
||||||
|
|
||||||
(defn handle-file-change
|
(defn handle-file-change
|
||||||
[{:keys [file-id changes] :as msg}]
|
[{:keys [file-id changes revn] :as msg}]
|
||||||
|
|
||||||
(dm/assert!
|
(dm/assert!
|
||||||
"expected valid arguments"
|
"expected valid parameters"
|
||||||
(sm/check! schema:handle-file-change msg))
|
(sm/check! schema:handle-file-change msg))
|
||||||
|
|
||||||
(ptk/reify ::handle-file-change
|
(ptk/reify ::handle-file-change
|
||||||
|
@ -209,15 +209,11 @@
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [page-id (:current-page-id state)
|
(let [page-id (:current-page-id state)
|
||||||
|
|
||||||
position-data-operation?
|
position-data-operation?
|
||||||
(fn [{:keys [type attr]}]
|
(fn [{:keys [type attr]}]
|
||||||
(and (= :set type) (= attr :position-data)))
|
(and (= :set type)
|
||||||
|
(= attr :position-data)))
|
||||||
;;add-origin-session-id
|
|
||||||
;;(fn [{:keys [] :as op}]
|
|
||||||
;; (cond-> op
|
|
||||||
;; (position-data-operation? op)
|
|
||||||
;; (update :val with-meta {:session-id (:session-id msg)})))
|
|
||||||
|
|
||||||
update-position-data
|
update-position-data
|
||||||
(fn [change]
|
(fn [change]
|
||||||
|
@ -228,24 +224,23 @@
|
||||||
(= :mod-obj (:type change)))
|
(= :mod-obj (:type change)))
|
||||||
(update :operations #(d/removev position-data-operation? %))))
|
(update :operations #(d/removev position-data-operation? %))))
|
||||||
|
|
||||||
process-page-changes
|
|
||||||
(fn [[page-id changes]]
|
|
||||||
(dch/update-indices page-id changes))
|
|
||||||
|
|
||||||
;; We update `position-data` from the incoming message
|
;; We update `position-data` from the incoming message
|
||||||
changes (->> changes
|
changes (->> changes
|
||||||
(mapv update-position-data)
|
(map update-position-data)
|
||||||
(d/removev (fn [change]
|
(remove (fn [change]
|
||||||
(and (= page-id (:page-id change))
|
(and (= page-id (:page-id change))
|
||||||
(:ignore-remote? change)))))
|
(:ignore-remote? change))))
|
||||||
|
(vec))]
|
||||||
|
|
||||||
changes-by-pages (group-by :page-id changes)]
|
;; The commit event is responsible to apply the data localy
|
||||||
|
;; and update the persistence internal state with the updated
|
||||||
(rx/merge
|
;; file-revn
|
||||||
(rx/of (dwp/shapes-changes-persisted file-id (assoc msg :changes changes)))
|
(rx/of (dch/commit {:file-id file-id
|
||||||
|
:file-revn revn
|
||||||
(when-not (empty? changes-by-pages)
|
:save-undo? false
|
||||||
(rx/from (map process-page-changes changes-by-pages))))))))
|
:source :remote
|
||||||
|
:redo-changes changes
|
||||||
|
:undo-changes []}))))))
|
||||||
|
|
||||||
(def ^:private
|
(def ^:private
|
||||||
schema:handle-library-change
|
schema:handle-library-change
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.files.changes-builder :as pcb]
|
[app.common.files.changes-builder :as pcb]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.workspace.path.common :refer [check-path-content!]]
|
[app.main.data.workspace.path.common :refer [check-path-content!]]
|
||||||
[app.main.data.workspace.path.helpers :as helpers]
|
[app.main.data.workspace.path.helpers :as helpers]
|
||||||
[app.main.data.workspace.path.state :as st]
|
[app.main.data.workspace.path.state :as st]
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
[app.common.types.shape :as cts]
|
[app.common.types.shape :as cts]
|
||||||
[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.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.drawing.common :as dwdc]
|
[app.main.data.workspace.drawing.common :as dwdc]
|
||||||
[app.main.data.workspace.edition :as dwe]
|
[app.main.data.workspace.edition :as dwe]
|
||||||
[app.main.data.workspace.path.changes :as changes]
|
[app.main.data.workspace.path.changes :as changes]
|
||||||
|
@ -24,6 +23,7 @@
|
||||||
[app.main.data.workspace.path.state :as st]
|
[app.main.data.workspace.path.state :as st]
|
||||||
[app.main.data.workspace.path.streams :as streams]
|
[app.main.data.workspace.path.streams :as streams]
|
||||||
[app.main.data.workspace.path.undo :as undo]
|
[app.main.data.workspace.path.undo :as undo]
|
||||||
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.util.mouse :as mse]
|
[app.util.mouse :as mse]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
|
@ -333,7 +333,7 @@
|
||||||
edit-mode (get-in state [:workspace-local :edit-path id :edit-mode])]
|
edit-mode (get-in state [:workspace-local :edit-path id :edit-mode])]
|
||||||
(if (= :draw edit-mode)
|
(if (= :draw edit-mode)
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of (dch/update-shapes [id] upsp/convert-to-path))
|
(rx/of (dwsh/update-shapes [id] upsp/convert-to-path))
|
||||||
(rx/of (handle-drawing id))
|
(rx/of (handle-drawing id))
|
||||||
(->> stream
|
(->> stream
|
||||||
(rx/filter (ptk/type? ::common/finish-path))
|
(rx/filter (ptk/type? ::common/finish-path))
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
[app.common.svg.path.command :as upc]
|
[app.common.svg.path.command :as upc]
|
||||||
[app.common.svg.path.shapes-to-path :as upsp]
|
[app.common.svg.path.shapes-to-path :as upsp]
|
||||||
[app.common.svg.path.subpath :as ups]
|
[app.common.svg.path.subpath :as ups]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.workspace.edition :as dwe]
|
[app.main.data.workspace.edition :as dwe]
|
||||||
[app.main.data.workspace.path.changes :as changes]
|
[app.main.data.workspace.path.changes :as changes]
|
||||||
[app.main.data.workspace.path.drawing :as drawing]
|
[app.main.data.workspace.path.drawing :as drawing]
|
||||||
|
@ -23,6 +23,7 @@
|
||||||
[app.main.data.workspace.path.state :as st]
|
[app.main.data.workspace.path.state :as st]
|
||||||
[app.main.data.workspace.path.streams :as streams]
|
[app.main.data.workspace.path.streams :as streams]
|
||||||
[app.main.data.workspace.path.undo :as undo]
|
[app.main.data.workspace.path.undo :as undo]
|
||||||
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.main.streams :as ms]
|
[app.main.streams :as ms]
|
||||||
[app.util.mouse :as mse]
|
[app.util.mouse :as mse]
|
||||||
|
@ -143,7 +144,7 @@
|
||||||
selected? (contains? selected-points position)]
|
selected? (contains? selected-points position)]
|
||||||
(streams/drag-stream
|
(streams/drag-stream
|
||||||
(rx/of
|
(rx/of
|
||||||
(dch/update-shapes [id] upsp/convert-to-path)
|
(dwsh/update-shapes [id] upsp/convert-to-path)
|
||||||
(when-not selected? (selection/select-node position shift?))
|
(when-not selected? (selection/select-node position shift?))
|
||||||
(drag-selected-points @ms/mouse-position))
|
(drag-selected-points @ms/mouse-position))
|
||||||
(rx/of (selection/select-node position shift?)))))))
|
(rx/of (selection/select-node position shift?)))))))
|
||||||
|
@ -227,7 +228,7 @@
|
||||||
mov-vec (gpt/multiply (get-displacement direction) scale)]
|
mov-vec (gpt/multiply (get-displacement direction) scale)]
|
||||||
|
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of (dch/update-shapes [id] upsp/convert-to-path))
|
(rx/of (dwsh/update-shapes [id] upsp/convert-to-path))
|
||||||
(rx/merge
|
(rx/merge
|
||||||
(->> move-events
|
(->> move-events
|
||||||
(rx/take-until stopper)
|
(rx/take-until stopper)
|
||||||
|
@ -265,7 +266,7 @@
|
||||||
|
|
||||||
(streams/drag-stream
|
(streams/drag-stream
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of (dch/update-shapes [id] upsp/convert-to-path))
|
(rx/of (dwsh/update-shapes [id] upsp/convert-to-path))
|
||||||
(->> (streams/move-handler-stream handler point handler opposite points)
|
(->> (streams/move-handler-stream handler point handler opposite points)
|
||||||
(rx/map
|
(rx/map
|
||||||
(fn [{:keys [x y alt? shift?]}]
|
(fn [{:keys [x y alt? shift?]}]
|
||||||
|
@ -354,5 +355,5 @@
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [id (st/get-path-id state)]
|
(let [id (st/get-path-id state)]
|
||||||
(rx/of (dch/update-shapes [id] upsp/convert-to-path)
|
(rx/of (dwsh/update-shapes [id] upsp/convert-to-path)
|
||||||
(split-segments event))))))
|
(split-segments event))))))
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
[app.common.files.helpers :as cph]
|
[app.common.files.helpers :as cph]
|
||||||
[app.common.svg.path.shapes-to-path :as upsp]
|
[app.common.svg.path.shapes-to-path :as upsp]
|
||||||
[app.common.types.container :as ctn]
|
[app.common.types.container :as ctn]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
|
|
@ -8,10 +8,11 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.svg.path.shapes-to-path :as upsp]
|
[app.common.svg.path.shapes-to-path :as upsp]
|
||||||
[app.common.svg.path.subpath :as ups]
|
[app.common.svg.path.subpath :as ups]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.workspace.edition :as dwe]
|
[app.main.data.workspace.edition :as dwe]
|
||||||
[app.main.data.workspace.path.changes :as changes]
|
[app.main.data.workspace.path.changes :as changes]
|
||||||
[app.main.data.workspace.path.state :as st]
|
[app.main.data.workspace.path.state :as st]
|
||||||
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.util.path.tools :as upt]
|
[app.util.path.tools :as upt]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
|
@ -37,7 +38,7 @@
|
||||||
changes (changes/generate-path-changes it objects page-id shape (:content shape) new-content)]
|
changes (changes/generate-path-changes it objects page-id shape (:content shape) new-content)]
|
||||||
|
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of (dch/update-shapes [id] upsp/convert-to-path))
|
(rx/of (dwsh/update-shapes [id] upsp/convert-to-path))
|
||||||
(rx/of (dch/commit-changes changes)
|
(rx/of (dch/commit-changes changes)
|
||||||
(when (empty? new-content)
|
(when (empty? new-content)
|
||||||
(dwe/clear-edition-mode)))))))))))
|
(dwe/clear-edition-mode)))))))))))
|
||||||
|
|
|
@ -1,263 +0,0 @@
|
||||||
;; 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.main.data.workspace.persistence
|
|
||||||
(:require
|
|
||||||
[app.common.data.macros :as dm]
|
|
||||||
[app.common.files.changes :as cpc]
|
|
||||||
[app.common.logging :as log]
|
|
||||||
[app.common.types.shape-tree :as ctst]
|
|
||||||
[app.common.uuid :as uuid]
|
|
||||||
[app.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.thumbnails :as dwt]
|
|
||||||
[app.main.features :as features]
|
|
||||||
[app.main.repo :as rp]
|
|
||||||
[app.main.store :as st]
|
|
||||||
[app.util.time :as dt]
|
|
||||||
[beicon.v2.core :as rx]
|
|
||||||
[okulary.core :as l]
|
|
||||||
[potok.v2.core :as ptk]))
|
|
||||||
|
|
||||||
(log/set-level! :info)
|
|
||||||
|
|
||||||
(declare persist-changes)
|
|
||||||
(declare persist-synchronous-changes)
|
|
||||||
(declare shapes-changes-persisted)
|
|
||||||
(declare shapes-changes-persisted-finished)
|
|
||||||
(declare update-persistence-status)
|
|
||||||
|
|
||||||
;; --- Persistence
|
|
||||||
|
|
||||||
(defn initialize-file-persistence
|
|
||||||
[file-id]
|
|
||||||
(ptk/reify ::initialize-persistence
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ _ stream]
|
|
||||||
(log/debug :hint "initialize persistence")
|
|
||||||
(let [stopper (rx/filter (ptk/type? ::initialize-persistence) stream)
|
|
||||||
commits (l/atom [])
|
|
||||||
saving? (l/atom false)
|
|
||||||
|
|
||||||
local-file?
|
|
||||||
#(as-> (:file-id %) event-file-id
|
|
||||||
(or (nil? event-file-id)
|
|
||||||
(= event-file-id file-id)))
|
|
||||||
|
|
||||||
library-file?
|
|
||||||
#(as-> (:file-id %) event-file-id
|
|
||||||
(and (some? event-file-id)
|
|
||||||
(not= event-file-id file-id)))
|
|
||||||
|
|
||||||
on-dirty
|
|
||||||
(fn []
|
|
||||||
;; Enable reload stopper
|
|
||||||
(swap! st/ongoing-tasks conj :workspace-change)
|
|
||||||
(st/emit! (update-persistence-status {:status :pending})))
|
|
||||||
|
|
||||||
on-saving
|
|
||||||
(fn []
|
|
||||||
(reset! saving? true)
|
|
||||||
(st/emit! (update-persistence-status {:status :saving})))
|
|
||||||
|
|
||||||
on-saved
|
|
||||||
(fn []
|
|
||||||
;; Disable reload stopper
|
|
||||||
(swap! st/ongoing-tasks disj :workspace-change)
|
|
||||||
(st/emit! (update-persistence-status {:status :saved}))
|
|
||||||
(reset! saving? false))]
|
|
||||||
|
|
||||||
(rx/merge
|
|
||||||
(->> stream
|
|
||||||
(rx/filter dch/commit-changes?)
|
|
||||||
(rx/map deref)
|
|
||||||
(rx/filter local-file?)
|
|
||||||
(rx/tap on-dirty)
|
|
||||||
(rx/filter (complement empty?))
|
|
||||||
(rx/map (fn [commit]
|
|
||||||
(-> commit
|
|
||||||
(assoc :id (uuid/next))
|
|
||||||
(assoc :file-id file-id))))
|
|
||||||
(rx/observe-on :async)
|
|
||||||
(rx/tap #(swap! commits conj %))
|
|
||||||
(rx/take-until (rx/delay 100 stopper))
|
|
||||||
(rx/finalize (fn []
|
|
||||||
(log/debug :hint "finalize persistence: changes watcher"))))
|
|
||||||
|
|
||||||
(->> (rx/from-atom commits)
|
|
||||||
(rx/filter (complement empty?))
|
|
||||||
(rx/sample-when
|
|
||||||
(rx/merge
|
|
||||||
(rx/filter #(= ::force-persist %) stream)
|
|
||||||
(->> (rx/merge
|
|
||||||
(rx/interval 5000)
|
|
||||||
(->> (rx/from-atom commits)
|
|
||||||
(rx/filter (complement empty?))
|
|
||||||
(rx/debounce 2000)))
|
|
||||||
;; Not sample while saving so there are no race conditions
|
|
||||||
(rx/filter #(not @saving?)))))
|
|
||||||
(rx/tap #(reset! commits []))
|
|
||||||
(rx/tap on-saving)
|
|
||||||
(rx/mapcat (fn [changes]
|
|
||||||
;; NOTE: this is needed for don't start the
|
|
||||||
;; next persistence before this one is
|
|
||||||
;; finished.
|
|
||||||
(if-let [file-revn (dm/get-in @st/state [:workspace-file :revn])]
|
|
||||||
(rx/merge
|
|
||||||
(->> (rx/of (persist-changes file-id file-revn changes commits))
|
|
||||||
(rx/observe-on :async))
|
|
||||||
(->> stream
|
|
||||||
;; We wait for every change to be persisted
|
|
||||||
(rx/filter (ptk/type? ::shapes-changes-persisted-finished))
|
|
||||||
(rx/take 1)
|
|
||||||
(rx/tap on-saved)
|
|
||||||
(rx/ignore)))
|
|
||||||
(rx/empty))))
|
|
||||||
(rx/take-until (rx/delay 100 stopper))
|
|
||||||
(rx/finalize (fn []
|
|
||||||
(log/debug :hint "finalize persistence: save loop"))))
|
|
||||||
|
|
||||||
;; Synchronous changes
|
|
||||||
(->> stream
|
|
||||||
(rx/filter dch/commit-changes?)
|
|
||||||
(rx/map deref)
|
|
||||||
(rx/filter library-file?)
|
|
||||||
(rx/filter (complement #(empty? (:changes %))))
|
|
||||||
(rx/map persist-synchronous-changes)
|
|
||||||
(rx/take-until (rx/delay 100 stopper))
|
|
||||||
(rx/finalize (fn []
|
|
||||||
(log/debug :hint "finalize persistence: synchronous save loop")))))))))
|
|
||||||
|
|
||||||
(defn persist-changes
|
|
||||||
[file-id file-revn changes pending-commits]
|
|
||||||
(log/debug :hint "persist changes" :changes (count changes))
|
|
||||||
(dm/assert! (uuid? file-id))
|
|
||||||
(ptk/reify ::persist-changes
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state _]
|
|
||||||
(let [sid (:session-id state)
|
|
||||||
|
|
||||||
features (features/get-team-enabled-features state)
|
|
||||||
params {:id file-id
|
|
||||||
:revn file-revn
|
|
||||||
:session-id sid
|
|
||||||
:changes-with-metadata (into [] changes)
|
|
||||||
:features features}]
|
|
||||||
|
|
||||||
(->> (rp/cmd! :update-file params)
|
|
||||||
(rx/mapcat (fn [lagged]
|
|
||||||
(log/debug :hint "changes persisted" :lagged (count lagged))
|
|
||||||
(let [frame-updates
|
|
||||||
(-> (group-by :page-id changes)
|
|
||||||
(update-vals #(into #{} (mapcat :frames) %)))
|
|
||||||
|
|
||||||
commits
|
|
||||||
(->> @pending-commits
|
|
||||||
(map #(assoc % :revn file-revn)))]
|
|
||||||
|
|
||||||
(rx/concat
|
|
||||||
(rx/merge
|
|
||||||
(->> (rx/from frame-updates)
|
|
||||||
(rx/mapcat (fn [[page-id frames]]
|
|
||||||
(->> frames (map (fn [frame-id] [file-id page-id frame-id])))))
|
|
||||||
(rx/map (fn [data]
|
|
||||||
(ptk/data-event ::dwt/update data))))
|
|
||||||
|
|
||||||
(->> (rx/from (concat lagged commits))
|
|
||||||
(rx/merge-map
|
|
||||||
(fn [{:keys [changes] :as entry}]
|
|
||||||
(rx/merge
|
|
||||||
(rx/from
|
|
||||||
(for [[page-id changes] (group-by :page-id changes)]
|
|
||||||
(dch/update-indices page-id changes)))
|
|
||||||
(rx/of (shapes-changes-persisted file-id entry)))))))
|
|
||||||
|
|
||||||
(rx/of (shapes-changes-persisted-finished))))))
|
|
||||||
(rx/catch (fn [cause]
|
|
||||||
(if (instance? js/TypeError cause)
|
|
||||||
(->> (rx/timer 2000)
|
|
||||||
(rx/map (fn [_]
|
|
||||||
(persist-changes file-id file-revn changes pending-commits))))
|
|
||||||
(rx/throw cause)))))))))
|
|
||||||
|
|
||||||
;; Event to be thrown after the changes have been persisted
|
|
||||||
(defn shapes-changes-persisted-finished
|
|
||||||
[]
|
|
||||||
(ptk/reify ::shapes-changes-persisted-finished))
|
|
||||||
|
|
||||||
(defn persist-synchronous-changes
|
|
||||||
[{:keys [file-id changes]}]
|
|
||||||
(dm/assert! (uuid? file-id))
|
|
||||||
(ptk/reify ::persist-synchronous-changes
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state _]
|
|
||||||
(let [features (features/get-team-enabled-features state)
|
|
||||||
|
|
||||||
sid (:session-id state)
|
|
||||||
file (dm/get-in state [:workspace-libraries file-id])
|
|
||||||
|
|
||||||
params {:id (:id file)
|
|
||||||
:revn (:revn file)
|
|
||||||
:session-id sid
|
|
||||||
:changes changes
|
|
||||||
:features features}]
|
|
||||||
|
|
||||||
(when (:id params)
|
|
||||||
(->> (rp/cmd! :update-file params)
|
|
||||||
(rx/ignore)))))))
|
|
||||||
|
|
||||||
(defn update-persistence-status
|
|
||||||
[{:keys [status reason]}]
|
|
||||||
(ptk/reify ::update-persistence-status
|
|
||||||
ptk/UpdateEvent
|
|
||||||
(update [_ state]
|
|
||||||
(update state :workspace-persistence
|
|
||||||
(fn [local]
|
|
||||||
(assoc local
|
|
||||||
:reason reason
|
|
||||||
:status status
|
|
||||||
:updated-at (dt/now)))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defn shapes-persisted-event? [event]
|
|
||||||
(= (ptk/type event) ::changes-persisted))
|
|
||||||
|
|
||||||
(defn shapes-changes-persisted
|
|
||||||
[file-id {:keys [revn changes] persisted-session-id :session-id}]
|
|
||||||
(dm/assert! (uuid? file-id))
|
|
||||||
(dm/assert! (int? revn))
|
|
||||||
(dm/assert! (cpc/check-changes! changes))
|
|
||||||
|
|
||||||
(ptk/reify ::shapes-changes-persisted
|
|
||||||
ptk/UpdateEvent
|
|
||||||
(update [_ state]
|
|
||||||
;; NOTE: we don't set the file features context here because
|
|
||||||
;; there are no useful context for code that need to be executed
|
|
||||||
;; on the frontend side
|
|
||||||
(let [current-file-id (:current-file-id state)
|
|
||||||
current-session-id (:session-id state)]
|
|
||||||
(if (and (some? current-file-id)
|
|
||||||
;; If the remote change is from teh current session we skip
|
|
||||||
(not= persisted-session-id current-session-id))
|
|
||||||
(if (= file-id current-file-id)
|
|
||||||
(let [changes (group-by :page-id changes)]
|
|
||||||
(-> state
|
|
||||||
(update-in [:workspace-file :revn] max revn)
|
|
||||||
(update :workspace-data
|
|
||||||
(fn [file]
|
|
||||||
(loop [fdata file
|
|
||||||
entries (seq changes)]
|
|
||||||
(if-let [[page-id changes] (first entries)]
|
|
||||||
(recur (-> fdata
|
|
||||||
(cpc/process-changes changes)
|
|
||||||
(cond-> (some? page-id)
|
|
||||||
(ctst/update-object-indices page-id)))
|
|
||||||
(rest entries))
|
|
||||||
fdata))))))
|
|
||||||
(-> state
|
|
||||||
(update-in [:workspace-libraries file-id :revn] max revn)
|
|
||||||
(update-in [:workspace-libraries file-id :data] cpc/process-changes changes)))
|
|
||||||
|
|
||||||
state)))))
|
|
|
@ -18,9 +18,9 @@
|
||||||
[app.common.record :as cr]
|
[app.common.record :as cr]
|
||||||
[app.common.types.component :as ctk]
|
[app.common.types.component :as ctk]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
[app.main.data.modal :as md]
|
[app.main.data.modal :as md]
|
||||||
[app.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.collapse :as dwc]
|
[app.main.data.workspace.collapse :as dwc]
|
||||||
[app.main.data.workspace.specialized-panel :as-alias dwsp]
|
[app.main.data.workspace.specialized-panel :as-alias dwsp]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
[app.common.types.modifiers :as ctm]
|
[app.common.types.modifiers :as ctm]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
[app.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.colors :as cl]
|
[app.main.data.workspace.colors :as cl]
|
||||||
[app.main.data.workspace.grid-layout.editor :as dwge]
|
[app.main.data.workspace.grid-layout.editor :as dwge]
|
||||||
[app.main.data.workspace.modifiers :as dwm]
|
[app.main.data.workspace.modifiers :as dwm]
|
||||||
|
@ -148,8 +148,8 @@
|
||||||
layout-initializer (get-layout-initializer type from-frame? calculate-params?)]
|
layout-initializer (get-layout-initializer type from-frame? calculate-params?)]
|
||||||
|
|
||||||
(rx/of (dwu/start-undo-transaction undo-id)
|
(rx/of (dwu/start-undo-transaction undo-id)
|
||||||
(dch/update-shapes [id] layout-initializer {:with-objects? true})
|
(dwsh/update-shapes [id] layout-initializer {:with-objects? true})
|
||||||
(dch/update-shapes (dm/get-prop parent :shapes) #(dissoc % :constraints-h :constraints-v))
|
(dwsh/update-shapes (dm/get-prop parent :shapes) #(dissoc % :constraints-h :constraints-v))
|
||||||
(ptk/data-event :layout/update {:ids [id]})
|
(ptk/data-event :layout/update {:ids [id]})
|
||||||
(dwu/commit-undo-transaction undo-id))))))
|
(dwu/commit-undo-transaction undo-id))))))
|
||||||
|
|
||||||
|
@ -188,8 +188,8 @@
|
||||||
(dwsh/create-artboard-from-selection new-shape-id parent-id group-index (:name (first selected-shapes)))
|
(dwsh/create-artboard-from-selection new-shape-id parent-id group-index (:name (first selected-shapes)))
|
||||||
(cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1})
|
(cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1})
|
||||||
(create-layout-from-id new-shape-id type)
|
(create-layout-from-id new-shape-id type)
|
||||||
(dch/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto))
|
(dwsh/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto))
|
||||||
(dch/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix))
|
(dwsh/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix))
|
||||||
(dwsh/delete-shapes page-id selected)
|
(dwsh/delete-shapes page-id selected)
|
||||||
(ptk/data-event :layout/update {:ids [new-shape-id]})
|
(ptk/data-event :layout/update {:ids [new-shape-id]})
|
||||||
(dwu/commit-undo-transaction undo-id)))
|
(dwu/commit-undo-transaction undo-id)))
|
||||||
|
@ -199,8 +199,8 @@
|
||||||
(dwsh/create-artboard-from-selection new-shape-id)
|
(dwsh/create-artboard-from-selection new-shape-id)
|
||||||
(cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1})
|
(cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1})
|
||||||
(create-layout-from-id new-shape-id type)
|
(create-layout-from-id new-shape-id type)
|
||||||
(dch/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto))
|
(dwsh/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto))
|
||||||
(dch/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix))))
|
(dwsh/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix))))
|
||||||
|
|
||||||
(rx/of (ptk/data-event :layout/update {:ids [new-shape-id]})
|
(rx/of (ptk/data-event :layout/update {:ids [new-shape-id]})
|
||||||
(dwu/commit-undo-transaction undo-id)))))))
|
(dwu/commit-undo-transaction undo-id)))))))
|
||||||
|
@ -213,7 +213,7 @@
|
||||||
(let [undo-id (js/Symbol)]
|
(let [undo-id (js/Symbol)]
|
||||||
(rx/of
|
(rx/of
|
||||||
(dwu/start-undo-transaction undo-id)
|
(dwu/start-undo-transaction undo-id)
|
||||||
(dch/update-shapes ids #(apply dissoc % layout-keys))
|
(dwsh/update-shapes ids #(apply dissoc % layout-keys))
|
||||||
(ptk/data-event :layout/update {:ids ids})
|
(ptk/data-event :layout/update {:ids ids})
|
||||||
(dwu/commit-undo-transaction undo-id))))))
|
(dwu/commit-undo-transaction undo-id))))))
|
||||||
|
|
||||||
|
@ -266,7 +266,7 @@
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(let [undo-id (js/Symbol)]
|
(let [undo-id (js/Symbol)]
|
||||||
(rx/of (dwu/start-undo-transaction undo-id)
|
(rx/of (dwu/start-undo-transaction undo-id)
|
||||||
(dch/update-shapes ids (d/patch-object changes))
|
(dwsh/update-shapes ids (d/patch-object changes))
|
||||||
(ptk/data-event :layout/update {:ids ids})
|
(ptk/data-event :layout/update {:ids ids})
|
||||||
(dwu/commit-undo-transaction undo-id))))))
|
(dwu/commit-undo-transaction undo-id))))))
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(let [undo-id (js/Symbol)]
|
(let [undo-id (js/Symbol)]
|
||||||
(rx/of (dwu/start-undo-transaction undo-id)
|
(rx/of (dwu/start-undo-transaction undo-id)
|
||||||
(dch/update-shapes
|
(dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(case type
|
(case type
|
||||||
|
@ -313,7 +313,7 @@
|
||||||
(if shapes-to-delete
|
(if shapes-to-delete
|
||||||
(dwsh/delete-shapes shapes-to-delete)
|
(dwsh/delete-shapes shapes-to-delete)
|
||||||
(rx/empty))
|
(rx/empty))
|
||||||
(dch/update-shapes
|
(dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
(fn [shape objects]
|
(fn [shape objects]
|
||||||
(case type
|
(case type
|
||||||
|
@ -387,7 +387,7 @@
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(let [undo-id (js/Symbol)]
|
(let [undo-id (js/Symbol)]
|
||||||
(rx/of (dwu/start-undo-transaction undo-id)
|
(rx/of (dwu/start-undo-transaction undo-id)
|
||||||
(dch/update-shapes
|
(dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(case type
|
(case type
|
||||||
|
@ -433,7 +433,7 @@
|
||||||
:row :layout-grid-rows
|
:row :layout-grid-rows
|
||||||
:column :layout-grid-columns)]
|
:column :layout-grid-columns)]
|
||||||
(rx/of (dwu/start-undo-transaction undo-id)
|
(rx/of (dwu/start-undo-transaction undo-id)
|
||||||
(dch/update-shapes
|
(dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(-> shape
|
(-> shape
|
||||||
|
@ -525,9 +525,9 @@
|
||||||
parent-ids (->> ids (map #(cfh/get-parent-id objects %)))
|
parent-ids (->> ids (map #(cfh/get-parent-id objects %)))
|
||||||
undo-id (js/Symbol)]
|
undo-id (js/Symbol)]
|
||||||
(rx/of (dwu/start-undo-transaction undo-id)
|
(rx/of (dwu/start-undo-transaction undo-id)
|
||||||
(dch/update-shapes ids (d/patch-object changes))
|
(dwsh/update-shapes ids (d/patch-object changes))
|
||||||
(dch/update-shapes children-ids (partial fix-child-sizing objects changes))
|
(dwsh/update-shapes children-ids (partial fix-child-sizing objects changes))
|
||||||
(dch/update-shapes
|
(dwsh/update-shapes
|
||||||
parent-ids
|
parent-ids
|
||||||
(fn [parent objects]
|
(fn [parent objects]
|
||||||
(-> parent
|
(-> parent
|
||||||
|
@ -546,8 +546,7 @@
|
||||||
(let [undo-id (js/Symbol)]
|
(let [undo-id (js/Symbol)]
|
||||||
(rx/of
|
(rx/of
|
||||||
(dwu/start-undo-transaction undo-id)
|
(dwu/start-undo-transaction undo-id)
|
||||||
|
(dwsh/update-shapes
|
||||||
(dch/update-shapes
|
|
||||||
[layout-id]
|
[layout-id]
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(->> ids
|
(->> ids
|
||||||
|
@ -570,7 +569,7 @@
|
||||||
(let [undo-id (js/Symbol)]
|
(let [undo-id (js/Symbol)]
|
||||||
(rx/of
|
(rx/of
|
||||||
(dwu/start-undo-transaction undo-id)
|
(dwu/start-undo-transaction undo-id)
|
||||||
(dch/update-shapes
|
(dwsh/update-shapes
|
||||||
[layout-id]
|
[layout-id]
|
||||||
(fn [shape objects]
|
(fn [shape objects]
|
||||||
(case mode
|
(case mode
|
||||||
|
@ -636,7 +635,7 @@
|
||||||
(let [undo-id (js/Symbol)]
|
(let [undo-id (js/Symbol)]
|
||||||
(rx/of
|
(rx/of
|
||||||
(dwu/start-undo-transaction undo-id)
|
(dwu/start-undo-transaction undo-id)
|
||||||
(dch/update-shapes
|
(dwsh/update-shapes
|
||||||
[layout-id]
|
[layout-id]
|
||||||
(fn [shape objects]
|
(fn [shape objects]
|
||||||
(let [cells (->> ids (map #(get-in shape [:layout-grid-cells %])))
|
(let [cells (->> ids (map #(get-in shape [:layout-grid-cells %])))
|
||||||
|
@ -668,7 +667,7 @@
|
||||||
(let [undo-id (js/Symbol)]
|
(let [undo-id (js/Symbol)]
|
||||||
(rx/of
|
(rx/of
|
||||||
(dwu/start-undo-transaction undo-id)
|
(dwu/start-undo-transaction undo-id)
|
||||||
(dch/update-shapes
|
(dwsh/update-shapes
|
||||||
[layout-id]
|
[layout-id]
|
||||||
(fn [shape objects]
|
(fn [shape objects]
|
||||||
(let [prev-data (-> (dm/get-in shape [:layout-grid-cells cell-id])
|
(let [prev-data (-> (dm/get-in shape [:layout-grid-cells cell-id])
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
[app.common.types.container :as ctn]
|
[app.common.types.container :as ctn]
|
||||||
[app.common.types.shape :as cts]
|
[app.common.types.shape :as cts]
|
||||||
[app.common.types.shape-tree :as ctst]
|
[app.common.types.shape-tree :as ctst]
|
||||||
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.comments :as dc]
|
[app.main.data.comments :as dc]
|
||||||
[app.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.edition :as dwe]
|
[app.main.data.workspace.edition :as dwe]
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
|
@ -26,6 +26,74 @@
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
|
(def ^:private update-layout-attr? #{:hidden})
|
||||||
|
|
||||||
|
(defn- add-undo-group
|
||||||
|
[changes state]
|
||||||
|
(let [undo (:workspace-undo state)
|
||||||
|
items (:items undo)
|
||||||
|
index (or (:index undo) (dec (count items)))
|
||||||
|
prev-item (when-not (or (empty? items) (= index -1))
|
||||||
|
(get items index))
|
||||||
|
undo-group (:undo-group prev-item)
|
||||||
|
add-undo-group? (and
|
||||||
|
(not (nil? undo-group))
|
||||||
|
(= (get-in changes [:redo-changes 0 :type]) :mod-obj)
|
||||||
|
(= (get-in prev-item [:redo-changes 0 :type]) :add-obj)
|
||||||
|
(contains? (:tags prev-item) :alt-duplication))] ;; This is a copy-and-move with mouse+alt
|
||||||
|
|
||||||
|
(cond-> changes add-undo-group? (assoc :undo-group undo-group))))
|
||||||
|
|
||||||
|
(defn update-shapes
|
||||||
|
([ids update-fn] (update-shapes ids update-fn nil))
|
||||||
|
([ids update-fn {:keys [reg-objects? save-undo? stack-undo? attrs ignore-tree page-id ignore-remote? ignore-touched undo-group with-objects?]
|
||||||
|
:or {reg-objects? false save-undo? true stack-undo? false ignore-remote? false ignore-touched false with-objects? false}}]
|
||||||
|
|
||||||
|
(dm/assert!
|
||||||
|
"expected a valid coll of uuid's"
|
||||||
|
(sm/check-coll-of-uuid! ids))
|
||||||
|
|
||||||
|
(dm/assert! (fn? update-fn))
|
||||||
|
|
||||||
|
(ptk/reify ::update-shapes
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [it state _]
|
||||||
|
(let [page-id (or page-id (:current-page-id state))
|
||||||
|
objects (wsh/lookup-page-objects state page-id)
|
||||||
|
ids (into [] (filter some?) ids)
|
||||||
|
|
||||||
|
update-layout-ids
|
||||||
|
(->> ids
|
||||||
|
(map (d/getf objects))
|
||||||
|
(filter #(some update-layout-attr? (pcb/changed-attrs % objects update-fn {:attrs attrs :with-objects? with-objects?})))
|
||||||
|
(map :id))
|
||||||
|
|
||||||
|
changes (-> (pcb/empty-changes it page-id)
|
||||||
|
(pcb/set-save-undo? save-undo?)
|
||||||
|
(pcb/set-stack-undo? stack-undo?)
|
||||||
|
(cls/generate-update-shapes ids
|
||||||
|
update-fn
|
||||||
|
objects
|
||||||
|
{:attrs attrs
|
||||||
|
:ignore-tree ignore-tree
|
||||||
|
:ignore-touched ignore-touched
|
||||||
|
:with-objects? with-objects?})
|
||||||
|
(cond-> undo-group
|
||||||
|
(pcb/set-undo-group undo-group)))
|
||||||
|
|
||||||
|
changes (add-undo-group changes state)]
|
||||||
|
(rx/concat
|
||||||
|
(if (seq (:redo-changes changes))
|
||||||
|
(let [changes (cond-> changes reg-objects? (pcb/resize-parents ids))
|
||||||
|
changes (cond-> changes ignore-remote? (pcb/ignore-remote))]
|
||||||
|
(rx/of (dch/commit-changes changes)))
|
||||||
|
(rx/empty))
|
||||||
|
|
||||||
|
;; Update layouts for properties marked
|
||||||
|
(if (d/not-empty? update-layout-ids)
|
||||||
|
(rx/of (ptk/data-event :layout/update {:ids update-layout-ids}))
|
||||||
|
(rx/empty))))))))
|
||||||
|
|
||||||
(defn add-shape
|
(defn add-shape
|
||||||
([shape]
|
([shape]
|
||||||
(add-shape shape {}))
|
(add-shape shape {}))
|
||||||
|
@ -227,7 +295,7 @@
|
||||||
ids (if (boolean? blocked)
|
ids (if (boolean? blocked)
|
||||||
(into ids (->> ids (mapcat #(cfh/get-children-ids objects %))))
|
(into ids (->> ids (mapcat #(cfh/get-children-ids objects %))))
|
||||||
ids)]
|
ids)]
|
||||||
(rx/of (dch/update-shapes ids update-fn {:attrs #{:blocked :hidden} :undo-group undo-group}))))))
|
(rx/of (update-shapes ids update-fn {:attrs #{:blocked :hidden} :undo-group undo-group}))))))
|
||||||
|
|
||||||
(defn toggle-visibility-selected
|
(defn toggle-visibility-selected
|
||||||
[]
|
[]
|
||||||
|
@ -235,7 +303,7 @@
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [selected (wsh/lookup-selected state)]
|
(let [selected (wsh/lookup-selected state)]
|
||||||
(rx/of (dch/update-shapes selected #(update % :hidden not)))))))
|
(rx/of (update-shapes selected #(update % :hidden not)))))))
|
||||||
|
|
||||||
(defn toggle-lock-selected
|
(defn toggle-lock-selected
|
||||||
[]
|
[]
|
||||||
|
@ -243,7 +311,7 @@
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [selected (wsh/lookup-selected state)]
|
(let [selected (wsh/lookup-selected state)]
|
||||||
(rx/of (dch/update-shapes selected #(update % :blocked not)))))))
|
(rx/of (update-shapes selected #(update % :blocked not)))))))
|
||||||
|
|
||||||
|
|
||||||
;; FIXME: this need to be refactored
|
;; FIXME: this need to be refactored
|
||||||
|
@ -273,8 +341,8 @@
|
||||||
(map (partial vector id)))))))
|
(map (partial vector id)))))))
|
||||||
(d/group-by first second)
|
(d/group-by first second)
|
||||||
(map (fn [[page-id frame-ids]]
|
(map (fn [[page-id frame-ids]]
|
||||||
(dch/update-shapes frame-ids #(dissoc % :use-for-thumbnail) {:page-id page-id})))))
|
(update-shapes frame-ids #(dissoc % :use-for-thumbnail) {:page-id page-id})))))
|
||||||
|
|
||||||
;; And finally: toggle the flag value on all the selected shapes
|
;; And finally: toggle the flag value on all the selected shapes
|
||||||
(rx/of (dch/update-shapes selected #(update % :use-for-thumbnail not))
|
(rx/of (update-shapes selected #(update % :use-for-thumbnail not))
|
||||||
(dwu/commit-undo-transaction undo-id)))))))
|
(dwu/commit-undo-transaction undo-id)))))))
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
[app.main.data.users :as du]
|
[app.main.data.users :as du]
|
||||||
[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.drawing :as dwd]
|
[app.main.data.workspace.drawing :as dwd]
|
||||||
[app.main.data.workspace.layers :as dwly]
|
[app.main.data.workspace.layers :as dwly]
|
||||||
[app.main.data.workspace.libraries :as dwl]
|
[app.main.data.workspace.libraries :as dwl]
|
||||||
|
@ -51,12 +50,12 @@
|
||||||
:undo {:tooltip (ds/meta "Z")
|
:undo {:tooltip (ds/meta "Z")
|
||||||
:command (ds/c-mod "z")
|
:command (ds/c-mod "z")
|
||||||
:subsections [:edit]
|
:subsections [:edit]
|
||||||
:fn #(emit-when-no-readonly dwc/undo)}
|
:fn #(emit-when-no-readonly dwu/undo)}
|
||||||
|
|
||||||
:redo {:tooltip (ds/meta "Y")
|
:redo {:tooltip (ds/meta "Y")
|
||||||
:command [(ds/c-mod "shift+z") (ds/c-mod "y")]
|
:command [(ds/c-mod "shift+z") (ds/c-mod "y")]
|
||||||
:subsections [:edit]
|
:subsections [:edit]
|
||||||
:fn #(emit-when-no-readonly dwc/redo)}
|
:fn #(emit-when-no-readonly dwu/redo)}
|
||||||
|
|
||||||
:clear-undo {:tooltip (ds/alt "Q")
|
:clear-undo {:tooltip (ds/alt "Q")
|
||||||
:command "alt+q"
|
:command "alt+q"
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
[app.common.svg.shapes-builder :as csvg.shapes-builder]
|
[app.common.svg.shapes-builder :as csvg.shapes-builder]
|
||||||
[app.common.types.shape-tree :as ctst]
|
[app.common.types.shape-tree :as ctst]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.main.data.workspace.undo :as dwu]
|
[app.main.data.workspace.undo :as dwu]
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
[app.common.types.modifiers :as ctm]
|
[app.common.types.modifiers :as ctm]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
[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.libraries :as dwl]
|
[app.main.data.workspace.libraries :as dwl]
|
||||||
[app.main.data.workspace.modifiers :as dwm]
|
[app.main.data.workspace.modifiers :as dwm]
|
||||||
|
@ -93,7 +92,7 @@
|
||||||
(some? (:current-page-id state))
|
(some? (:current-page-id state))
|
||||||
(some? shape))
|
(some? shape))
|
||||||
(rx/of
|
(rx/of
|
||||||
(dch/update-shapes
|
(dwsh/update-shapes
|
||||||
[id]
|
[id]
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(let [{:keys [width height position-data]} modifiers]
|
(let [{:keys [width height position-data]} modifiers]
|
||||||
|
@ -230,7 +229,7 @@
|
||||||
shape-ids (cond (cfh/text-shape? shape) [id]
|
shape-ids (cond (cfh/text-shape? shape) [id]
|
||||||
(cfh/group-shape? shape) (cfh/get-children-ids objects id))]
|
(cfh/group-shape? shape) (cfh/get-children-ids objects id))]
|
||||||
|
|
||||||
(rx/of (dch/update-shapes shape-ids update-fn))))))
|
(rx/of (dwsh/update-shapes shape-ids update-fn))))))
|
||||||
|
|
||||||
(defn update-paragraph-attrs
|
(defn update-paragraph-attrs
|
||||||
[{:keys [id attrs]}]
|
[{:keys [id attrs]}]
|
||||||
|
@ -257,7 +256,7 @@
|
||||||
(cfh/text-shape? shape) [id]
|
(cfh/text-shape? shape) [id]
|
||||||
(cfh/group-shape? shape) (cfh/get-children-ids objects id))]
|
(cfh/group-shape? shape) (cfh/get-children-ids objects id))]
|
||||||
|
|
||||||
(rx/of (dch/update-shapes shape-ids update-fn))))))))
|
(rx/of (dwsh/update-shapes shape-ids update-fn))))))))
|
||||||
|
|
||||||
(defn update-text-attrs
|
(defn update-text-attrs
|
||||||
[{:keys [id attrs]}]
|
[{:keys [id attrs]}]
|
||||||
|
@ -277,7 +276,7 @@
|
||||||
shape-ids (cond
|
shape-ids (cond
|
||||||
(cfh/text-shape? shape) [id]
|
(cfh/text-shape? shape) [id]
|
||||||
(cfh/group-shape? shape) (cfh/get-children-ids objects id))]
|
(cfh/group-shape? shape) (cfh/get-children-ids objects id))]
|
||||||
(rx/of (dch/update-shapes shape-ids #(update-text-content % update-node? d/txt-merge attrs))))))))
|
(rx/of (dwsh/update-shapes shape-ids #(update-text-content % update-node? d/txt-merge attrs))))))))
|
||||||
|
|
||||||
|
|
||||||
(defn migrate-node
|
(defn migrate-node
|
||||||
|
@ -337,7 +336,7 @@
|
||||||
(dissoc :fills)
|
(dissoc :fills)
|
||||||
(d/update-when :content update-content)))]
|
(d/update-when :content update-content)))]
|
||||||
|
|
||||||
(rx/of (dch/update-shapes shape-ids update-shape)))))))
|
(rx/of (dwsh/update-shapes shape-ids update-shape)))))))
|
||||||
|
|
||||||
;; --- RESIZE UTILS
|
;; --- RESIZE UTILS
|
||||||
|
|
||||||
|
@ -390,10 +389,10 @@
|
||||||
|
|
||||||
(let [ids (into #{} (filter changed-text?) (keys props))]
|
(let [ids (into #{} (filter changed-text?) (keys props))]
|
||||||
(rx/of (dwu/start-undo-transaction undo-id)
|
(rx/of (dwu/start-undo-transaction undo-id)
|
||||||
(dch/update-shapes ids update-fn {:reg-objects? true
|
(dwsh/update-shapes ids update-fn {:reg-objects? true
|
||||||
:stack-undo? true
|
:stack-undo? true
|
||||||
:ignore-remote? true
|
:ignore-remote? true
|
||||||
:ignore-touched true})
|
:ignore-touched true})
|
||||||
(ptk/data-event :layout/update {:ids ids})
|
(ptk/data-event :layout/update {:ids ids})
|
||||||
(dwu/commit-undo-transaction undo-id))))))))
|
(dwu/commit-undo-transaction undo-id))))))))
|
||||||
|
|
||||||
|
@ -532,7 +531,7 @@
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [position-data (::update-position-data state)]
|
(let [position-data (::update-position-data state)]
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of (dch/update-shapes
|
(rx/of (dwsh/update-shapes
|
||||||
(keys position-data)
|
(keys position-data)
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(-> shape
|
(-> shape
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
[app.common.files.helpers :as cfh]
|
[app.common.files.helpers :as cfh]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.thumbnails :as thc]
|
[app.common.thumbnails :as thc]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.changes :as dch]
|
||||||
|
[app.main.data.persistence :as-alias dps]
|
||||||
[app.main.data.workspace.notifications :as-alias wnt]
|
[app.main.data.workspace.notifications :as-alias wnt]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.main.rasterizer :as thr]
|
[app.main.rasterizer :as thr]
|
||||||
|
@ -24,9 +25,10 @@
|
||||||
[app.util.timers :as tm]
|
[app.util.timers :as tm]
|
||||||
[app.util.webapi :as wapi]
|
[app.util.webapi :as wapi]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
|
[cuerdas.core :as str]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
(l/set-level! :info)
|
(l/set-level! :warn)
|
||||||
|
|
||||||
(declare update-thumbnail)
|
(declare update-thumbnail)
|
||||||
|
|
||||||
|
@ -65,10 +67,9 @@
|
||||||
ptk/EffectEvent
|
ptk/EffectEvent
|
||||||
(effect [_ _ _]
|
(effect [_ _ _]
|
||||||
(l/dbg :hint "request thumbnail" :requester requester :file-id file-id :page-id page-id :shape-id shape-id :tag tag)
|
(l/dbg :hint "request thumbnail" :requester requester :file-id file-id :page-id page-id :shape-id shape-id :tag tag)
|
||||||
(q/enqueue-unique
|
(q/enqueue-unique queue
|
||||||
queue
|
(create-request file-id page-id shape-id tag)
|
||||||
(create-request file-id page-id shape-id tag)
|
(partial find-request file-id page-id shape-id tag))))))
|
||||||
(partial find-request file-id page-id shape-id tag))))))
|
|
||||||
|
|
||||||
;; This function first renders the HTML calling `render/render-frame` that
|
;; This function first renders the HTML calling `render/render-frame` that
|
||||||
;; returns HTML as a string, then we send that data to the iframe rasterizer
|
;; returns HTML as a string, then we send that data to the iframe rasterizer
|
||||||
|
@ -92,24 +93,36 @@
|
||||||
|
|
||||||
(defn clear-thumbnail
|
(defn clear-thumbnail
|
||||||
([file-id page-id frame-id tag]
|
([file-id page-id frame-id tag]
|
||||||
(clear-thumbnail (thc/fmt-object-id file-id page-id frame-id tag)))
|
(clear-thumbnail file-id (thc/fmt-object-id file-id page-id frame-id tag)))
|
||||||
([object-id]
|
([file-id object-id]
|
||||||
(let [emit-rpc? (volatile! false)]
|
(let [pending (volatile! false)]
|
||||||
(ptk/reify ::clear-thumbnail
|
(ptk/reify ::clear-thumbnail
|
||||||
cljs.core/IDeref
|
cljs.core/IDeref
|
||||||
(-deref [_] object-id)
|
(-deref [_] object-id)
|
||||||
|
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [uri (dm/get-in state [:workspace-thumbnails object-id])]
|
(update state :workspace-thumbnails
|
||||||
(if (some? uri)
|
(fn [thumbs]
|
||||||
(do
|
(if-let [uri (get thumbs object-id)]
|
||||||
(l/dbg :hint "clear thumbnail" :object-id object-id)
|
(do (vreset! pending uri)
|
||||||
(vreset! emit-rpc? true)
|
(dissoc thumbs object-id))
|
||||||
(tm/schedule-on-idle (partial wapi/revoke-uri uri))
|
thumbs))))
|
||||||
(update state :workspace-thumbnails dissoc object-id))
|
|
||||||
|
|
||||||
state)))))))
|
ptk/WatchEvent
|
||||||
|
(watch [_ _ _]
|
||||||
|
(if-let [uri @pending]
|
||||||
|
(do
|
||||||
|
(l/trc :hint "clear-thumbnail" :uri uri)
|
||||||
|
(when (str/starts-with? uri "blob:")
|
||||||
|
(tm/schedule-on-idle (partial wapi/revoke-uri uri)))
|
||||||
|
|
||||||
|
(let [params {:file-id file-id
|
||||||
|
:object-id object-id}]
|
||||||
|
(->> (rp/cmd! :delete-file-object-thumbnail params)
|
||||||
|
(rx/catch rx/empty)
|
||||||
|
(rx/ignore))))
|
||||||
|
(rx/empty)))))))
|
||||||
|
|
||||||
(defn- assoc-thumbnail
|
(defn- assoc-thumbnail
|
||||||
[object-id uri]
|
[object-id uri]
|
||||||
|
@ -181,7 +194,7 @@
|
||||||
(defn- extract-root-frame-changes
|
(defn- extract-root-frame-changes
|
||||||
"Process a changes set in a commit to extract the frames that are changing"
|
"Process a changes set in a commit to extract the frames that are changing"
|
||||||
[page-id [event [old-data new-data]]]
|
[page-id [event [old-data new-data]]]
|
||||||
(let [changes (-> event deref :changes)
|
(let [changes (:changes event)
|
||||||
|
|
||||||
extract-ids
|
extract-ids
|
||||||
(fn [{:keys [page-id type] :as change}]
|
(fn [{:keys [page-id type] :as change}]
|
||||||
|
@ -239,58 +252,53 @@
|
||||||
(rx/buffer 2 1)
|
(rx/buffer 2 1)
|
||||||
(rx/share))
|
(rx/share))
|
||||||
|
|
||||||
local-changes-s
|
;; All commits stream, indepentendly of the source of the commit
|
||||||
|
all-commits-s
|
||||||
(->> stream
|
(->> stream
|
||||||
(rx/filter dch/commit-changes?)
|
(rx/filter dch/commit?)
|
||||||
(rx/with-latest-from workspace-data-s)
|
(rx/map deref)
|
||||||
(rx/merge-map (partial extract-root-frame-changes page-id))
|
|
||||||
(rx/tap #(l/trc :hint "incoming change" :origin "local" :frame-id (dm/str %))))
|
|
||||||
|
|
||||||
notification-changes-s
|
|
||||||
(->> stream
|
|
||||||
(rx/filter (ptk/type? ::wnt/handle-file-change))
|
|
||||||
(rx/observe-on :async)
|
(rx/observe-on :async)
|
||||||
(rx/with-latest-from workspace-data-s)
|
(rx/with-latest-from workspace-data-s)
|
||||||
(rx/merge-map (partial extract-root-frame-changes page-id))
|
(rx/merge-map (partial extract-root-frame-changes page-id))
|
||||||
(rx/tap #(l/trc :hint "incoming change" :origin "notifications" :frame-id (dm/str %))))
|
(rx/tap #(l/trc :hint "inconming change" :origin "local" :frame-id (dm/str %)))
|
||||||
|
|
||||||
persistence-changes-s
|
|
||||||
(->> stream
|
|
||||||
(rx/filter (ptk/type? ::update))
|
|
||||||
(rx/map deref)
|
|
||||||
(rx/filter (fn [[file-id page-id]]
|
|
||||||
(and (= file-id file-id)
|
|
||||||
(= page-id page-id))))
|
|
||||||
(rx/map (fn [[_ _ frame-id]] frame-id))
|
|
||||||
(rx/tap #(l/trc :hint "incoming change" :origin "persistence" :frame-id (dm/str %))))
|
|
||||||
|
|
||||||
all-changes-s
|
|
||||||
(->> (rx/merge
|
|
||||||
;; LOCAL CHANGES
|
|
||||||
local-changes-s
|
|
||||||
;; NOTIFICATIONS CHANGES
|
|
||||||
notification-changes-s
|
|
||||||
;; PERSISTENCE CHANGES
|
|
||||||
persistence-changes-s)
|
|
||||||
|
|
||||||
(rx/share))
|
(rx/share))
|
||||||
|
|
||||||
;; BUFFER NOTIFIER (window of 5s of inactivity)
|
local-commits-s
|
||||||
|
(->> stream
|
||||||
|
(rx/filter dch/commit?)
|
||||||
|
(rx/map deref)
|
||||||
|
(rx/filter #(= :local (:source %)))
|
||||||
|
(rx/observe-on :async)
|
||||||
|
(rx/with-latest-from workspace-data-s)
|
||||||
|
(rx/merge-map (partial extract-root-frame-changes page-id))
|
||||||
|
(rx/tap #(l/trc :hint "inconming change" :origin "local" :frame-id (dm/str %)))
|
||||||
|
(rx/share))
|
||||||
|
|
||||||
|
;; BUFFER NOTIFIER: only on local changes, remote changes
|
||||||
|
;; we expect to receive thumbnail uri once it is
|
||||||
|
;; generated va notifications subsystem
|
||||||
notifier-s
|
notifier-s
|
||||||
(->> all-changes-s
|
(->> stream
|
||||||
(rx/debounce 1000)
|
(rx/filter (ptk/type? ::dps/commit-persisted))
|
||||||
|
(rx/map deref)
|
||||||
|
(rx/observe-on :async)
|
||||||
|
(rx/with-latest-from workspace-data-s)
|
||||||
|
(rx/merge-map (partial extract-root-frame-changes page-id))
|
||||||
|
(rx/tap #(l/trc :hint "inconming change" :origin "local" :frame-id (dm/str %)))
|
||||||
|
(rx/debounce 5000)
|
||||||
(rx/tap #(l/trc :hint "buffer initialized")))]
|
(rx/tap #(l/trc :hint "buffer initialized")))]
|
||||||
|
|
||||||
(->> (rx/merge
|
(->> (rx/merge
|
||||||
;; Perform instant thumbnail cleaning of affected frames
|
;; Perform instant thumbnail cleaning of affected frames
|
||||||
;; and interrupt any ongoing update-thumbnail process
|
;; and interrupt any ongoing update-thumbnail process
|
||||||
;; related to current frame-id
|
;; related to current frame-id
|
||||||
(->> all-changes-s
|
(->> all-commits-s
|
||||||
(rx/map #(clear-thumbnail file-id page-id % "frame")))
|
(rx/map (fn [frame-id]
|
||||||
|
(clear-thumbnail file-id page-id frame-id "frame"))))
|
||||||
|
|
||||||
;; Generate thumbnails in batchs, once user becomes
|
;; Generate thumbnails in batchs, once user becomes
|
||||||
;; inactive for some instant
|
;; inactive for some instant only for local changes
|
||||||
(->> all-changes-s
|
(->> local-commits-s
|
||||||
(rx/buffer-until notifier-s)
|
(rx/buffer-until notifier-s)
|
||||||
(rx/mapcat #(into #{} %))
|
(rx/mapcat #(into #{} %))
|
||||||
(rx/map #(request-thumbnail file-id page-id % "frame" "watch-state-changes"))))
|
(rx/map #(request-thumbnail file-id page-id % "frame" "watch-state-changes"))))
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
[app.common.types.modifiers :as ctm]
|
[app.common.types.modifiers :as ctm]
|
||||||
[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.main.data.workspace.changes :as dch]
|
[app.main.data.changes :as dch]
|
||||||
[app.main.data.workspace.collapse :as dwc]
|
[app.main.data.workspace.collapse :as dwc]
|
||||||
[app.main.data.workspace.modifiers :as dwm]
|
[app.main.data.workspace.modifiers :as dwm]
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
|
|
|
@ -11,18 +11,18 @@
|
||||||
[app.common.files.changes :as cpc]
|
[app.common.files.changes :as cpc]
|
||||||
[app.common.logging :as log]
|
[app.common.logging :as log]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
|
[app.common.types.shape.layout :as ctl]
|
||||||
|
[app.main.data.changes :as dch]
|
||||||
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
|
[app.util.router :as rt]
|
||||||
[app.util.time :as dt]
|
[app.util.time :as dt]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
(def discard-transaction-time-millis (* 20 1000))
|
|
||||||
|
|
||||||
;; Change this to :info :debug or :trace to debug this module
|
;; Change this to :info :debug or :trace to debug this module
|
||||||
(log/set-level! :warn)
|
(log/set-level! :warn)
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
(def discard-transaction-time-millis (* 20 1000))
|
||||||
;; Undo / Redo
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
(def ^:private
|
(def ^:private
|
||||||
schema:undo-entry
|
schema:undo-entry
|
||||||
|
@ -44,7 +44,6 @@
|
||||||
(subvec undo (- cnt MAX-UNDO-SIZE))
|
(subvec undo (- cnt MAX-UNDO-SIZE))
|
||||||
undo)))
|
undo)))
|
||||||
|
|
||||||
;; TODO: Review the necessity of this method
|
|
||||||
(defn materialize-undo
|
(defn materialize-undo
|
||||||
[_changes index]
|
[_changes index]
|
||||||
(ptk/reify ::materialize-undo
|
(ptk/reify ::materialize-undo
|
||||||
|
@ -84,8 +83,7 @@
|
||||||
(-> state
|
(-> state
|
||||||
(update-in [:workspace-undo :transaction :undo-changes] #(into undo-changes %))
|
(update-in [:workspace-undo :transaction :undo-changes] #(into undo-changes %))
|
||||||
(update-in [:workspace-undo :transaction :redo-changes] #(into % redo-changes))
|
(update-in [:workspace-undo :transaction :redo-changes] #(into % redo-changes))
|
||||||
(cond->
|
(cond-> (nil? (get-in state [:workspace-undo :transaction :undo-group]))
|
||||||
(nil? (get-in state [:workspace-undo :transaction :undo-group]))
|
|
||||||
(assoc-in [:workspace-undo :transaction :undo-group] undo-group))
|
(assoc-in [:workspace-undo :transaction :undo-group] undo-group))
|
||||||
(assoc-in [:workspace-undo :transaction :tags] tags)))
|
(assoc-in [:workspace-undo :transaction :tags] tags)))
|
||||||
|
|
||||||
|
@ -182,3 +180,125 @@
|
||||||
(rx/tap #(js/console.warn (dm/str "FORCE COMMIT TRANSACTION AFTER " (second %) "MS")))
|
(rx/tap #(js/console.warn (dm/str "FORCE COMMIT TRANSACTION AFTER " (second %) "MS")))
|
||||||
(rx/map first)
|
(rx/map first)
|
||||||
(rx/map commit-undo-transaction))))))
|
(rx/map commit-undo-transaction))))))
|
||||||
|
|
||||||
|
(defn undo-to-index
|
||||||
|
"Repeat undoing or redoing until dest-index is reached."
|
||||||
|
[dest-index]
|
||||||
|
(ptk/reify ::undo-to-index
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [it state _]
|
||||||
|
(let [objects (wsh/lookup-page-objects state)
|
||||||
|
edition (get-in state [:workspace-local :edition])
|
||||||
|
drawing (get state :workspace-drawing)]
|
||||||
|
(when-not (and (or (some? edition) (some? (:object drawing)))
|
||||||
|
(not (ctl/grid-layout? objects edition)))
|
||||||
|
(let [undo (:workspace-undo state)
|
||||||
|
items (:items undo)
|
||||||
|
index (or (:index undo) (dec (count items)))]
|
||||||
|
(when (and (some? items)
|
||||||
|
(<= -1 dest-index (dec (count items))))
|
||||||
|
(let [changes (vec (apply concat
|
||||||
|
(cond
|
||||||
|
(< dest-index index)
|
||||||
|
(->> (subvec items (inc dest-index) (inc index))
|
||||||
|
(reverse)
|
||||||
|
(map :undo-changes))
|
||||||
|
(> dest-index index)
|
||||||
|
(->> (subvec items (inc index) (inc dest-index))
|
||||||
|
(map :redo-changes))
|
||||||
|
:else [])))]
|
||||||
|
(when (seq changes)
|
||||||
|
(rx/of (materialize-undo changes dest-index)
|
||||||
|
(dch/commit-changes {:redo-changes changes
|
||||||
|
:undo-changes []
|
||||||
|
:origin it
|
||||||
|
:save-undo? false})))))))))))
|
||||||
|
|
||||||
|
(declare ^:private assure-valid-current-page)
|
||||||
|
|
||||||
|
(def undo
|
||||||
|
(ptk/reify ::undo
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [it state _]
|
||||||
|
(let [objects (wsh/lookup-page-objects state)
|
||||||
|
edition (get-in state [:workspace-local :edition])
|
||||||
|
drawing (get state :workspace-drawing)]
|
||||||
|
|
||||||
|
;; Editors handle their own undo's
|
||||||
|
(when (or (and (nil? edition) (nil? (:object drawing)))
|
||||||
|
(ctl/grid-layout? objects edition))
|
||||||
|
(let [undo (:workspace-undo state)
|
||||||
|
items (:items undo)
|
||||||
|
index (or (:index undo) (dec (count items)))]
|
||||||
|
(when-not (or (empty? items) (= index -1))
|
||||||
|
(let [item (get items index)
|
||||||
|
changes (:undo-changes item)
|
||||||
|
undo-group (:undo-group item)
|
||||||
|
|
||||||
|
find-first-group-idx
|
||||||
|
(fn [index]
|
||||||
|
(if (= (dm/get-in items [index :undo-group]) undo-group)
|
||||||
|
(recur (dec index))
|
||||||
|
(inc index)))
|
||||||
|
|
||||||
|
undo-group-index
|
||||||
|
(when undo-group
|
||||||
|
(find-first-group-idx index))]
|
||||||
|
|
||||||
|
(if undo-group
|
||||||
|
(rx/of (undo-to-index (dec undo-group-index)))
|
||||||
|
(rx/of (materialize-undo changes (dec index))
|
||||||
|
(dch/commit-changes {:redo-changes changes
|
||||||
|
:undo-changes []
|
||||||
|
:save-undo? false
|
||||||
|
:origin it})
|
||||||
|
(assure-valid-current-page)))))))))))
|
||||||
|
|
||||||
|
(def redo
|
||||||
|
(ptk/reify ::redo
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [it state _]
|
||||||
|
(let [objects (wsh/lookup-page-objects state)
|
||||||
|
edition (get-in state [:workspace-local :edition])
|
||||||
|
drawing (get state :workspace-drawing)]
|
||||||
|
(when (and (or (nil? edition) (ctl/grid-layout? objects edition))
|
||||||
|
(or (empty? drawing) (= :curve (:tool drawing))))
|
||||||
|
(let [undo (:workspace-undo state)
|
||||||
|
items (:items undo)
|
||||||
|
index (or (:index undo) (dec (count items)))]
|
||||||
|
(when-not (or (empty? items) (= index (dec (count items))))
|
||||||
|
(let [item (get items (inc index))
|
||||||
|
changes (:redo-changes item)
|
||||||
|
undo-group (:undo-group item)
|
||||||
|
find-last-group-idx (fn flgidx [index]
|
||||||
|
(let [item (get items index)]
|
||||||
|
(if (= (:undo-group item) undo-group)
|
||||||
|
(flgidx (inc index))
|
||||||
|
(dec index))))
|
||||||
|
|
||||||
|
redo-group-index (when undo-group
|
||||||
|
(find-last-group-idx (inc index)))]
|
||||||
|
(if undo-group
|
||||||
|
(rx/of (undo-to-index redo-group-index))
|
||||||
|
(rx/of (materialize-undo changes (inc index))
|
||||||
|
(dch/commit-changes {:redo-changes changes
|
||||||
|
:undo-changes []
|
||||||
|
:origin it
|
||||||
|
:save-undo? false})))))))))))
|
||||||
|
|
||||||
|
(defn- assure-valid-current-page
|
||||||
|
[]
|
||||||
|
(ptk/reify ::assure-valid-current-page
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(let [current_page (:current-page-id state)
|
||||||
|
pages (get-in state [:workspace-data :pages])
|
||||||
|
exists? (some #(= current_page %) pages)
|
||||||
|
|
||||||
|
project-id (:current-project-id state)
|
||||||
|
file-id (:current-file-id state)
|
||||||
|
pparams {:file-id file-id :project-id project-id}
|
||||||
|
qparams {:page-id (first pages)}]
|
||||||
|
(if exists?
|
||||||
|
(rx/empty)
|
||||||
|
(rx/of (rt/nav :workspace pparams qparams)))))))
|
||||||
|
|
|
@ -45,6 +45,9 @@
|
||||||
(def export
|
(def export
|
||||||
(l/derived :export st/state))
|
(l/derived :export st/state))
|
||||||
|
|
||||||
|
(def persistence
|
||||||
|
(l/derived :persistence st/state))
|
||||||
|
|
||||||
;; ---- Dashboard refs
|
;; ---- Dashboard refs
|
||||||
|
|
||||||
(def dashboard-local
|
(def dashboard-local
|
||||||
|
|
|
@ -34,8 +34,6 @@
|
||||||
(def debug-exclude-events
|
(def debug-exclude-events
|
||||||
#{:app.main.data.workspace.notifications/handle-pointer-update
|
#{:app.main.data.workspace.notifications/handle-pointer-update
|
||||||
:app.main.data.workspace.notifications/handle-pointer-send
|
:app.main.data.workspace.notifications/handle-pointer-send
|
||||||
:app.main.data.workspace.persistence/update-persistence-status
|
|
||||||
:app.main.data.workspace.changes/update-indices
|
|
||||||
:app.main.data.websocket/send-message
|
:app.main.data.websocket/send-message
|
||||||
:app.main.data.workspace.selection/change-hover-state})
|
:app.main.data.workspace.selection/change-hover-state})
|
||||||
|
|
||||||
|
@ -65,7 +63,7 @@
|
||||||
:app.util.router/assign-exception}]
|
:app.util.router/assign-exception}]
|
||||||
(->> (rx/merge
|
(->> (rx/merge
|
||||||
(->> stream
|
(->> stream
|
||||||
(rx/filter (ptk/type? :app.main.data.workspace.changes/commit-changes))
|
(rx/filter (ptk/type? :app.main.data.changes/commit))
|
||||||
(rx/map #(-> % deref :hint-origin)))
|
(rx/map #(-> % deref :hint-origin)))
|
||||||
(rx/map ptk/type stream))
|
(rx/map ptk/type stream))
|
||||||
(rx/filter #(not (contains? omitset %)))
|
(rx/filter #(not (contains? omitset %)))
|
||||||
|
|
|
@ -101,7 +101,7 @@
|
||||||
(cond-> (and value is-checkbox?) (assoc :default-checked value))
|
(cond-> (and value is-checkbox?) (assoc :default-checked value))
|
||||||
(cond-> (and touched? (:message error)) (assoc "aria-invalid" "true"
|
(cond-> (and touched? (:message error)) (assoc "aria-invalid" "true"
|
||||||
"aria-describedby" (dm/str "error-" input-name)))
|
"aria-describedby" (dm/str "error-" input-name)))
|
||||||
(obj/clj->props))
|
(obj/map->obj obj/prop-key-fn))
|
||||||
|
|
||||||
checked? (and is-checkbox? (= value true))
|
checked? (and is-checkbox? (= value true))
|
||||||
show-valid? (and show-success? touched? (not error))
|
show-valid? (and show-success? touched? (not error))
|
||||||
|
@ -201,7 +201,7 @@
|
||||||
:on-blur on-blur
|
:on-blur on-blur
|
||||||
;; :placeholder label
|
;; :placeholder label
|
||||||
:on-change on-change)
|
:on-change on-change)
|
||||||
(obj/clj->props))]
|
(obj/map->obj obj/prop-key-fn))]
|
||||||
|
|
||||||
[:div {:class (dm/str klass " " (stl/css :textarea-wrapper))}
|
[:div {:class (dm/str klass " " (stl/css :textarea-wrapper))}
|
||||||
[:label {:class (stl/css :textarea-label)} label]
|
[:label {:class (stl/css :textarea-label)} label]
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.main.data.messages :as msg]
|
[app.main.data.messages :as msg]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
|
[app.main.data.persistence :as dps]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.colors :as dc]
|
[app.main.data.workspace.colors :as dc]
|
||||||
[app.main.data.workspace.persistence :as dwp]
|
|
||||||
[app.main.features :as features]
|
[app.main.features :as features]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
@ -177,6 +177,9 @@
|
||||||
|
|
||||||
background-color (:background-color wglobal)]
|
background-color (:background-color wglobal)]
|
||||||
|
|
||||||
|
(mf/with-effect []
|
||||||
|
(st/emit! (dps/initialize-persistence)))
|
||||||
|
|
||||||
;; Setting the layout preset by its name
|
;; Setting the layout preset by its name
|
||||||
(mf/with-effect [layout-name]
|
(mf/with-effect [layout-name]
|
||||||
(st/emit! (dw/initialize-layout layout-name)))
|
(st/emit! (dw/initialize-layout layout-name)))
|
||||||
|
@ -188,7 +191,7 @@
|
||||||
(mf/with-effect [project-id file-id]
|
(mf/with-effect [project-id file-id]
|
||||||
(st/emit! (dw/initialize-file project-id file-id))
|
(st/emit! (dw/initialize-file project-id file-id))
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! ::dwp/force-persist
|
(st/emit! ::dps/force-persist
|
||||||
(dc/stop-picker)
|
(dc/stop-picker)
|
||||||
(modal/hide)
|
(modal/hide)
|
||||||
msg/hide
|
msg/hide
|
||||||
|
|
|
@ -19,9 +19,9 @@
|
||||||
[app.main.data.shortcuts :as scd]
|
[app.main.data.shortcuts :as scd]
|
||||||
[app.main.data.users :as du]
|
[app.main.data.users :as du]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.common :as dwc]
|
|
||||||
[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.data.workspace.undo :as dwu]
|
||||||
[app.main.features :as features]
|
[app.main.features :as features]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
@ -414,8 +414,8 @@
|
||||||
::mf/wrap [mf/memo]}
|
::mf/wrap [mf/memo]}
|
||||||
[{:keys [on-close]}]
|
[{:keys [on-close]}]
|
||||||
(let [select-all (mf/use-fn #(st/emit! (dw/select-all)))
|
(let [select-all (mf/use-fn #(st/emit! (dw/select-all)))
|
||||||
undo (mf/use-fn #(st/emit! dwc/undo))
|
undo (mf/use-fn #(st/emit! dwu/undo))
|
||||||
redo (mf/use-fn #(st/emit! dwc/redo))]
|
redo (mf/use-fn #(st/emit! dwu/redo))]
|
||||||
[:& dropdown-menu {:show true
|
[:& dropdown-menu {:show true
|
||||||
:list-class (stl/css-case :sub-menu true
|
:list-class (stl/css-case :sub-menu true
|
||||||
:edit true)
|
:edit true)
|
||||||
|
|
|
@ -25,38 +25,35 @@
|
||||||
[okulary.core :as l]
|
[okulary.core :as l]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(def ref:workspace-persistence
|
(def ref:persistence-status
|
||||||
(l/derived :workspace-persistence st/state))
|
(l/derived :status refs/persistence))
|
||||||
|
|
||||||
;; --- Persistence state Widget
|
;; --- Persistence state Widget
|
||||||
|
|
||||||
(mf/defc persistence-state-widget
|
(mf/defc persistence-state-widget
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]
|
||||||
|
::mf/wrap-props false}
|
||||||
[]
|
[]
|
||||||
(let [{:keys [status]} (mf/deref ref:workspace-persistence)]
|
(let [status (mf/deref ref:persistence-status)]
|
||||||
[:div {:class (stl/css :persistence-status-widget)}
|
[:div {:class (stl/css :persistence-status-widget)}
|
||||||
(case status
|
(case status
|
||||||
:pending
|
:pending
|
||||||
[:div {:class (stl/css-case :status-icon true
|
[:div {:class (stl/css :status-icon :pending-status)
|
||||||
:pending-status true)
|
|
||||||
:title (tr "workspace.header.unsaved")}
|
:title (tr "workspace.header.unsaved")}
|
||||||
i/status-alert]
|
i/status-alert]
|
||||||
|
|
||||||
:saving
|
:saving
|
||||||
[:div {:class (stl/css-case :status-icon true
|
[:div {:class (stl/css :status-icon :saving-status)
|
||||||
:saving-status true)
|
|
||||||
:title (tr "workspace.header.saving")}
|
:title (tr "workspace.header.saving")}
|
||||||
i/status-update]
|
i/status-update]
|
||||||
|
|
||||||
:saved
|
:saved
|
||||||
[:div {:class (stl/css-case :status-icon true
|
[:div {:class (stl/css :status-icon :saved-status)
|
||||||
:saved-status true)
|
|
||||||
:title (tr "workspace.header.saved")}
|
:title (tr "workspace.header.saved")}
|
||||||
i/status-tick]
|
i/status-tick]
|
||||||
|
|
||||||
:error
|
:error
|
||||||
[:div {:class (stl/css-case :status-icon true
|
[:div {:class (stl/css :status-icon :error-status)
|
||||||
:error-status true)
|
|
||||||
:title "There was an error saving the data. Please refresh if this persists."}
|
:title "There was an error saving the data. Please refresh if this persists."}
|
||||||
i/status-wrong]
|
i/status-wrong]
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.common :as dwc]
|
[app.main.data.workspace.undo :as dwu]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
|
@ -304,7 +304,7 @@
|
||||||
:show-detail @show-detail?)
|
:show-detail @show-detail?)
|
||||||
:on-pointer-enter #(reset! hover? true)
|
:on-pointer-enter #(reset! hover? true)
|
||||||
:on-pointer-leave #(reset! hover? false)
|
:on-pointer-leave #(reset! hover? false)
|
||||||
:on-click #(st/emit! (dwc/undo-to-index idx-entry))}
|
:on-click #(st/emit! (dwu/undo-to-index idx-entry))}
|
||||||
|
|
||||||
[:div {:class (stl/css :history-entry-summary)}
|
[:div {:class (stl/css :history-entry-summary)}
|
||||||
[:div {:class (stl/css :history-entry-summary-icon)}
|
[:div {:class (stl/css :history-entry-summary-icon)}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[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.components.title-bar :refer [title-bar]]
|
[app.main.ui.components.title-bar :refer [title-bar]]
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn [update-fn]
|
(fn [update-fn]
|
||||||
(st/emit! (dch/update-shapes ids update-fn))))
|
(st/emit! (dwsh/update-shapes ids update-fn))))
|
||||||
|
|
||||||
handle-add
|
handle-add
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
[app.common.geom.rect :as grc]
|
[app.common.geom.rect :as grc]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.select :refer [select]]
|
[app.main.ui.components.select :refer [select]]
|
||||||
|
@ -102,7 +102,7 @@
|
||||||
[:constraints-h :center])
|
[:constraints-h :center])
|
||||||
nil ())]
|
nil ())]
|
||||||
|
|
||||||
(st/emit! (dch/update-shapes
|
(st/emit! (dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
#(assoc % constraint new-value))))))
|
#(assoc % constraint new-value))))))
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn [value]
|
(fn [value]
|
||||||
(when-not (str/empty? value)
|
(when-not (str/empty? value)
|
||||||
(st/emit! (dch/update-shapes
|
(st/emit! (dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
#(assoc % :constraints-h (keyword value)))))))
|
#(assoc % :constraints-h (keyword value)))))))
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn [value]
|
(fn [value]
|
||||||
(when-not (str/empty? value)
|
(when-not (str/empty? value)
|
||||||
(st/emit! (dch/update-shapes
|
(st/emit! (dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
#(assoc % :constraints-v (keyword value)))))))
|
#(assoc % :constraints-v (keyword value)))))))
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(st/emit! (dch/update-shapes ids #(update % :fixed-scroll not)))))
|
(st/emit! (dwsh/update-shapes ids #(update % :fixed-scroll not)))))
|
||||||
|
|
||||||
options-h
|
options-h
|
||||||
(mf/with-memo [constraints-h]
|
(mf/with-memo [constraints-h]
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.main.data.exports :as de]
|
[app.main.data.exports :as de]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
@ -97,9 +97,9 @@
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn []
|
(fn []
|
||||||
(let [xspec {:type :png :suffix "" :scale 1}]
|
(let [xspec {:type :png :suffix "" :scale 1}]
|
||||||
(st/emit! (dch/update-shapes ids
|
(st/emit! (dwsh/update-shapes ids
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(assoc shape :exports (into [xspec] (:exports shape)))))))))
|
(assoc shape :exports (into [xspec] (:exports shape)))))))))
|
||||||
|
|
||||||
delete-export
|
delete-export
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
@ -110,16 +110,16 @@
|
||||||
(mapv second)))
|
(mapv second)))
|
||||||
|
|
||||||
remove (fn [shape] (update shape :exports remove-fill-by-index position))]
|
remove (fn [shape] (update shape :exports remove-fill-by-index position))]
|
||||||
(st/emit! (dch/update-shapes ids remove)))))
|
(st/emit! (dwsh/update-shapes ids remove)))))
|
||||||
|
|
||||||
on-scale-change
|
on-scale-change
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn [index event]
|
(fn [index event]
|
||||||
(let [scale (d/parse-double event)]
|
(let [scale (d/parse-double event)]
|
||||||
(st/emit! (dch/update-shapes ids
|
(st/emit! (dwsh/update-shapes ids
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(assoc-in shape [:exports index :scale] scale)))))))
|
(assoc-in shape [:exports index :scale] scale)))))))
|
||||||
|
|
||||||
on-suffix-change
|
on-suffix-change
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
@ -129,26 +129,26 @@
|
||||||
index (-> (dom/get-current-target event)
|
index (-> (dom/get-current-target event)
|
||||||
(dom/get-data "value")
|
(dom/get-data "value")
|
||||||
(d/parse-integer))]
|
(d/parse-integer))]
|
||||||
(st/emit! (dch/update-shapes ids
|
(st/emit! (dwsh/update-shapes ids
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(assoc-in shape [:exports index :suffix] value)))))))
|
(assoc-in shape [:exports index :suffix] value)))))))
|
||||||
|
|
||||||
on-type-change
|
on-type-change
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn [index event]
|
(fn [index event]
|
||||||
(let [type (keyword event)]
|
(let [type (keyword event)]
|
||||||
(st/emit! (dch/update-shapes ids
|
(st/emit! (dwsh/update-shapes ids
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(assoc-in shape [:exports index :type] type)))))))
|
(assoc-in shape [:exports index :type] type)))))))
|
||||||
|
|
||||||
on-remove-all
|
on-remove-all
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (dch/update-shapes ids
|
(st/emit! (dwsh/update-shapes ids
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(assoc shape :exports []))))))
|
(assoc shape :exports []))))))
|
||||||
manage-key-down
|
manage-key-down
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [event]
|
(fn [event]
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[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.components.select :refer [select]]
|
[app.main.ui.components.select :refer [select]]
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn [prop value]
|
(fn [prop value]
|
||||||
(st/emit! (dch/update-shapes ids #(assoc % prop value)))))
|
(st/emit! (dwsh/update-shapes ids #(assoc % prop value)))))
|
||||||
|
|
||||||
handle-change-blend-mode
|
handle-change-blend-mode
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
[app.common.types.shape.radius :as ctsr]
|
[app.common.types.shape.radius :as ctsr]
|
||||||
[app.main.constants :refer [size-presets]]
|
[app.main.constants :refer [size-presets]]
|
||||||
[app.main.data.workspace :as udw]
|
[app.main.data.workspace :as udw]
|
||||||
[app.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.interactions :as dwi]
|
[app.main.data.workspace.interactions :as dwi]
|
||||||
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.undo :as dwu]
|
[app.main.data.workspace.undo :as dwu]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
@ -249,13 +249,13 @@
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids-with-children)
|
(mf/deps ids-with-children)
|
||||||
(fn [update-fn]
|
(fn [update-fn]
|
||||||
(dch/update-shapes ids-with-children
|
(dwsh/update-shapes ids-with-children
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(if (ctsr/has-radius? shape)
|
(if (ctsr/has-radius? shape)
|
||||||
(update-fn shape)
|
(update-fn shape)
|
||||||
shape))
|
shape))
|
||||||
{:reg-objects? true
|
{:reg-objects? true
|
||||||
:attrs [:rx :ry :r1 :r2 :r3 :r4]})))
|
:attrs [:rx :ry :r1 :r2 :r3 :r4]})))
|
||||||
|
|
||||||
on-switch-to-radius-1
|
on-switch-to-radius-1
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
@ -317,7 +317,7 @@
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [value (-> event dom/get-target dom/checked?)]
|
(let [value (-> event dom/get-target dom/checked?)]
|
||||||
(st/emit! (dch/update-shapes ids (fn [shape] (assoc shape :show-content (not value))))))))
|
(st/emit! (dwsh/update-shapes ids (fn [shape] (assoc shape :show-content (not value))))))))
|
||||||
|
|
||||||
on-change-show-in-viewer
|
on-change-show-in-viewer
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
@ -327,7 +327,7 @@
|
||||||
undo-id (js/Symbol)]
|
undo-id (js/Symbol)]
|
||||||
(do
|
(do
|
||||||
(st/emit! (dwu/start-undo-transaction undo-id)
|
(st/emit! (dwu/start-undo-transaction undo-id)
|
||||||
(dch/update-shapes ids (fn [shape] (assoc shape :hide-in-viewer (not value)))))
|
(dwsh/update-shapes ids (fn [shape] (assoc shape :hide-in-viewer (not value)))))
|
||||||
|
|
||||||
(when-not value
|
(when-not value
|
||||||
;; when a frame is no longer shown in view mode, cannot have
|
;; when a frame is no longer shown in view mode, cannot have
|
||||||
|
@ -399,7 +399,7 @@
|
||||||
:placeholder (if (= :multiple (:width values)) (tr "settings.multiple") "--")
|
:placeholder (if (= :multiple (:width values)) (tr "settings.multiple") "--")
|
||||||
:on-change on-width-change
|
:on-change on-width-change
|
||||||
:disabled disabled-width-sizing?
|
:disabled disabled-width-sizing?
|
||||||
:className (stl/css :numeric-input)
|
:class (stl/css :numeric-input)
|
||||||
:value (:width values)}]]
|
:value (:width values)}]]
|
||||||
[:div {:class (stl/css-case :height true
|
[:div {:class (stl/css-case :height true
|
||||||
:disabled disabled-height-sizing?)
|
:disabled disabled-height-sizing?)
|
||||||
|
@ -410,7 +410,7 @@
|
||||||
:placeholder (if (= :multiple (:height values)) (tr "settings.multiple") "--")
|
:placeholder (if (= :multiple (:height values)) (tr "settings.multiple") "--")
|
||||||
:on-change on-height-change
|
:on-change on-height-change
|
||||||
:disabled disabled-height-sizing?
|
:disabled disabled-height-sizing?
|
||||||
:className (stl/css :numeric-input)
|
:class (stl/css :numeric-input)
|
||||||
:value (:height values)}]]
|
:value (:height values)}]]
|
||||||
[:button {:class (stl/css-case
|
[:button {:class (stl/css-case
|
||||||
:lock-size-btn true
|
:lock-size-btn true
|
||||||
|
@ -430,7 +430,7 @@
|
||||||
:placeholder (if (= :multiple (:x values)) (tr "settings.multiple") "--")
|
:placeholder (if (= :multiple (:x values)) (tr "settings.multiple") "--")
|
||||||
:on-change on-pos-x-change
|
:on-change on-pos-x-change
|
||||||
:disabled disabled-position-x?
|
:disabled disabled-position-x?
|
||||||
:className (stl/css :numeric-input)
|
:class (stl/css :numeric-input)
|
||||||
:value (:x values)}]]
|
:value (:x values)}]]
|
||||||
|
|
||||||
[:div {:class (stl/css-case :y-position true
|
[:div {:class (stl/css-case :y-position true
|
||||||
|
@ -441,7 +441,7 @@
|
||||||
:placeholder (if (= :multiple (:y values)) (tr "settings.multiple") "--")
|
:placeholder (if (= :multiple (:y values)) (tr "settings.multiple") "--")
|
||||||
:disabled disabled-position-y?
|
:disabled disabled-position-y?
|
||||||
:on-change on-pos-y-change
|
:on-change on-pos-y-change
|
||||||
:className (stl/css :numeric-input)
|
:class (stl/css :numeric-input)
|
||||||
:value (:y values)}]]])
|
:value (:y values)}]]])
|
||||||
(when (or (options :rotation) (options :radius))
|
(when (or (options :rotation) (options :radius))
|
||||||
[:div {:class (stl/css :rotation-radius)}
|
[:div {:class (stl/css :rotation-radius)}
|
||||||
|
@ -457,7 +457,7 @@
|
||||||
:data-wrap true
|
:data-wrap true
|
||||||
:placeholder (if (= :multiple (:rotation values)) (tr "settings.multiple") "--")
|
:placeholder (if (= :multiple (:rotation values)) (tr "settings.multiple") "--")
|
||||||
:on-change on-rotation-change
|
:on-change on-rotation-change
|
||||||
:className (stl/css :numeric-input)
|
:class (stl/css :numeric-input)
|
||||||
:value (:rotation values)}]])
|
:value (:rotation values)}]])
|
||||||
|
|
||||||
(when (options :radius)
|
(when (options :radius)
|
||||||
|
@ -473,7 +473,7 @@
|
||||||
:ref radius-input-ref
|
:ref radius-input-ref
|
||||||
:min 0
|
:min 0
|
||||||
:on-change on-radius-1-change
|
:on-change on-radius-1-change
|
||||||
:className (stl/css :numeric-input)
|
:class (stl/css :numeric-input)
|
||||||
:value (:rx values)}]]
|
:value (:rx values)}]]
|
||||||
|
|
||||||
@radius-multi?
|
@radius-multi?
|
||||||
|
@ -485,7 +485,7 @@
|
||||||
:placeholder "Mixed"
|
:placeholder "Mixed"
|
||||||
:min 0
|
:min 0
|
||||||
:on-change on-radius-multi-change
|
:on-change on-radius-multi-change
|
||||||
:className (stl/css :numeric-input)
|
:class (stl/css :numeric-input)
|
||||||
:value (if all-equal? (:rx values) nil)}]]
|
:value (if all-equal? (:rx values) nil)}]]
|
||||||
|
|
||||||
|
|
||||||
|
@ -497,7 +497,7 @@
|
||||||
{:placeholder "--"
|
{:placeholder "--"
|
||||||
:min 0
|
:min 0
|
||||||
:on-change on-radius-r1-change
|
:on-change on-radius-r1-change
|
||||||
:className (stl/css :numeric-input)
|
:class (stl/css :numeric-input)
|
||||||
:value (:r1 values)}]]
|
:value (:r1 values)}]]
|
||||||
|
|
||||||
[:div {:class (stl/css :small-input)
|
[:div {:class (stl/css :small-input)
|
||||||
|
@ -506,7 +506,7 @@
|
||||||
{:placeholder "--"
|
{:placeholder "--"
|
||||||
:min 0
|
:min 0
|
||||||
:on-change on-radius-r2-change
|
:on-change on-radius-r2-change
|
||||||
:className (stl/css :numeric-input)
|
:class (stl/css :numeric-input)
|
||||||
:value (:r2 values)}]]
|
:value (:r2 values)}]]
|
||||||
|
|
||||||
[:div {:class (stl/css :small-input)
|
[:div {:class (stl/css :small-input)
|
||||||
|
@ -515,7 +515,7 @@
|
||||||
{:placeholder "--"
|
{:placeholder "--"
|
||||||
:min 0
|
:min 0
|
||||||
:on-change on-radius-r4-change
|
:on-change on-radius-r4-change
|
||||||
:className (stl/css :numeric-input)
|
:class (stl/css :numeric-input)
|
||||||
:value (:r4 values)}]]
|
:value (:r4 values)}]]
|
||||||
|
|
||||||
[:div {:class (stl/css :small-input)
|
[:div {:class (stl/css :small-input)
|
||||||
|
@ -524,7 +524,7 @@
|
||||||
{:placeholder "--"
|
{:placeholder "--"
|
||||||
:min 0
|
:min 0
|
||||||
:on-change on-radius-r3-change
|
:on-change on-radius-r3-change
|
||||||
:className (stl/css :numeric-input)
|
:class (stl/css :numeric-input)
|
||||||
:value (:r3 values)}]]])]
|
:value (:r3 values)}]]])]
|
||||||
[:button {:class (stl/css-case :radius-mode true
|
[:button {:class (stl/css-case :radius-mode true
|
||||||
:selected (= radius-mode :radius-4))
|
:selected (= radius-mode :radius-4))
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.math :as mth]
|
[app.common.math :as mth]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.colors :as dc]
|
[app.main.data.workspace.colors :as dc]
|
||||||
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.undo :as dwu]
|
[app.main.data.workspace.undo :as dwu]
|
||||||
[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*]]
|
||||||
|
@ -73,7 +73,7 @@
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids index)
|
(mf/deps ids index)
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (dch/update-shapes ids #(update % :shadow remove-shadow-by-index index)))))
|
(st/emit! (dwsh/update-shapes ids #(update % :shadow remove-shadow-by-index index)))))
|
||||||
|
|
||||||
on-drop
|
on-drop
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
@ -102,7 +102,7 @@
|
||||||
([index attr update-ref]
|
([index attr update-ref]
|
||||||
(fn [value]
|
(fn [value]
|
||||||
(when (mth/finite? value)
|
(when (mth/finite? value)
|
||||||
(st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index attr] value)))
|
(st/emit! (dwsh/update-shapes ids #(assoc-in % [:shadow index attr] value)))
|
||||||
(when-let [update-node (and update-ref (mf/ref-val update-ref))]
|
(when-let [update-node (and update-ref (mf/ref-val update-ref))]
|
||||||
(dom/set-value! update-node value))))))
|
(dom/set-value! update-node value))))))
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids index)
|
(mf/deps ids index)
|
||||||
(fn [color]
|
(fn [color]
|
||||||
(st/emit! (dch/update-shapes
|
(st/emit! (dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
#(assoc-in % [:shadow index :color] (d/without-nils color))))))
|
#(assoc-in % [:shadow index :color] (d/without-nils color))))))
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
(mf/deps ids index value)
|
(mf/deps ids index value)
|
||||||
(fn [_color _opacity]
|
(fn [_color _opacity]
|
||||||
(when-not (string? (:color value))
|
(when-not (string? (:color value))
|
||||||
(st/emit! (dch/update-shapes
|
(st/emit! (dwsh/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)))))))
|
||||||
|
@ -128,7 +128,7 @@
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids index)
|
(mf/deps ids index)
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (dch/update-shapes ids #(update-in % [:shadow index :hidden] not)))))
|
(st/emit! (dwsh/update-shapes ids #(update-in % [:shadow index :hidden] not)))))
|
||||||
|
|
||||||
on-toggle-open-shadow
|
on-toggle-open-shadow
|
||||||
(fn []
|
(fn []
|
||||||
|
@ -139,7 +139,7 @@
|
||||||
(mf/deps ids index)
|
(mf/deps ids index)
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [value (keyword event)]
|
(let [value (keyword event)]
|
||||||
(st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index :style] value))))))
|
(st/emit! (dwsh/update-shapes ids #(assoc-in % [:shadow index :style] value))))))
|
||||||
|
|
||||||
type-options [{:value "drop-shadow" :label (tr "workspace.options.shadow-options.drop-shadow")}
|
type-options [{:value "drop-shadow" :label (tr "workspace.options.shadow-options.drop-shadow")}
|
||||||
{:value "inner-shadow" :label (tr "workspace.options.shadow-options.inner-shadow")}]
|
{:value "inner-shadow" :label (tr "workspace.options.shadow-options.inner-shadow")}]
|
||||||
|
@ -268,7 +268,7 @@
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (dch/update-shapes ids #(dissoc % :shadow)))))
|
(st/emit! (dwsh/update-shapes ids #(dissoc % :shadow)))))
|
||||||
|
|
||||||
handle-reorder
|
handle-reorder
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.title-bar :refer [title-bar]]
|
[app.main.ui.components.title-bar :refer [title-bar]]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
|
@ -66,7 +66,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! (dch/update-shapes ids update-fn)))))
|
(st/emit! (dwsh/update-shapes ids update-fn)))))
|
||||||
|
|
||||||
handle-delete
|
handle-delete
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
@ -81,7 +81,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! (dch/update-shapes ids update-fn)))))]
|
(st/emit! (dwsh/update-shapes ids update-fn)))))]
|
||||||
|
|
||||||
(when-not (empty? attrs)
|
(when-not (empty? attrs)
|
||||||
[:div {:class (stl/css :element-set)}
|
[:div {:class (stl/css :element-set)}
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.text :as txt]
|
[app.common.text :as txt]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[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.shapes :as dwsh]
|
||||||
[app.main.data.workspace.shortcuts :as sc]
|
[app.main.data.workspace.shortcuts :as sc]
|
||||||
[app.main.data.workspace.texts :as dwt]
|
[app.main.data.workspace.texts :as dwt]
|
||||||
[app.main.data.workspace.undo :as dwu]
|
[app.main.data.workspace.undo :as dwu]
|
||||||
|
@ -127,8 +127,8 @@
|
||||||
grow-type (keyword value)]
|
grow-type (keyword value)]
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(dwu/start-undo-transaction uid)
|
(dwu/start-undo-transaction uid)
|
||||||
(dch/update-shapes ids #(assoc % :grow-type grow-type)))
|
(dwsh/update-shapes ids #(assoc % :grow-type grow-type)))
|
||||||
;; We asynchronously commit so every sychronous event is resolved first and inside the transaction
|
;; We asynchronously commit so every sychronous event is resolved first and inside the transaction
|
||||||
(ts/schedule #(st/emit! (dwu/commit-undo-transaction uid))))
|
(ts/schedule #(st/emit! (dwu/commit-undo-transaction uid))))
|
||||||
(when (some? on-blur) (on-blur))))]
|
(when (some? on-blur) (on-blur))))]
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
[app.common.text :as txt]
|
[app.common.text :as txt]
|
||||||
[app.common.types.shape :as cts]
|
[app.common.types.shape :as cts]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace.changes :as ch]
|
[app.main.data.changes :as ch]
|
||||||
[app.main.data.workspace.groups :as dwg]
|
[app.main.data.workspace.groups :as dwg]
|
||||||
[app.main.data.workspace.media :as dwm]
|
[app.main.data.workspace.media :as dwm]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
[app.common.types.shape.radius :as ctsr]
|
[app.common.types.shape.radius :as ctsr]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace :as udw]
|
[app.main.data.workspace :as udw]
|
||||||
[app.main.data.workspace.changes :as dwc]
|
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
[app.main.data.workspace.shape-layout :as dwsl]
|
[app.main.data.workspace.shape-layout :as dwsl]
|
||||||
[app.main.data.workspace.shapes :as dwsh]
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
|
@ -118,25 +117,25 @@
|
||||||
:get #(-> % proxy->shape :name)
|
:get #(-> % proxy->shape :name)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (obj/get self "$id")]
|
(let [id (obj/get self "$id")]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :name value)))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :name value)))))}
|
||||||
|
|
||||||
{:name "blocked"
|
{:name "blocked"
|
||||||
:get #(-> % proxy->shape :blocked boolean)
|
:get #(-> % proxy->shape :blocked boolean)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (obj/get self "$id")]
|
(let [id (obj/get self "$id")]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :blocked value)))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :blocked value)))))}
|
||||||
|
|
||||||
{:name "hidden"
|
{:name "hidden"
|
||||||
:get #(-> % proxy->shape :hidden boolean)
|
:get #(-> % proxy->shape :hidden boolean)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (obj/get self "$id")]
|
(let [id (obj/get self "$id")]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :hidden value)))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :hidden value)))))}
|
||||||
|
|
||||||
{:name "proportionLock"
|
{:name "proportionLock"
|
||||||
:get #(-> % proxy->shape :proportion-lock boolean)
|
:get #(-> % proxy->shape :proportion-lock boolean)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (obj/get self "$id")]
|
(let [id (obj/get self "$id")]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :proportion-lock value)))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :proportion-lock value)))))}
|
||||||
|
|
||||||
{:name "constraintsHorizontal"
|
{:name "constraintsHorizontal"
|
||||||
:get #(-> % proxy->shape :constraints-h d/name)
|
:get #(-> % proxy->shape :constraints-h d/name)
|
||||||
|
@ -144,7 +143,7 @@
|
||||||
(let [id (obj/get self "$id")
|
(let [id (obj/get self "$id")
|
||||||
value (keyword value)]
|
value (keyword value)]
|
||||||
(when (contains? cts/horizontal-constraint-types value)
|
(when (contains? cts/horizontal-constraint-types value)
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :constraints-h value))))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :constraints-h value))))))}
|
||||||
|
|
||||||
{:name "constraintsVertical"
|
{:name "constraintsVertical"
|
||||||
:get #(-> % proxy->shape :constraints-v d/name)
|
:get #(-> % proxy->shape :constraints-v d/name)
|
||||||
|
@ -152,7 +151,7 @@
|
||||||
(let [id (obj/get self "$id")
|
(let [id (obj/get self "$id")
|
||||||
value (keyword value)]
|
value (keyword value)]
|
||||||
(when (contains? cts/vertical-constraint-types value)
|
(when (contains? cts/vertical-constraint-types value)
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :constraints-v value))))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :constraints-v value))))))}
|
||||||
|
|
||||||
{:name "borderRadius"
|
{:name "borderRadius"
|
||||||
:get #(-> % proxy->shape :rx)
|
:get #(-> % proxy->shape :rx)
|
||||||
|
@ -161,8 +160,8 @@
|
||||||
shape (proxy->shape self)]
|
shape (proxy->shape self)]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(when (or (not (ctsr/has-radius? shape)) (ctsr/radius-4? shape))
|
(when (or (not (ctsr/has-radius? shape)) (ctsr/radius-4? shape))
|
||||||
(st/emit! (dwc/update-shapes [id] ctsr/switch-to-radius-1)))
|
(st/emit! (dwsh/update-shapes [id] ctsr/switch-to-radius-1)))
|
||||||
(st/emit! (dwc/update-shapes [id] #(ctsr/set-radius-1 % value))))))}
|
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-1 % value))))))}
|
||||||
|
|
||||||
{:name "borderRadiusTopLeft"
|
{:name "borderRadiusTopLeft"
|
||||||
:get #(-> % proxy->shape :r1)
|
:get #(-> % proxy->shape :r1)
|
||||||
|
@ -171,8 +170,8 @@
|
||||||
shape (proxy->shape self)]
|
shape (proxy->shape self)]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(when (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape)))
|
(when (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape)))
|
||||||
(st/emit! (dwc/update-shapes [id] ctsr/switch-to-radius-4)))
|
(st/emit! (dwsh/update-shapes [id] ctsr/switch-to-radius-4)))
|
||||||
(st/emit! (dwc/update-shapes [id] #(ctsr/set-radius-4 % :r1 value))))))}
|
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r1 value))))))}
|
||||||
|
|
||||||
{:name "borderRadiusTopRight"
|
{:name "borderRadiusTopRight"
|
||||||
:get #(-> % proxy->shape :r2)
|
:get #(-> % proxy->shape :r2)
|
||||||
|
@ -181,8 +180,8 @@
|
||||||
shape (proxy->shape self)]
|
shape (proxy->shape self)]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(when (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape)))
|
(when (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape)))
|
||||||
(st/emit! (dwc/update-shapes [id] ctsr/switch-to-radius-4)))
|
(st/emit! (dwsh/update-shapes [id] ctsr/switch-to-radius-4)))
|
||||||
(st/emit! (dwc/update-shapes [id] #(ctsr/set-radius-4 % :r2 value))))))}
|
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r2 value))))))}
|
||||||
|
|
||||||
{:name "borderRadiusBottomRight"
|
{:name "borderRadiusBottomRight"
|
||||||
:get #(-> % proxy->shape :r3)
|
:get #(-> % proxy->shape :r3)
|
||||||
|
@ -191,8 +190,8 @@
|
||||||
shape (proxy->shape self)]
|
shape (proxy->shape self)]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(when (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape)))
|
(when (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape)))
|
||||||
(st/emit! (dwc/update-shapes [id] ctsr/switch-to-radius-4)))
|
(st/emit! (dwsh/update-shapes [id] ctsr/switch-to-radius-4)))
|
||||||
(st/emit! (dwc/update-shapes [id] #(ctsr/set-radius-4 % :r3 value))))))}
|
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r3 value))))))}
|
||||||
|
|
||||||
{:name "borderRadiusBottomLeft"
|
{:name "borderRadiusBottomLeft"
|
||||||
:get #(-> % proxy->shape :r4)
|
:get #(-> % proxy->shape :r4)
|
||||||
|
@ -201,15 +200,15 @@
|
||||||
shape (proxy->shape self)]
|
shape (proxy->shape self)]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(when (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape)))
|
(when (or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape)))
|
||||||
(st/emit! (dwc/update-shapes [id] ctsr/switch-to-radius-4)))
|
(st/emit! (dwsh/update-shapes [id] ctsr/switch-to-radius-4)))
|
||||||
(st/emit! (dwc/update-shapes [id] #(ctsr/set-radius-4 % :r4 value))))))}
|
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r4 value))))))}
|
||||||
|
|
||||||
{:name "opacity"
|
{:name "opacity"
|
||||||
:get #(-> % proxy->shape :opacity)
|
:get #(-> % proxy->shape :opacity)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (obj/get self "$id")]
|
(let [id (obj/get self "$id")]
|
||||||
(when (and (us/safe-number? value) (>= value 0) (<= value 1))
|
(when (and (us/safe-number? value) (>= value 0) (<= value 1))
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :opacity value))))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :opacity value))))))}
|
||||||
|
|
||||||
{:name "blendMode"
|
{:name "blendMode"
|
||||||
:get #(-> % proxy->shape :blend-mode (d/nilv :normal) d/name)
|
:get #(-> % proxy->shape :blend-mode (d/nilv :normal) d/name)
|
||||||
|
@ -217,7 +216,7 @@
|
||||||
(let [id (obj/get self "$id")
|
(let [id (obj/get self "$id")
|
||||||
value (keyword value)]
|
value (keyword value)]
|
||||||
(when (contains? cts/blend-modes value)
|
(when (contains? cts/blend-modes value)
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :blend-mode value))))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :blend-mode value))))))}
|
||||||
|
|
||||||
{:name "shadows"
|
{:name "shadows"
|
||||||
:get #(-> % proxy->shape :shadow array-to-js)
|
:get #(-> % proxy->shape :shadow array-to-js)
|
||||||
|
@ -236,13 +235,13 @@
|
||||||
:hidden false}
|
:hidden false}
|
||||||
(utils/from-js val #{:style :type})))
|
(utils/from-js val #{:style :type})))
|
||||||
value)]
|
value)]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :shadow value)))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :shadow value)))))}
|
||||||
|
|
||||||
{:name "blur"
|
{:name "blur"
|
||||||
:get #(-> % proxy->shape :blur utils/to-js)
|
:get #(-> % proxy->shape :blur utils/to-js)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(if (nil? value)
|
(if (nil? value)
|
||||||
(st/emit! (dwc/update-shapes [id] #(dissoc % :blur)))
|
(st/emit! (dwsh/update-shapes [id] #(dissoc % :blur)))
|
||||||
(let [id (obj/get self "$id")
|
(let [id (obj/get self "$id")
|
||||||
value
|
value
|
||||||
(d/patch-object
|
(d/patch-object
|
||||||
|
@ -251,14 +250,14 @@
|
||||||
:value 4
|
:value 4
|
||||||
:hidden false}
|
:hidden false}
|
||||||
(utils/from-js value))]
|
(utils/from-js value))]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :blur value))))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :blur value))))))}
|
||||||
|
|
||||||
{:name "exports"
|
{:name "exports"
|
||||||
:get #(-> % proxy->shape :exports array-to-js)
|
:get #(-> % proxy->shape :exports array-to-js)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (obj/get self "$id")
|
(let [id (obj/get self "$id")
|
||||||
value (mapv #(utils/from-js %) value)]
|
value (mapv #(utils/from-js %) value)]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :exports value)))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :exports value)))))}
|
||||||
|
|
||||||
;; Geometry properties
|
;; Geometry properties
|
||||||
{:name "x"
|
{:name "x"
|
||||||
|
@ -354,14 +353,14 @@
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (obj/get self "$id")
|
(let [id (obj/get self "$id")
|
||||||
value (mapv #(utils/from-js %) value)]
|
value (mapv #(utils/from-js %) value)]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :fills value)))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :fills value)))))}
|
||||||
|
|
||||||
{:name "strokes"
|
{:name "strokes"
|
||||||
:get #(-> % proxy->shape :strokes array-to-js)
|
:get #(-> % proxy->shape :strokes array-to-js)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (obj/get self "$id")
|
(let [id (obj/get self "$id")
|
||||||
value (mapv #(utils/from-js % #{:stroke-style :stroke-alignment}) value)]
|
value (mapv #(utils/from-js % #{:stroke-style :stroke-alignment}) value)]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :strokes value)))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :strokes value)))))}
|
||||||
|
|
||||||
{:name "layoutChild"
|
{:name "layoutChild"
|
||||||
:get
|
:get
|
||||||
|
@ -421,7 +420,7 @@
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (obj/get self "$id")
|
(let [id (obj/get self "$id")
|
||||||
value (mapv #(utils/from-js %) value)]
|
value (mapv #(utils/from-js %) value)]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :grids value)))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :grids value)))))}
|
||||||
|
|
||||||
{:name "horizontalSizing"
|
{:name "horizontalSizing"
|
||||||
:get #(-> % proxy->shape :layout-item-h-sizing (d/nilv :fix) d/name)
|
:get #(-> % proxy->shape :layout-item-h-sizing (d/nilv :fix) d/name)
|
||||||
|
@ -463,7 +462,7 @@
|
||||||
ted/import-content
|
ted/import-content
|
||||||
ted/create-editor-state)]
|
ted/create-editor-state)]
|
||||||
(st/emit! (dwt/update-editor-state shape editor))))
|
(st/emit! (dwt/update-editor-state shape editor))))
|
||||||
(st/emit! (dwc/update-shapes [id] #(txt/change-text % value)))))}
|
(st/emit! (dwsh/update-shapes [id] #(txt/change-text % value)))))}
|
||||||
|
|
||||||
{:name "growType"
|
{:name "growType"
|
||||||
:get #(-> % proxy->shape :grow-type d/name)
|
:get #(-> % proxy->shape :grow-type d/name)
|
||||||
|
@ -472,7 +471,7 @@
|
||||||
(let [id (obj/get self "$id")
|
(let [id (obj/get self "$id")
|
||||||
value (keyword value)]
|
value (keyword value)]
|
||||||
(when (contains? #{:auto-width :auto-height :fixed} value)
|
(when (contains? #{:auto-width :auto-height :fixed} value)
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :grow-type value))))))}
|
(st/emit! (dwsh/update-shapes [id] #(assoc % :grow-type value))))))}
|
||||||
|
|
||||||
{:name "fontId"
|
{:name "fontId"
|
||||||
:get #(-> % proxy->shape text-props :font-id)
|
:get #(-> % proxy->shape text-props :font-id)
|
||||||
|
|
|
@ -8,7 +8,10 @@
|
||||||
"A collection of helpers for work with javascript objects."
|
"A collection of helpers for work with javascript objects."
|
||||||
(:refer-clojure :exclude [set! new get get-in merge clone contains? array? into-array])
|
(:refer-clojure :exclude [set! new get get-in merge clone contains? array? into-array])
|
||||||
(:require
|
(:require
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]
|
||||||
|
;; FIXME: we use goog.string here for performance reasons, pending
|
||||||
|
;; to apply this optimizations directly to cuerdas.
|
||||||
|
[goog.string :as gstr]))
|
||||||
|
|
||||||
(defn array?
|
(defn array?
|
||||||
[o]
|
[o]
|
||||||
|
@ -105,28 +108,51 @@
|
||||||
[obj prop]
|
[obj prop]
|
||||||
(js* "~{} in ~{}" prop obj))
|
(js* "~{} in ~{}" prop obj))
|
||||||
|
|
||||||
|
(defn- transform-prop-key
|
||||||
|
[s]
|
||||||
|
(let [result (js* "~{}.replace(\":\", \"-\").replace(/-./g, x=>x[1].toUpperCase())", s)]
|
||||||
|
(if ^boolean (gstr/startsWith s "-")
|
||||||
|
(gstr/capitalize result)
|
||||||
|
result)))
|
||||||
|
|
||||||
|
(defn prop-key-fn
|
||||||
|
[k]
|
||||||
|
(when (string? k)
|
||||||
|
(cond
|
||||||
|
(or (= k "class")
|
||||||
|
(= k "class-name"))
|
||||||
|
"className"
|
||||||
|
|
||||||
|
(gstr/startsWith k "data-")
|
||||||
|
k
|
||||||
|
|
||||||
|
:else
|
||||||
|
(transform-prop-key k))))
|
||||||
|
|
||||||
(defn map->obj
|
(defn map->obj
|
||||||
[x]
|
"A simplified version of clj->js with focus on performance"
|
||||||
(cond
|
([x] (map->obj x identity))
|
||||||
(nil? x)
|
([x ^function key-fn]
|
||||||
nil
|
(cond
|
||||||
|
(nil? x)
|
||||||
|
nil
|
||||||
|
|
||||||
(keyword? x)
|
(keyword? x)
|
||||||
(name x)
|
(name x)
|
||||||
|
|
||||||
(map? x)
|
(map? x)
|
||||||
(reduce-kv (fn [m k v]
|
(reduce-kv (fn [m k v]
|
||||||
(let [k (if (keyword? k) (name k) k)]
|
(let [k (if (keyword? k) (name k) k)]
|
||||||
(unchecked-set m k (^function map->obj v))
|
(unchecked-set m (key-fn k) (map->obj v key-fn))
|
||||||
m))
|
m))
|
||||||
#js {}
|
#js {}
|
||||||
x)
|
x)
|
||||||
|
|
||||||
(coll? x)
|
(coll? x)
|
||||||
(reduce (fn [arr v]
|
(reduce (fn [arr v]
|
||||||
(.push arr v)
|
(.push arr v)
|
||||||
arr)
|
arr)
|
||||||
(array)
|
(array)
|
||||||
x)
|
x)
|
||||||
|
|
||||||
:else x))
|
:else x)))
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
[app.common.uri :as u]
|
[app.common.uri :as u]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
|
[app.main.data.changes :as dwc]
|
||||||
[app.main.data.dashboard.shortcuts]
|
[app.main.data.dashboard.shortcuts]
|
||||||
[app.main.data.preview :as dp]
|
[app.main.data.preview :as dp]
|
||||||
[app.main.data.viewer.shortcuts]
|
[app.main.data.viewer.shortcuts]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.changes :as dch]
|
|
||||||
[app.main.data.workspace.path.shortcuts]
|
[app.main.data.workspace.path.shortcuts]
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
[app.main.data.workspace.shortcuts]
|
[app.main.data.workspace.shortcuts]
|
||||||
|
@ -52,8 +52,6 @@
|
||||||
(def debug-exclude-events
|
(def debug-exclude-events
|
||||||
#{:app.main.data.workspace.notifications/handle-pointer-update
|
#{:app.main.data.workspace.notifications/handle-pointer-update
|
||||||
:app.main.data.workspace.notifications/handle-pointer-send
|
:app.main.data.workspace.notifications/handle-pointer-send
|
||||||
:app.main.data.workspace.persistence/update-persistence-status
|
|
||||||
:app.main.data.workspace.changes/update-indices
|
|
||||||
:app.main.data.websocket/send-message
|
:app.main.data.websocket/send-message
|
||||||
:app.main.data.workspace.selection/change-hover-state})
|
:app.main.data.workspace.selection/change-hover-state})
|
||||||
|
|
||||||
|
@ -303,7 +301,7 @@
|
||||||
|
|
||||||
(let [file-id (:current-file-id @st/state)
|
(let [file-id (:current-file-id @st/state)
|
||||||
changes (t/decode-str changes*)]
|
changes (t/decode-str changes*)]
|
||||||
(st/emit! (dch/commit-changes {:redo-changes changes
|
(st/emit! (dwc/commit-changes {:redo-changes changes
|
||||||
:undo-changes []
|
:undo-changes []
|
||||||
:save-undo? true
|
:save-undo? true
|
||||||
:file-id file-id}))))
|
:file-id file-id}))))
|
||||||
|
|
|
@ -3,12 +3,13 @@
|
||||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
;;
|
;;
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns frontend-tests.basic-shapes-test
|
(ns frontend-tests.basic-shapes-test
|
||||||
(:require
|
(:require
|
||||||
[app.common.test-helpers.files :as cthf]
|
[app.common.test-helpers.files :as cthf]
|
||||||
[app.common.test-helpers.ids-map :as cthi]
|
[app.common.test-helpers.ids-map :as cthi]
|
||||||
[app.common.test-helpers.shapes :as cths]
|
[app.common.test-helpers.shapes :as cths]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[cljs.test :as t :include-macros true]
|
[cljs.test :as t :include-macros true]
|
||||||
[frontend-tests.helpers.state :as ths]))
|
[frontend-tests.helpers.state :as ths]))
|
||||||
|
|
||||||
|
@ -21,12 +22,12 @@
|
||||||
(-> (cthf/sample-file :file1 :page-label :page1)
|
(-> (cthf/sample-file :file1 :page-label :page1)
|
||||||
(cths/add-sample-shape :shape1)))
|
(cths/add-sample-shape :shape1)))
|
||||||
|
|
||||||
;; ==== Action
|
;; ==== Action
|
||||||
events
|
events
|
||||||
[(dch/update-shapes [(cthi/id :shape1)]
|
[(dwsh/update-shapes [(cthi/id :shape1)]
|
||||||
#(assoc % :fills
|
#(assoc % :fills
|
||||||
(cths/sample-fills-color :fill-color
|
(cths/sample-fills-color :fill-color
|
||||||
"#fabada")))]]
|
"#fabada")))]]
|
||||||
|
|
||||||
(ths/run-store
|
(ths/run-store
|
||||||
store done events
|
store done events
|
||||||
|
@ -40,7 +41,7 @@
|
||||||
fills' (:fills shape1')
|
fills' (:fills shape1')
|
||||||
fill' (first fills')]
|
fill' (first fills')]
|
||||||
|
|
||||||
;; ==== Check
|
;; ==== Check
|
||||||
(t/is (some? shape1'))
|
(t/is (some? shape1'))
|
||||||
(t/is (= (count fills') 1))
|
(t/is (= (count fills') 1))
|
||||||
(t/is (= (:fill-color fill') "#fabada"))
|
(t/is (= (:fill-color fill') "#fabada"))
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
event occurs, and then call the function with the final state at
|
event occurs, and then call the function with the final state at
|
||||||
this point."
|
this point."
|
||||||
[state done completed-cb]
|
[state done completed-cb]
|
||||||
(let [store (ptk/store {:state state :on-error on-error})
|
(let [store (ptk/store {:state state :on-error on-error})
|
||||||
stream (ptk/input-stream store)
|
stream (ptk/input-stream store)
|
||||||
stream (->> stream
|
stream (->> stream
|
||||||
(rx/take-until (rx/filter #(= :the/end %) stream))
|
(rx/take-until (rx/filter #(= :the/end %) stream))
|
||||||
|
|
|
@ -38,21 +38,3 @@
|
||||||
{:name "Rect 1"}))
|
{:name "Rect 1"}))
|
||||||
shape (thp/get-shape state :shape1)]
|
shape (thp/get-shape state :shape1)]
|
||||||
(t/is (= (:name shape) "Rect 1")))))
|
(t/is (= (:name shape) "Rect 1")))))
|
||||||
|
|
||||||
(t/deftest asynctest
|
|
||||||
(t/testing "asynctest"
|
|
||||||
(t/async done
|
|
||||||
(let [state {}
|
|
||||||
color {:color clr/white}
|
|
||||||
|
|
||||||
store (the/prepare-store state done
|
|
||||||
(fn [new-state]
|
|
||||||
(t/is (= (get-in new-state [:workspace-data
|
|
||||||
:recent-colors])
|
|
||||||
[color]))))]
|
|
||||||
|
|
||||||
(ptk/emit!
|
|
||||||
store
|
|
||||||
(dwl/add-recent-color color)
|
|
||||||
:the/end)))))
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue