소스 검색

fix: undo block deletion needs multiple steps (#8833)

fix: undo block deletion needs multiple steps

---------

Co-authored-by: charlie <[email protected]>
Tienson Qin 3 년 전
부모
커밋
0eab5ebef4

+ 62 - 35
src/main/frontend/handler/editor.cljs

@@ -224,35 +224,41 @@
 (defn edit-block!
 (defn edit-block!
   ([block pos id]
   ([block pos id]
    (edit-block! block pos id nil))
    (edit-block! block pos id nil))
-  ([block pos id {:keys [custom-content tail-len move-cursor?]
+  ([block pos id {:keys [custom-content tail-len move-cursor? retry-times]
                   :or {tail-len 0
                   :or {tail-len 0
-                       move-cursor? true}}]
-   (when-not config/publishing?
-     (when-let [block-id (:block/uuid block)]
-       (let [block (or (db/pull [:block/uuid block-id]) block)
-             edit-input-id (if (uuid? id)
-                             (get-edit-input-id-with-block-id id)
-                             (-> (str (subs id 0 (- (count id) 36)) block-id)
-                                 (string/replace "ls-block" "edit-block")))
-             content (or custom-content (:block/content block) "")
-             content-length (count content)
-             text-range (cond
-                          (vector? pos)
-                          (text-range-by-lst-fst-line content pos)
-
-                          (and (> tail-len 0) (>= (count content) tail-len))
-                          (subs content 0 (- (count content) tail-len))
-
-                          (or (= :max pos) (<= content-length pos))
-                          content
-
-                          :else
-                          (subs content 0 pos))
-             content (-> (property/remove-built-in-properties (:block/format block)
-                                                              content)
-                         (drawer/remove-logbook))]
-         (clear-selection!)
-         (state/set-editing! edit-input-id content block text-range move-cursor?))))))
+                       move-cursor? true
+                       retry-times 0}
+                  :as opts}]
+   (when-not (> retry-times 2)
+     (when-not config/publishing?
+       (when-let [block-id (:block/uuid block)]
+         (let [block (or (db/pull [:block/uuid block-id]) block)
+               edit-input-id (if (uuid? id)
+                               (get-edit-input-id-with-block-id id)
+                               (-> (str (subs id 0 (- (count id) 36)) block-id)
+                                   (string/replace "ls-block" "edit-block")))
+               content (or custom-content (:block/content block) "")
+               content-length (count content)
+               text-range (cond
+                            (vector? pos)
+                            (text-range-by-lst-fst-line content pos)
+
+                            (and (> tail-len 0) (>= (count content) tail-len))
+                            (subs content 0 (- (count content) tail-len))
+
+                            (or (= :max pos) (<= content-length pos))
+                            content
+
+                            :else
+                            (subs content 0 pos))
+               content (-> (property/remove-built-in-properties (:block/format block)
+                                                                content)
+                           (drawer/remove-logbook))]
+           (clear-selection!)
+           (if edit-input-id
+             (state/set-editing! edit-input-id content block text-range move-cursor?)
+             ;; Block may not be rendered yet
+             (js/setTimeout (fn [] (edit-block! block pos id (update opts :retry-times inc))) 10))))))))
 
 
 (defn- another-block-with-same-id-exists?
 (defn- another-block-with-same-id-exists?
   [current-id block-id]
   [current-id block-id]
@@ -787,7 +793,11 @@
           (edit-block! block pos id
           (edit-block! block pos id
                        {:custom-content new-value
                        {:custom-content new-value
                         :tail-len tail-len
                         :tail-len tail-len
-                        :move-cursor? false}))))))
+                        :move-cursor? false})
+          {:prev-block block
+           :new-content new-value})))))
+
+(declare save-block!)
 
 
 (defn delete-block!
 (defn delete-block!
   ([repo]
   ([repo]
@@ -810,9 +820,18 @@
              (when-not (and has-children? left-has-children?)
              (when-not (and has-children? left-has-children?)
                (when block-parent-id
                (when block-parent-id
                  (let [block-parent (gdom/getElement block-parent-id)
                  (let [block-parent (gdom/getElement block-parent-id)
-                       sibling-block (util/get-prev-block-non-collapsed-non-embed block-parent)]
-                   (delete-block-aux! block delete-children?)
-                   (move-to-prev-block repo sibling-block format id value)))))))))
+                       sibling-block (util/get-prev-block-non-collapsed-non-embed block-parent)
+                       {:keys [prev-block new-content]} (move-to-prev-block repo sibling-block format id value)
+                       concat-prev-block? (boolean (and prev-block new-content))
+                       transact-opts (cond->
+                                       {:outliner-op :delete-block}
+                                       concat-prev-block?
+                                       (assoc :concat-data
+                                              {:last-edit-block (:block/uuid block)}))]
+                   (outliner-tx/transact! transact-opts
+                     (when concat-prev-block?
+                       (save-block! repo prev-block new-content))
+                     (delete-block-aux! block delete-children?))))))))))
    (state/set-editor-op! nil)))
    (state/set-editor-op! nil)))
 
 
 (defn delete-blocks!
 (defn delete-blocks!
@@ -2584,9 +2603,17 @@
       nil
       nil
 
 
       :else
       :else
-      (do
-        (delete-block-aux! next-block false)
-        (state/set-edit-content! input-id (str value "" (:block/content next-block)))
+      (let [edit-block (state/get-edit-block)
+            transact-opts {:outliner-op :delete-block
+                           :concat-data {:last-edit-block (:block/uuid edit-block)
+                                         :end? true}}
+            new-content (str value "" (:block/content next-block))
+            repo (state/get-current-repo)]
+        (outliner-tx/transact! transact-opts
+          (save-block! repo edit-block new-content)
+          (delete-block-aux! next-block false))
+
+        (state/set-edit-content! input-id new-content)
         (cursor/move-cursor-to input current-pos)))))
         (cursor/move-cursor-to input current-pos)))))
 
 
 (defn keydown-delete-handler
 (defn keydown-delete-handler

+ 22 - 2
src/main/frontend/modules/editor/undo_redo.cljs

@@ -1,5 +1,6 @@
 (ns frontend.modules.editor.undo-redo
 (ns frontend.modules.editor.undo-redo
   (:require [datascript.core :as d]
   (:require [datascript.core :as d]
+            [frontend.db :as db]
             [frontend.db.conn :as conn]
             [frontend.db.conn :as conn]
             [frontend.modules.datascript-report.core :as db-report]
             [frontend.modules.datascript-report.core :as db-report]
             [frontend.state :as state]
             [frontend.state :as state]
@@ -103,14 +104,33 @@
     (when e
     (when e
       (let [{:keys [txs tx-meta]} e
       (let [{:keys [txs tx-meta]} e
             new-txs (get-txs false txs)
             new-txs (get-txs false txs)
-            editor-cursor (if (= (get-in e [:editor-cursor :last-edit-block :block/uuid])
-                                 (get-in prev-e [:editor-cursor :last-edit-block :block/uuid])) ; same block
+            undo-delete-concat-block? (and (= :delete-block (:outliner-op tx-meta))
+                                           (seq (:concat-data tx-meta)))
+            editor-cursor (cond
+                            undo-delete-concat-block?
+                            (let [data (:concat-data tx-meta)]
+                              (assoc (:editor-cursor e)
+                                     :last-edit-block {:block/uuid (:last-edit-block data)}
+                                     :pos (if (:end? data) :max 0)))
+
+                            ;; same block
+                            (= (get-in e [:editor-cursor :last-edit-block :block/uuid])
+                               (get-in prev-e [:editor-cursor :last-edit-block :block/uuid]))
                             (:editor-cursor prev-e)
                             (:editor-cursor prev-e)
+
+                            :else
                             (:editor-cursor e))]
                             (:editor-cursor e))]
+
         (push-redo e)
         (push-redo e)
         (transact! new-txs (merge {:undo? true}
         (transact! new-txs (merge {:undo? true}
                                   tx-meta
                                   tx-meta
                                   (select-keys e [:pagination-blocks-range])))
                                   (select-keys e [:pagination-blocks-range])))
+
+        (when undo-delete-concat-block?
+          (when-let [block (state/get-edit-block)]
+            (state/set-edit-content! (state/get-edit-input-id)
+                                     (:block/content (db/entity (:db/id block))))))
+
         (when (:whiteboard/transact? tx-meta)
         (when (:whiteboard/transact? tx-meta)
           (state/pub-event! [:whiteboard/undo e]))
           (state/pub-event! [:whiteboard/undo e]))
         (assoc e
         (assoc e

+ 3 - 0
src/main/frontend/modules/outliner/datascript.cljc

@@ -58,7 +58,10 @@
                   (not (:skip-transact? opts))
                   (not (:skip-transact? opts))
                   (not (contains? (:file/unlinked-dirs @state/state)
                   (not (contains? (:file/unlinked-dirs @state/state)
                                   (config/get-repo-dir (state/get-current-repo)))))
                                   (config/get-repo-dir (state/get-current-repo)))))
+
+         ;; (prn "[DEBUG] Outliner transact:")
          ;; (frontend.util/pprint txs)
          ;; (frontend.util/pprint txs)
+
          (try
          (try
            (let [repo (get opts :repo (state/get-current-repo))
            (let [repo (get opts :repo (state/get-current-repo))
                  conn (conn/get-db repo false)
                  conn (conn/get-db repo false)

+ 7 - 2
src/main/frontend/modules/outliner/transaction.cljc

@@ -1,5 +1,10 @@
 (ns frontend.modules.outliner.transaction
 (ns frontend.modules.outliner.transaction
-  #?(:cljs (:require-macros [frontend.modules.outliner.transaction])))
+  #?(:cljs (:require-macros [frontend.modules.outliner.transaction]))
+  #?(:cljs (:require [malli.core :as m])))
+
+(def transact-opts [:or :symbol :map])
+
+#?(:cljs (m/=> transact! [:=> [:cat transact-opts :any] :any]))
 
 
 (defmacro transact!
 (defmacro transact!
   "Batch all the transactions in `body` to a single transaction, Support nested transact! calls.
   "Batch all the transactions in `body` to a single transaction, Support nested transact! calls.
@@ -18,7 +23,7 @@
     (move-blocks! ...)
     (move-blocks! ...)
     (delete-blocks! ...))"
     (delete-blocks! ...))"
   [opts & body]
   [opts & body]
-  (assert (map? opts))
+  (assert (or (map? opts) (symbol? opts)) (str "opts is not a map or symbol, type: " (type opts) ))
   `(let [transact-data# frontend.modules.outliner.core/*transaction-data*
   `(let [transact-data# frontend.modules.outliner.core/*transaction-data*
          opts# (if transact-data#
          opts# (if transact-data#
                  (assoc ~opts :nested-transaction? true)
                  (assoc ~opts :nested-transaction? true)

+ 2 - 1
src/main/frontend/state.cljs

@@ -1119,7 +1119,8 @@ Similar to re-frame subscriptions"
     (when container
     (when container
       {:last-edit-block edit-block
       {:last-edit-block edit-block
        :container       (gobj/get container "id")
        :container       (gobj/get container "id")
-       :pos             (cursor/pos (gdom/getElement edit-input-id))})))
+       :pos             (or (cursor/pos (gdom/getElement edit-input-id))
+                            (count (:block/content edit-block)))})))
 
 
 (defn clear-edit!
 (defn clear-edit!
   []
   []