fix: history undo/redo

This commit is contained in:
Tienson Qin
2024-01-09 23:44:45 +08:00
parent 5e1a6b8952
commit 324ed9a9cd
6 changed files with 123 additions and 146 deletions

View File

@@ -45,9 +45,9 @@
(state/set-block-op-type! nil)
(state/set-state! [:editor/last-replace-ref-content-tx (state/get-current-repo)] nil)
(editor/save-current-block!)
(let [{:keys [editor-cursor app-state]} (undo-redo/undo)]
(restore-cursor! editor-cursor)
(restore-app-state! app-state))
(let [cursor-state (undo-redo/undo)]
(state/set-state! :ui/restore-cursor-state (select-keys cursor-state [:editor-cursor :app-state])))
(state/set-editor-op! nil))
(defn redo!
@@ -55,7 +55,6 @@
(util/stop e)
(state/set-editor-op! :redo)
(state/clear-editor-action!)
(let [{:keys [editor-cursor app-state]} (undo-redo/redo)]
(restore-cursor! editor-cursor)
(restore-app-state! app-state))
(let [cursor-state (undo-redo/redo)]
(state/set-state! :ui/restore-cursor-state (select-keys cursor-state [:editor-cursor :app-state])))
(state/set-editor-op! nil))

View File

@@ -4,9 +4,7 @@
[frontend.util.page :as page-util]
[frontend.state :as state]
[clojure.set :as set]
[medley.core :as medley]
[frontend.util.drawer :as drawer]
[frontend.handler.file-based.property.util :as property-util]))
[medley.core :as medley]))
;;;; APIs
@@ -37,22 +35,6 @@
(let [undo-stack (get-undo-stack)]
(swap! undo-stack conj txs)))
(comment
(defn get-content-from-txs
"For test."
[txs]
(filterv (fn [[_ a & y]]
(= :block/content a))
txs))
(defn get-content-from-stack
"For test."
[stack]
(mapv #(get-content-from-txs (:txs %)) stack))
(debug/pprint "pop entity" (get-content-from-txs (:txs removed-e)))
(debug/pprint "undo-stack" (get-content-from-stack @undo-stack)))
(defn pop-undo
[]
(let [undo-stack (get-undo-stack)]
@@ -151,15 +133,6 @@
(pop-undo))
(pop-undo)))
(defn- set-editor-content!
"Prevent block auto-save during undo/redo."
[]
(when-let [block (state/get-edit-block)]
(when-let [content (:block/content (db/entity (:db/id block)))]
(let [content' (-> (property-util/remove-built-in-properties (:block/format block) content)
(drawer/remove-logbook))]
(state/set-edit-content! (state/get-edit-input-id) content')))))
(defn- get-next-tx-editor-cursor
[tx-id]
(let [result (->> (sort (keys @(:history/tx->editor-cursor @state/state)))
@@ -198,7 +171,6 @@
(push-redo e)
(transact! new-txs (merge {:undo? true}
tx-meta))
(set-editor-content!)
(when (:whiteboard/transact? tx-meta)
(state/pub-event! [:whiteboard/undo e]))
(assoc e
@@ -216,7 +188,6 @@
(push-undo e)
(transact! new-txs (merge {:redo? true}
tx-meta))
(set-editor-content!)
(when (:whiteboard/transact? tx-meta)
(state/pub-event! [:whiteboard/redo e]))
(assoc e
@@ -239,7 +210,7 @@
(reset! *pause-listener false))
(defn listen-db-changes!
[{:keys [tx-data tx-meta blocks pages]}]
[{:keys [tx-id tx-data tx-meta blocks pages]}]
(when (and (seq tx-data)
(not (or (:undo? tx-meta)
(:redo? tx-meta)))
@@ -248,17 +219,14 @@
(set (map :a tx-data))
#{:block/created-at :block/updated-at})))
(reset-redo)
(if (:replace? tx-meta)
(let [removed-e (pop-undo)
entity (update removed-e :txs concat tx-data)]
(push-undo entity))
(let [updated-blocks (concat blocks pages)
entity {:blocks updated-blocks
:txs tx-data
:tx-meta tx-meta
:app-state (select-keys @state/state
[:route-match
:ui/sidebar-open?
:ui/sidebar-collapsed-blocks
:sidebar/blocks])}]
(push-undo entity)))))
(let [updated-blocks (concat blocks pages)
entity {:blocks updated-blocks
:tx-id tx-id
:txs tx-data
:tx-meta tx-meta
:app-state (select-keys @state/state
[:route-match
:ui/sidebar-open?
:ui/sidebar-collapsed-blocks
:sidebar/blocks])}]
(push-undo entity))))

View File

@@ -5,39 +5,32 @@
[frontend.db.react :as react]
[frontend.handler.file-based.property.util :as property-util]
[frontend.state :as state]
[frontend.util.cursor :as cursor]
[frontend.util.drawer :as drawer]
[frontend.modules.editor.undo-redo :as undo-redo]
[datascript.core :as d]
[datascript.db :as d-db]
[frontend.handler.ui :as ui-handler]))
[frontend.handler.ui :as ui-handler]
[frontend.handler.history :as history]))
(defn- reset-editing-block-content!
[tx-data tx-meta]
;; FIXME:
;; (let [repo (state/get-current-repo)
;; db? (config/db-based-graph? repo)]
;; (when-not (or (:undo? tx-meta) (:redo? tx-meta))
;; (when-let [edit-block (state/get-edit-block)]
;; (when-let [last-datom (-> (filter (fn [datom]
;; (and (= :block/content (:a datom))
;; (= (:e datom) (:db/id edit-block)))) tx-data)
;; last)]
;; (when-let [input (state/get-input)]
;; (when (:added last-datom)
;; (let [entity (db/entity (:e last-datom))
;; db-content (:block/content entity)
;; content (if db? db-content
;; (->> db-content
;; (property-util/remove-built-in-properties (or (:block/format entity) :markdown))
;; drawer/remove-logbook))
;; pos (cursor/pos input)
;; pos (when pos (if (zero? pos) (count content) 0))]
;; (when (not= (string/trim content)
;; (string/trim (.-value input)))
;; (state/set-edit-content! input content))
;; (when pos (cursor/move-cursor-to input pos)))))))))
)
[tx-data]
(let [repo (state/get-current-repo)
db? (config/db-based-graph? repo)]
(when-let [edit-block (state/get-edit-block)]
(when-let [last-datom (-> (filter (fn [datom]
(and (= :block/content (:a datom))
(= (:e datom) (:db/id edit-block)))) tx-data)
last)]
(when-let [input (state/get-input)]
(when (:added last-datom)
(let [entity (db/entity (:e last-datom))
db-content (:block/content entity)
content (if db? db-content
(->> db-content
(property-util/remove-built-in-properties (or (:block/format entity) :markdown))
drawer/remove-logbook))]
(when (not= (string/trim content)
(string/trim (.-value input)))
(state/set-edit-content! input content)))))))))
(defn store-undo-data!
[{:keys [tx-meta] :as opts}]
@@ -51,17 +44,36 @@
[repo page-names]
(state/update-state! [repo :unloaded-pages] #(remove page-names %)))
(defn- get-tx-id
[tx-report]
(get-in tx-report [:tempids :db/current-tx]))
(defn- update-current-tx-editor-cursor!
[tx-report]
(let [tx-id (get-tx-id tx-report)
editor-cursor (:ui/before-editor-cursor @state/state)]
(state/update-state! :history/tx->editor-cursor
(fn [m] (assoc m tx-id editor-cursor)))))
(defn restore-cursor-and-app-state!
[{:keys [editor-cursor app-state]}]
(history/restore-cursor! editor-cursor)
(history/restore-app-state! app-state))
(defn invoke-hooks
[{:keys [tx-meta tx-data deleted-block-uuids affected-keys blocks] :as opts}]
(let [{:keys [from-disk? new-graph? local-tx?]} tx-meta
(let [{:keys [from-disk? new-graph? local-tx? undo? redo?]} tx-meta
repo (state/get-current-repo)
tx-report {:tx-meta tx-meta
:tx-data tx-data}]
(when local-tx? (store-undo-data! opts))
(let [conn (db/get-db repo false)]
(d/transact! conn tx-data tx-meta))
(let [conn (db/get-db repo false)
tx-report (d/transact! conn tx-data tx-meta)]
(when local-tx?
(let [tx-id (get-tx-id tx-report)]
(store-undo-data! (assoc opts :tx-id tx-id))))
(when-not (or undo? redo?)
(update-current-tx-editor-cursor! tx-report)))
(let [pages (set (keep #(when (= :block/name (:a %)) (:v %)) tx-data))]
(when (seq pages)
@@ -79,7 +91,7 @@
(ui-handler/re-render-root!))
(do
(try
(reset-editing-block-content! tx-data tx-meta)
(reset-editing-block-content! tx-data)
(catch :default e
(prn :reset-editing-block-content)
(js/console.error e)))
@@ -87,6 +99,11 @@
(when-not (:graph/importing @state/state)
(react/refresh! repo tx-report affected-keys)
(when-let [state (:ui/restore-cursor-state @state/state)]
(when (or undo? redo?)
(restore-cursor-and-app-state! state)
(state/set-state! :ui/restore-cursor-state nil)))
(when (and state/lsp-enabled?
(seq blocks)
(<= (count blocks) 1000))
@@ -100,5 +117,5 @@
(when (some (fn [datom] (and
(= :block/uuid (:a datom))
(= (:v datom) deleting-block-id)
(true? (d-db/datom-added datom)))) tx-data) ; editing-block was added back (could be undo or from remote sync)
(true? (:added datom)))) tx-data) ; editing-block was added back (could be undo or from remote sync)
(state/set-state! :ui/deleting-block nil)))))

View File

@@ -13,30 +13,16 @@
(contains? (:file/unlinked-dirs @state/state)
(config/get-repo-dir repo))))
(def set-state-fn state/set-state!)
(defn get-tx-id
[tx-report]
(get-in tx-report [:tempids :db/current-tx]))
(defn after-transact-fn
[tx-report opts]
(let [tx-id (get-tx-id tx-report)]
(state/update-state! :history/tx->editor-cursor
(fn [m] (assoc m tx-id (:before-editor-cursor opts)))))
;; update the current edit block to include full information
(when-let [block (state/get-edit-block)]
(when (and (:block/uuid block) (not (:db/id block)))
(state/set-state! :editor/block (db/pull [:block/uuid (:block/uuid block)])))))))
(def set-state-fn state/set-state!)))
(defmacro transact!
[opts & body]
`(let [transact-opts# {:repo (state/get-current-repo)
:conn (db/get-db false)
:before-editor-cursor (state/get-current-edit-block-and-position)
:unlinked-graph? frontend.modules.outliner.ui/unlinked-graph?
:set-state-fn frontend.modules.outliner.ui/set-state-fn
:after-transact-fn frontend.modules.outliner.ui/after-transact-fn}]
(logseq.outliner.transaction/transact! (assoc ~opts :transact-opts transact-opts#)
~@body)))
`(do
(state/set-state! :ui/before-editor-cursor (state/get-current-edit-block-and-position))
(let [transact-opts# {:repo (state/get-current-repo)
:conn (db/get-db false)
:unlinked-graph? frontend.modules.outliner.ui/unlinked-graph?
:set-state-fn frontend.modules.outliner.ui/set-state-fn}]
(logseq.outliner.transaction/transact! (assoc ~opts :transact-opts transact-opts#)
~@body))))

View File

@@ -1966,34 +1966,38 @@ Similar to re-frame subscriptions"
(when (first elements)
(util/scroll-to-element (gobj/get (first elements) "id")))
(exit-editing-and-set-selected-blocks! elements))
(when (and edit-input-id block
(or
(publishing-enable-editing?)
(not @publishing?)))
(let [block-element (gdom/getElement (string/replace edit-input-id "edit-block" "ls-block"))
container (util/get-block-container block-element)
block (if container
(assoc block
:block.temp/container (gobj/get container "id"))
block)
content (string/trim (or content ""))]
(when ref (set-editing-ref! ref))
(set-state! :editor/block block)
(set-state! :editor/content content :path-in-sub-atom (:block/uuid block))
(set-state! :editor/last-key-code nil)
(set-state! :editor/set-timestamp-block nil)
(set-state! :editor/cursor-range cursor-range)
(let [edit-input-id (if ref
(or (some-> (gobj/get ref "id") (string/replace "ls-block" "edit-block"))
edit-input-id)
edit-input-id)]
(when (and edit-input-id block
(or
(publishing-enable-editing?)
(not @publishing?)))
(let [block-element (gdom/getElement (string/replace edit-input-id "edit-block" "ls-block"))
container (util/get-block-container block-element)
block (if container
(assoc block
:block.temp/container (gobj/get container "id"))
block)
content (string/trim (or content ""))]
(when ref (set-editing-ref! ref))
(set-state! :editor/block block)
(set-state! :editor/content content :path-in-sub-atom (:block/uuid block))
(set-state! :editor/last-key-code nil)
(set-state! :editor/set-timestamp-block nil)
(set-state! :editor/cursor-range cursor-range)
(when-let [input (gdom/getElement edit-input-id)]
(let [pos (count cursor-range)]
(when content
(util/set-change-value input content))
(when-let [input (gdom/getElement edit-input-id)]
(let [pos (count cursor-range)]
(when content
(util/set-change-value input content))
(when move-cursor?
(cursor/move-cursor-to input pos))
(when move-cursor?
(cursor/move-cursor-to input pos))
(when (or (util/mobile?) (mobile-util/native-platform?))
(set-state! :mobile/show-action-bar? false))))))))
(when (or (util/mobile?) (mobile-util/native-platform?))
(set-state! :mobile/show-action-bar? false)))))))))
(defn action-bar-open?
[]

View File

@@ -174,18 +174,21 @@
(defn sync-db-to-main-thread
[repo conn]
(d/listen! conn :sync-db
(fn [{:keys [tx-data tx-meta] :as tx-report}]
(let [result (pipeline/invoke-hooks repo conn tx-report (worker-state/get-context))
(fn [{:keys [tx-meta] :as tx-report}]
(let [{:keys [pipeline-replace?]} tx-meta
result (pipeline/invoke-hooks repo conn tx-report (worker-state/get-context))
tx-report' (or (:tx-report result) tx-report)
;; TODO: delay search indice so that UI can be refreshed earlier
search-indice (search/sync-search-indice repo (:tx-report result))
data (pr-str
(merge
{:repo repo
:search-indice search-indice
:tx-data tx-data
:tx-meta tx-meta}
(dissoc result :tx-report)))]
(worker-util/post-message :sync-db-changes data)))))
search-indice (search/sync-search-indice repo tx-report')]
(when-not pipeline-replace?
(let [data (pr-str
(merge
{:repo repo
:search-indice search-indice
:tx-data (:tx-data tx-report')
:tx-meta tx-meta}
(dissoc result :tx-report)))]
(worker-util/post-message :sync-db-changes data)))))))
(defn listen-to-db-changes!
[repo conn]