diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index e81850b1e..9ac3c3c5d 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -224,35 +224,41 @@ (defn edit-block! ([block pos id] (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 - 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) + 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)) + (and (> tail-len 0) (>= (count content) tail-len)) + (subs content 0 (- (count content) tail-len)) - (or (= :max pos) (<= content-length pos)) - content + (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?)))))) + :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? [current-id block-id] @@ -787,7 +793,11 @@ (edit-block! block pos id {:custom-content new-value :tail-len tail-len - :move-cursor? false})))))) + :move-cursor? false}) + {:prev-block block + :new-content new-value}))))) + +(declare save-block!) (defn delete-block! ([repo] @@ -810,9 +820,18 @@ (when-not (and has-children? left-has-children?) (when 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))) (defn delete-blocks! @@ -2584,9 +2603,17 @@ nil :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))))) (defn keydown-delete-handler diff --git a/src/main/frontend/modules/editor/undo_redo.cljs b/src/main/frontend/modules/editor/undo_redo.cljs index 2ca5b2d58..0e426c815 100644 --- a/src/main/frontend/modules/editor/undo_redo.cljs +++ b/src/main/frontend/modules/editor/undo_redo.cljs @@ -1,5 +1,6 @@ (ns frontend.modules.editor.undo-redo (:require [datascript.core :as d] + [frontend.db :as db] [frontend.db.conn :as conn] [frontend.modules.datascript-report.core :as db-report] [frontend.state :as state] @@ -103,14 +104,33 @@ (when e (let [{:keys [txs tx-meta]} e 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) + + :else (:editor-cursor e))] + (push-redo e) (transact! new-txs (merge {:undo? true} tx-meta (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) (state/pub-event! [:whiteboard/undo e])) (assoc e diff --git a/src/main/frontend/modules/outliner/datascript.cljc b/src/main/frontend/modules/outliner/datascript.cljc index 17164aea2..e058ffd15 100644 --- a/src/main/frontend/modules/outliner/datascript.cljc +++ b/src/main/frontend/modules/outliner/datascript.cljc @@ -58,7 +58,10 @@ (not (:skip-transact? opts)) (not (contains? (:file/unlinked-dirs @state/state) (config/get-repo-dir (state/get-current-repo))))) + + ;; (prn "[DEBUG] Outliner transact:") ;; (frontend.util/pprint txs) + (try (let [repo (get opts :repo (state/get-current-repo)) conn (conn/get-db repo false) diff --git a/src/main/frontend/modules/outliner/transaction.cljc b/src/main/frontend/modules/outliner/transaction.cljc index d4c5600b7..738486659 100644 --- a/src/main/frontend/modules/outliner/transaction.cljc +++ b/src/main/frontend/modules/outliner/transaction.cljc @@ -1,5 +1,10 @@ (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! "Batch all the transactions in `body` to a single transaction, Support nested transact! calls. @@ -18,7 +23,7 @@ (move-blocks! ...) (delete-blocks! ...))" [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* opts# (if transact-data# (assoc ~opts :nested-transaction? true) diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index 54b776faa..47050f05c 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -1119,7 +1119,8 @@ Similar to re-frame subscriptions" (when container {:last-edit-block edit-block :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! []