mirror of
https://github.com/logseq/logseq.git
synced 2026-05-28 14:39:48 +00:00
fix: history undo/redo
This commit is contained in:
@@ -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))
|
||||
|
||||
@@ -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))))
|
||||
|
||||
@@ -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)))))
|
||||
|
||||
@@ -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))))
|
||||
|
||||
@@ -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?
|
||||
[]
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user