|
@@ -2,79 +2,37 @@
|
|
"Whiteboard related handlers"
|
|
"Whiteboard related handlers"
|
|
(:require [datascript.core :as d]
|
|
(:require [datascript.core :as d]
|
|
[dommy.core :as dom]
|
|
[dommy.core :as dom]
|
|
|
|
+ [frontend.db :as db]
|
|
[frontend.db.model :as model]
|
|
[frontend.db.model :as model]
|
|
[frontend.db.utils :as db-utils]
|
|
[frontend.db.utils :as db-utils]
|
|
[frontend.handler.editor :as editor-handler]
|
|
[frontend.handler.editor :as editor-handler]
|
|
[frontend.handler.route :as route-handler]
|
|
[frontend.handler.route :as route-handler]
|
|
|
|
+ [frontend.modules.editor.undo-redo :as history]
|
|
[frontend.modules.outliner.core :as outliner]
|
|
[frontend.modules.outliner.core :as outliner]
|
|
[frontend.modules.outliner.file :as outliner-file]
|
|
[frontend.modules.outliner.file :as outliner-file]
|
|
[frontend.state :as state]
|
|
[frontend.state :as state]
|
|
[frontend.util :as util]
|
|
[frontend.util :as util]
|
|
[logseq.graph-parser.util :as gp-util]
|
|
[logseq.graph-parser.util :as gp-util]
|
|
[logseq.graph-parser.whiteboard :as gp-whiteboard]
|
|
[logseq.graph-parser.whiteboard :as gp-whiteboard]
|
|
- [promesa.core :as p]))
|
|
|
|
|
|
+ [promesa.core :as p]
|
|
|
|
+ [goog.object :as gobj]
|
|
|
|
+ [clojure.set :as set]
|
|
|
|
+ [clojure.string :as string]
|
|
|
|
+ [cljs-bean.core :as bean]))
|
|
|
|
|
|
-(defn shape->block [shape page-name idx]
|
|
|
|
|
|
+(defn js->clj-keywordize
|
|
|
|
+ [obj]
|
|
|
|
+ (js->clj obj :keywordize-keys true))
|
|
|
|
+
|
|
|
|
+(defn shape->block [shape page-name]
|
|
(let [properties {:ls-type :whiteboard-shape
|
|
(let [properties {:ls-type :whiteboard-shape
|
|
- :logseq.tldraw.shape (assoc shape :index idx)}
|
|
|
|
|
|
+ :logseq.tldraw.shape shape}
|
|
block {:block/page {:block/name (util/page-name-sanity-lc page-name)}
|
|
block {:block/page {:block/name (util/page-name-sanity-lc page-name)}
|
|
:block/parent {:block/name page-name}
|
|
:block/parent {:block/name page-name}
|
|
:block/properties properties}
|
|
:block/properties properties}
|
|
additional-props (gp-whiteboard/with-whiteboard-block-props block page-name)]
|
|
additional-props (gp-whiteboard/with-whiteboard-block-props block page-name)]
|
|
(merge block additional-props)))
|
|
(merge block additional-props)))
|
|
|
|
|
|
-(defn- tldr-page->blocks-tx [page-name tldr-data]
|
|
|
|
- (let [page-name (util/page-name-sanity-lc page-name)
|
|
|
|
- page-entity (model/get-page page-name)
|
|
|
|
- page-block (merge {:block/name page-name
|
|
|
|
- :block/type "whiteboard"
|
|
|
|
- :block/properties {:ls-type :whiteboard-page
|
|
|
|
- :logseq.tldraw.page (dissoc tldr-data :shapes)}}
|
|
|
|
- (when page-entity (select-keys page-entity [:block/created-at])))
|
|
|
|
- ;; todo: use get-paginated-blocks instead?
|
|
|
|
- existing-blocks (model/get-page-blocks-no-cache (state/get-current-repo)
|
|
|
|
- page-name
|
|
|
|
- {:pull-keys '[:db/id
|
|
|
|
- :block/uuid
|
|
|
|
- :block/properties [:ls-type]
|
|
|
|
- :block/created-at
|
|
|
|
- :block/updated-at
|
|
|
|
- {:block/parent [:block/uuid]}]})
|
|
|
|
- id->block (zipmap (map :block/uuid existing-blocks) existing-blocks)
|
|
|
|
- shapes (:shapes tldr-data)
|
|
|
|
- ;; we should maintain the order of the shapes in the page
|
|
|
|
- ;; bring back/forward is depending on this ordering
|
|
|
|
- blocks (map-indexed
|
|
|
|
- (fn [idx shape]
|
|
|
|
- (let [block (shape->block shape page-name idx)]
|
|
|
|
- (merge block
|
|
|
|
- (select-keys (id->block (:block/uuid block))
|
|
|
|
- [:block/created-at :block/updated-at])))) shapes)
|
|
|
|
- block-ids (->> shapes
|
|
|
|
- (map (fn [shape] (when (= (:blockType shape) "B")
|
|
|
|
- (uuid (:pageId shape)))))
|
|
|
|
- (concat (map :block/uuid blocks))
|
|
|
|
- (remove nil?)
|
|
|
|
- (set))
|
|
|
|
- ;; delete blocks when all of the following are false
|
|
|
|
- ;; - the block is not in the new blocks list
|
|
|
|
- ;; - the block's parent is not in the new block list
|
|
|
|
- ;; - the block is not a shape block
|
|
|
|
- delete-blocks (filterv (fn [block]
|
|
|
|
- (not
|
|
|
|
- (or (block-ids (:block/uuid block))
|
|
|
|
- (block-ids (:block/uuid (:block/parent block)))
|
|
|
|
- (not (gp-whiteboard/shape-block? block)))))
|
|
|
|
- existing-blocks)
|
|
|
|
- ;; always recalcuate refs for now.
|
|
|
|
- ;; todo: optimize in frontend.modules.outliner.pipeline/compute-block-path-refs?
|
|
|
|
- refs-tx (mapcat (fn [m] [[:db/retract (:db/id m) :block/path-refs]
|
|
|
|
- [:db/retract (:db/id m) :block/refs]]) existing-blocks)
|
|
|
|
- delete-blocks-tx (mapv (fn [s] [:db/retractEntity (:db/id s)]) delete-blocks)
|
|
|
|
- page-and-blocks (->> (cons page-block blocks)
|
|
|
|
- (map outliner/block-with-timestamps))]
|
|
|
|
- (concat refs-tx page-and-blocks delete-blocks-tx)))
|
|
|
|
-
|
|
|
|
(defn- get-whiteboard-clj [page-name]
|
|
(defn- get-whiteboard-clj [page-name]
|
|
(when (model/page-exists? page-name)
|
|
(when (model/page-exists? page-name)
|
|
(let [page-block (model/get-page page-name)
|
|
(let [page-block (model/get-page page-name)
|
|
@@ -82,12 +40,20 @@
|
|
blocks (model/get-page-blocks-no-cache page-name)]
|
|
blocks (model/get-page-blocks-no-cache page-name)]
|
|
[page-block blocks])))
|
|
[page-block blocks])))
|
|
|
|
|
|
|
|
+(defn- build-shapes
|
|
|
|
+ [page-block blocks]
|
|
|
|
+ (let [shapes-index (get-in page-block [:block/properties :logseq.tldraw.page :shapes-index])
|
|
|
|
+ shape-id->index (zipmap shapes-index (range 0 (count shapes-index)))]
|
|
|
|
+ (->> blocks
|
|
|
|
+ (map (fn [block]
|
|
|
|
+ (assoc block :index (get shape-id->index (str (:block/uuid block)) 0))))
|
|
|
|
+ (sort-by :index)
|
|
|
|
+ (filter gp-whiteboard/shape-block?)
|
|
|
|
+ (map gp-whiteboard/block->shape))))
|
|
|
|
+
|
|
(defn- whiteboard-clj->tldr [page-block blocks]
|
|
(defn- whiteboard-clj->tldr [page-block blocks]
|
|
(let [id (str (:block/uuid page-block))
|
|
(let [id (str (:block/uuid page-block))
|
|
- shapes (->> blocks
|
|
|
|
- (filter gp-whiteboard/shape-block?)
|
|
|
|
- (map gp-whiteboard/block->shape)
|
|
|
|
- (sort-by :index))
|
|
|
|
|
|
+ shapes (build-shapes page-block blocks)
|
|
tldr-page (gp-whiteboard/page-block->tldr-page page-block)
|
|
tldr-page (gp-whiteboard/page-block->tldr-page page-block)
|
|
assets (:assets tldr-page)
|
|
assets (:assets tldr-page)
|
|
tldr-page (dissoc tldr-page :assets)]
|
|
tldr-page (dissoc tldr-page :assets)]
|
|
@@ -99,23 +65,128 @@
|
|
:name (:block/name page-block)
|
|
:name (:block/name page-block)
|
|
:shapes shapes})]})))
|
|
:shapes shapes})]})))
|
|
|
|
|
|
-(defn transact-tldr! [page-name tldr]
|
|
|
|
- (let [{:keys [pages assets]} (js->clj tldr :keywordize-keys true)
|
|
|
|
- page (first pages)
|
|
|
|
- tx (tldr-page->blocks-tx page-name (assoc page :assets assets))]
|
|
|
|
- (db-utils/transact! tx)))
|
|
|
|
-
|
|
|
|
-(defn get-default-tldr
|
|
|
|
- [page-id]
|
|
|
|
- {:currentPageId page-id,
|
|
|
|
- :selectedIds [],
|
|
|
|
- :pages [{:id page-id
|
|
|
|
- :name page-id
|
|
|
|
- :ls-type :whiteboard-page
|
|
|
|
- :shapes []
|
|
|
|
- :bindings {}
|
|
|
|
- :nonce 1}]
|
|
|
|
- :assets []})
|
|
|
|
|
|
+(defn build-page-block
|
|
|
|
+ [page-name tldraw-page assets shapes-index]
|
|
|
|
+ (let [page-entity (model/get-page page-name)
|
|
|
|
+ get-k #(gobj/get tldraw-page %)]
|
|
|
|
+ {:block/name page-name
|
|
|
|
+ :block/type "whiteboard"
|
|
|
|
+ :block/properties {:ls-type :whiteboard-page
|
|
|
|
+ :logseq.tldraw.page {:id (get-k "id")
|
|
|
|
+ :name (get-k "name")
|
|
|
|
+ :bindings (js->clj-keywordize (get-k "bindings"))
|
|
|
|
+ :nonce (get-k "nonce")
|
|
|
|
+ :assets (js->clj-keywordize assets)
|
|
|
|
+ :shapes-index shapes-index}}
|
|
|
|
+ :block/updated-at (util/time-ms)
|
|
|
|
+ :block/created-at (or (:block/created-at page-entity)
|
|
|
|
+ (util/time-ms))}))
|
|
|
|
+
|
|
|
|
+(defn- compute-tx
|
|
|
|
+ [^js app ^js tl-page new-id-nonces db-id-nonces page-name]
|
|
|
|
+ (let [assets (js->clj-keywordize (.getCleanUpAssets app))
|
|
|
|
+ new-shapes (.-shapes tl-page)
|
|
|
|
+ shapes-index (map #(gobj/get % "id") new-shapes)
|
|
|
|
+ upsert-shapes (->> (set/difference new-id-nonces db-id-nonces)
|
|
|
|
+ (map (fn [{:keys [id]}]
|
|
|
|
+ (-> (.-serialized ^js (.getShapeById tl-page id))
|
|
|
|
+ js->clj-keywordize)))
|
|
|
|
+ (set))
|
|
|
|
+ old-ids (set (map :id db-id-nonces))
|
|
|
|
+ new-ids (set (map :id new-id-nonces))
|
|
|
|
+ created-ids (->> (set/difference new-ids old-ids)
|
|
|
|
+ (remove string/blank?)
|
|
|
|
+ (set))
|
|
|
|
+ created-shapes (set (filter #(created-ids (:id %)) upsert-shapes))
|
|
|
|
+ deleted-ids (->> (set/difference old-ids new-ids)
|
|
|
|
+ (remove string/blank?))
|
|
|
|
+ repo (state/get-current-repo)
|
|
|
|
+ deleted-shapes (when (seq deleted-ids)
|
|
|
|
+ (->> (db/pull-many repo '[*] (mapv (fn [id] [:block/uuid (uuid id)]) deleted-ids))
|
|
|
|
+ (map (fn [b]
|
|
|
|
+ (get-in b [:block/properties :logseq.tldraw.shape])))))
|
|
|
|
+ deleted-shapes-tx (mapv (fn [id] [:db/retractEntity [:block/uuid (uuid id)]]) deleted-ids)
|
|
|
|
+ with-timestamps (fn [block]
|
|
|
|
+ (if (contains? created-ids (str (:block/uuid block)))
|
|
|
|
+ (assoc block :block/updated-at (util/time-ms))
|
|
|
|
+ (outliner/block-with-timestamps block)))
|
|
|
|
+ changed-shapes (set/difference upsert-shapes created-shapes)
|
|
|
|
+ prev-changed-blocks (when (seq changed-shapes)
|
|
|
|
+ (db/pull-many repo '[*] (mapv (fn [shape]
|
|
|
|
+ [:block/uuid (uuid (:id shape))]) changed-shapes)))]
|
|
|
|
+ {:page-block (build-page-block page-name tl-page assets shapes-index)
|
|
|
|
+ :upserted-blocks (->> upsert-shapes
|
|
|
|
+ (map #(shape->block % page-name))
|
|
|
|
+ (map with-timestamps))
|
|
|
|
+ :delete-blocks deleted-shapes-tx
|
|
|
|
+ :metadata {:whiteboard/transact? true
|
|
|
|
+ :data {:page-name page-name
|
|
|
|
+ :deleted-shapes deleted-shapes
|
|
|
|
+ :new-shapes created-shapes
|
|
|
|
+ :changed-shapes changed-shapes
|
|
|
|
+ :prev-changed-blocks prev-changed-blocks}}}))
|
|
|
|
+
|
|
|
|
+(defonce *last-shapes-nonce (atom {}))
|
|
|
|
+(defn transact-tldr-delta! [page-name ^js app]
|
|
|
|
+ (let [tl-page ^js (second (first (.-pages app)))
|
|
|
|
+ shapes (.-shapes ^js tl-page)
|
|
|
|
+ new-id-nonces (set (map (fn [shape]
|
|
|
|
+ {:id (.-id shape)
|
|
|
|
+ :nonce (.-nonce shape)}) shapes))
|
|
|
|
+ repo (state/get-current-repo)
|
|
|
|
+ db-id-nonces (or
|
|
|
|
+ (get-in @*last-shapes-nonce [repo page-name])
|
|
|
|
+ (set (->> (model/get-whiteboard-id-nonces repo page-name)
|
|
|
|
+ (map #(update % :id str)))))
|
|
|
|
+ {:keys [page-block upserted-blocks delete-blocks metadata]}
|
|
|
|
+ (compute-tx app tl-page new-id-nonces db-id-nonces page-name)
|
|
|
|
+ tx-data (concat delete-blocks [page-block] upserted-blocks)
|
|
|
|
+ new-shapes (get-in metadata [:data :new-shapes])
|
|
|
|
+ metadata' (cond
|
|
|
|
+ ;; group
|
|
|
|
+ (some #(= "group" (:type %)) new-shapes)
|
|
|
|
+ (assoc metadata :whiteboard/op :group)
|
|
|
|
+
|
|
|
|
+ ;; ungroup
|
|
|
|
+ (some #(= "group" (:type %)) (get-in metadata [:data :deleted-shapes]))
|
|
|
|
+ (assoc metadata :whiteboard/op :un-group)
|
|
|
|
+
|
|
|
|
+ ;; arrow
|
|
|
|
+ (some #(and (= "line" (:type %))
|
|
|
|
+ (= "arrow "(:end (:decorations %)))) new-shapes)
|
|
|
|
+
|
|
|
|
+ (assoc metadata :whiteboard/op :new-arrow)
|
|
|
|
+ :else
|
|
|
|
+ metadata)
|
|
|
|
+ metadata' (if (seq (concat upserted-blocks delete-blocks))
|
|
|
|
+ metadata'
|
|
|
|
+ (assoc metadata :undo? true))]
|
|
|
|
+ (swap! *last-shapes-nonce assoc-in [repo page-name] new-id-nonces)
|
|
|
|
+ (if (contains? #{:new-arrow} (:whiteboard/op metadata'))
|
|
|
|
+ (state/set-state! :whiteboard/pending-tx-data
|
|
|
|
+ {:tx-data tx-data
|
|
|
|
+ :metadata metadata'})
|
|
|
|
+ (let [pending-tx-data (:whiteboard/pending-tx-data @state/state)
|
|
|
|
+ tx-data' (concat (:tx-data pending-tx-data) tx-data)
|
|
|
|
+ metadata'' (merge metadata' (:metadata pending-tx-data))]
|
|
|
|
+ (state/set-state! :whiteboard/pending-tx-data {})
|
|
|
|
+ (db-utils/transact! repo tx-data' metadata'')))))
|
|
|
|
+
|
|
|
|
+(defn get-default-new-whiteboard-tx
|
|
|
|
+ [page-name id]
|
|
|
|
+ [#:block{:name page-name,
|
|
|
|
+ :type "whiteboard",
|
|
|
|
+ :properties
|
|
|
|
+ {:ls-type :whiteboard-page,
|
|
|
|
+ :logseq.tldraw.page
|
|
|
|
+ {:id id,
|
|
|
|
+ :name page-name,
|
|
|
|
+ :ls-type :whiteboard-page,
|
|
|
|
+ :bindings {},
|
|
|
|
+ :nonce 1,
|
|
|
|
+ :assets []}},
|
|
|
|
+ :updated-at (util/time-ms),
|
|
|
|
+ :created-at (util/time-ms)}])
|
|
|
|
|
|
(defn get-whiteboard-entity [page-name]
|
|
(defn get-whiteboard-entity [page-name]
|
|
(db-utils/entity [:block/name (util/page-name-sanity-lc page-name)]))
|
|
(db-utils/entity [:block/name (util/page-name-sanity-lc page-name)]))
|
|
@@ -125,17 +196,15 @@
|
|
(create-new-whiteboard-page! nil))
|
|
(create-new-whiteboard-page! nil))
|
|
([name]
|
|
([name]
|
|
(let [uuid (or (and name (parse-uuid name)) (d/squuid))
|
|
(let [uuid (or (and name (parse-uuid name)) (d/squuid))
|
|
- name (or name (str uuid))
|
|
|
|
- tldr (get-default-tldr (str uuid))]
|
|
|
|
- (transact-tldr! name (get-default-tldr (str uuid)))
|
|
|
|
|
|
+ name (or name (str uuid))]
|
|
|
|
+ (db/transact! (get-default-new-whiteboard-tx name (str uuid)))
|
|
(let [entity (get-whiteboard-entity name)
|
|
(let [entity (get-whiteboard-entity name)
|
|
tx (assoc (select-keys entity [:db/id])
|
|
tx (assoc (select-keys entity [:db/id])
|
|
:block/uuid uuid)]
|
|
:block/uuid uuid)]
|
|
(db-utils/transact! [tx])
|
|
(db-utils/transact! [tx])
|
|
(let [page-entity (get-whiteboard-entity name)]
|
|
(let [page-entity (get-whiteboard-entity name)]
|
|
(when (and page-entity (nil? (:block/file page-entity)))
|
|
(when (and page-entity (nil? (:block/file page-entity)))
|
|
- (outliner-file/sync-to-file page-entity))))
|
|
|
|
- tldr)))
|
|
|
|
|
|
+ (outliner-file/sync-to-file page-entity)))))))
|
|
|
|
|
|
(defn create-new-whiteboard-and-redirect!
|
|
(defn create-new-whiteboard-and-redirect!
|
|
([]
|
|
([]
|
|
@@ -237,10 +306,7 @@
|
|
([{:keys [pages blocks]} api]
|
|
([{:keys [pages blocks]} api]
|
|
(let [page-block (first pages)
|
|
(let [page-block (first pages)
|
|
;; FIXME: should also clone normal blocks
|
|
;; FIXME: should also clone normal blocks
|
|
- shapes (->> blocks
|
|
|
|
- (filter gp-whiteboard/shape-block?)
|
|
|
|
- (map gp-whiteboard/block->shape)
|
|
|
|
- (sort-by :index))
|
|
|
|
|
|
+ shapes (build-shapes page-block blocks)
|
|
tldr-page (gp-whiteboard/page-block->tldr-page page-block)
|
|
tldr-page (gp-whiteboard/page-block->tldr-page page-block)
|
|
assets (:assets tldr-page)
|
|
assets (:assets tldr-page)
|
|
bindings (:bindings tldr-page)]
|
|
bindings (:bindings tldr-page)]
|
|
@@ -265,3 +331,88 @@
|
|
(state/set-onboarding-whiteboard! true))
|
|
(state/set-onboarding-whiteboard! true))
|
|
(p/catch
|
|
(p/catch
|
|
(fn [e] (js/console.warn "Failed to populate onboarding whiteboard" e))))))
|
|
(fn [e] (js/console.warn "Failed to populate onboarding whiteboard" e))))))
|
|
|
|
+
|
|
|
|
+(defn- delete-shapes!
|
|
|
|
+ [^js api shapes]
|
|
|
|
+ (apply (.-deleteShapes api) (map :id shapes)))
|
|
|
|
+
|
|
|
|
+(defn- create-shapes!
|
|
|
|
+ [^js api shapes]
|
|
|
|
+ (apply (.-createShapes api) (bean/->js shapes)))
|
|
|
|
+
|
|
|
|
+(defn- update-shapes!
|
|
|
|
+ [^js api shapes]
|
|
|
|
+ (apply (.-updateShapes api) (bean/->js shapes)))
|
|
|
|
+
|
|
|
|
+(defn- select-shapes
|
|
|
|
+ [^js api ids]
|
|
|
|
+ (apply (.-selectShapes api) ids))
|
|
|
|
+
|
|
|
|
+(defn update-bindings!
|
|
|
|
+ [^js tl-page page-name]
|
|
|
|
+ (when-let [page (db/entity [:block/name page-name])]
|
|
|
|
+ (let [bindings (get-in page [:block/properties :logseq.tldraw.page :bindings])]
|
|
|
|
+ (when (seq bindings)
|
|
|
|
+ (.updateBindings tl-page (bean/->js bindings))))))
|
|
|
|
+
|
|
|
|
+(defn undo!
|
|
|
|
+ [{:keys [tx-meta]}]
|
|
|
|
+ (history/pause-listener!)
|
|
|
|
+ (try
|
|
|
|
+ (when-let [app (state/active-tldraw-app)]
|
|
|
|
+ (let [{:keys [deleted-shapes new-shapes changed-shapes prev-changed-blocks]} (:data tx-meta)
|
|
|
|
+ whiteboard-op (:whiteboard/op tx-meta)
|
|
|
|
+ ^js api (.-api app)]
|
|
|
|
+ (when api
|
|
|
|
+ (case whiteboard-op
|
|
|
|
+ :group
|
|
|
|
+ (do
|
|
|
|
+ (select-shapes api (map :id new-shapes))
|
|
|
|
+ (.unGroup api))
|
|
|
|
+ :un-group
|
|
|
|
+ (do
|
|
|
|
+ (select-shapes api (mapcat :children deleted-shapes))
|
|
|
|
+ (.doGroup api))
|
|
|
|
+ (do
|
|
|
|
+ (when (seq deleted-shapes)
|
|
|
|
+ (create-shapes! api deleted-shapes))
|
|
|
|
+ (when (seq new-shapes)
|
|
|
|
+ (delete-shapes! api new-shapes))
|
|
|
|
+ (when (seq changed-shapes)
|
|
|
|
+ (let [prev-shapes (map (fn [b] (get-in b [:block/properties :logseq.tldraw.shape]))
|
|
|
|
+ prev-changed-blocks)]
|
|
|
|
+ (update-shapes! api prev-shapes))))))))
|
|
|
|
+ (catch :default e
|
|
|
|
+ (js/console.error e)))
|
|
|
|
+ (history/resume-listener!))
|
|
|
|
+
|
|
|
|
+(defn redo!
|
|
|
|
+ [{:keys [tx-meta]}]
|
|
|
|
+ (history/pause-listener!)
|
|
|
|
+ (try
|
|
|
|
+ (when-let [app (state/active-tldraw-app)]
|
|
|
|
+ (let [{:keys [page-name deleted-shapes new-shapes changed-shapes]} (:data tx-meta)
|
|
|
|
+ whiteboard-op (:whiteboard/op tx-meta)
|
|
|
|
+ ^js api (.-api app)
|
|
|
|
+ tl-page ^js (second (first (.-pages app)))]
|
|
|
|
+ (when api
|
|
|
|
+ (update-bindings! tl-page page-name)
|
|
|
|
+ (case whiteboard-op
|
|
|
|
+ :group
|
|
|
|
+ (do
|
|
|
|
+ (select-shapes api (mapcat :children new-shapes))
|
|
|
|
+ (.doGroup api))
|
|
|
|
+ :un-group
|
|
|
|
+ (do
|
|
|
|
+ (select-shapes api (map :id deleted-shapes))
|
|
|
|
+ (.unGroup api))
|
|
|
|
+ (do
|
|
|
|
+ (when (seq deleted-shapes)
|
|
|
|
+ (delete-shapes! api deleted-shapes))
|
|
|
|
+ (when (seq new-shapes)
|
|
|
|
+ (create-shapes! api new-shapes))
|
|
|
|
+ (when (seq changed-shapes)
|
|
|
|
+ (update-shapes! api changed-shapes)))))))
|
|
|
|
+ (catch :default e
|
|
|
|
+ (js/console.error e)))
|
|
|
|
+ (history/resume-listener!))
|