From 05ca8fd883a86cfdeb54077996d20476d1e5fba6 Mon Sep 17 00:00:00 2001 From: charlie Date: Thu, 22 May 2025 15:06:47 +0800 Subject: [PATCH] enhance(capacitor): improve block editor --- src/main/capacitor/app.cljs | 2 +- src/main/capacitor/components/blocks.cljs | 74 +++++++++++++---------- src/main/capacitor/components/editor.cljs | 32 ++++++---- src/main/capacitor/state.cljs | 16 ++++- 4 files changed, 75 insertions(+), 49 deletions(-) diff --git a/src/main/capacitor/app.cljs b/src/main/capacitor/app.cljs index c60b355e1f..b43cbcebc3 100644 --- a/src/main/capacitor/app.cljs +++ b/src/main/capacitor/app.cljs @@ -212,7 +212,7 @@ (fn [] (cond (not (nil? (state/get-editing-block))) - (state/set-editing-block! nil) + (state/exit-editing!) :else (cc-utils/nav-pop!))) diff --git a/src/main/capacitor/components/blocks.cljs b/src/main/capacitor/components/blocks.cljs index 65a7aea56b..473bc1e588 100644 --- a/src/main/capacitor/components/blocks.cljs +++ b/src/main/capacitor/components/blocks.cljs @@ -2,6 +2,7 @@ (:require [capacitor.state :as state] [clojure.string :as string] [frontend.db.model :as db-model] + [frontend.util.cursor :as cursor] [promesa.core :as p] [rum.core :as rum] [frontend.db.async :as db-async] @@ -96,43 +97,49 @@ (rum/defc block-editor [block] (let [content (:block/title block) - exit! #(state/set-state! :editing-block nil)] + block-uuid (:block/uuid block) + current-repo (fstate/get-current-repo)] + (cc-editor/editor-aux content - {:on-outside! + {:on-focused! + (fn [^js input] + (let [cursor-at (some-> (state/get-editing-opts) :cursor-at)] + (if (number? cursor-at) + (cursor/move-cursor-to input cursor-at) + (cursor/move-cursor-to-end input)))) + + :on-outside! (fn [^js e] (let [edit-target? (some-> e (.-target) (cc-common/get-dom-block-uuid))] (when edit-target? (cc-common/keep-keyboard-open e)) (when (and (not edit-target?) (= block (:editing-block @state/*state))) - (exit!)))) + (state/exit-editing!)))) :on-save! - (fn [content {:keys [enter?]}] - (let [block-uuid (:block/uuid block) - current-repo (fstate/get-current-repo)] - - ;; update block content - (-> (do (when enter? (exit!)) - ;; check block exist? - (when-not (db-utils/entity (:db/id block)) - (throw nil)) - (editor-handler/save-block! current-repo block-uuid content)) - (p/then (fn [] - (state/set-state! [:modified-blocks block-uuid] (js/Date.now)) - (when enter? - ;; create new block - (cc-common/keep-keyboard-open nil) - (-> (insert-new-block! "" {:block-uuid block-uuid}) - (p/then (fn [new-block] - (prn :debug "new block:" new-block) - (when-let [parent-block (:block/parent new-block)] - (state/set-state! [:modified-pages (:block/uuid parent-block)] (js/Date.now))) - ;; edit the new block - (js/requestAnimationFrame #(state/set-editing-block! new-block)) - ))) - ))) - (p/catch #(notification/show! (str %) :error))))) + (fn [content {:keys [enter? esc?]}] + ;; update block content + (-> (do (when (or enter? esc?) (state/exit-editing!)) + ;; check block exist? + (when-not (db-utils/entity (:db/id block)) + (throw nil)) + (editor-handler/save-block! current-repo block-uuid content)) + (p/then (fn [] + (state/set-state! [:modified-blocks block-uuid] (js/Date.now)) + (when enter? + ;; create new block + (cc-common/keep-keyboard-open nil) + (-> (insert-new-block! "" {:block-uuid block-uuid}) + (p/then (fn [new-block] + (prn :debug "new block:" new-block) + (when-let [parent-block (:block/parent new-block)] + (state/set-state! [:modified-pages (:block/uuid parent-block)] (js/Date.now))) + ;; edit the new block + (js/requestAnimationFrame #(state/edit-block! new-block)) + ))) + ))) + (p/catch #(notification/show! (str %) :error)))) :on-delete! (fn [content] @@ -140,18 +147,21 @@ parent-block (:block/parent block)] (cond (and (nil? prev-block) (nil? parent-block)) nil + :else (let [has-children? (seq (:block/_parent block))] (when-not has-children? (p/do! (editor-handler/delete-block-aux! block) (state/set-state! [:modified-blocks (:block/uuid block)] (js/Date.now)) + (when (and (false? (some-> content (string/trim) (string/blank?))) prev-block) + (editor-handler/save-block! current-repo prev-block + (str (:block/title prev-block) content))) (when prev-block (cc-common/keep-keyboard-open nil) - (js/requestAnimationFrame #(state/set-editing-block! prev-block))) - (when (false? (some-> content (string/trim) (string/blank?))) - (notification/show! "concat prev block content!!") - ))))) + (state/set-state! [:modified-blocks (:block/uuid prev-block)] (js/Date.now)) + (js/requestAnimationFrame #(state/edit-block! prev-block + {:cursor-at (count (:block/title prev-block))}))))))) (prn :debug "delete node:" (:db/id block) (:block/title prev-block)) )) }))) diff --git a/src/main/capacitor/components/editor.cljs b/src/main/capacitor/components/editor.cljs index 183b936f60..dc48aeb536 100644 --- a/src/main/capacitor/components/editor.cljs +++ b/src/main/capacitor/components/editor.cljs @@ -7,7 +7,7 @@ [frontend.handler.notification :as notification])) (rum/defc editor-aux - [content {:keys [on-outside! on-save! on-delete!]}] + [content {:keys [on-outside! on-save! on-delete! on-focused! on-keydown! on-keyup!]}] (let [*input (rum/use-ref nil)] @@ -17,8 +17,8 @@ (fn [] (when-let [^js input (some-> (rum/deref *input))] (.focus input) - (let [len (.-length (.-value input))] - (.setSelectionRange input len len)) + (when on-focused! + (on-focused! input)) ;(.scrollIntoView input #js {:behavior "smooth", :block "start"}) ))) #()) @@ -35,7 +35,7 @@ (let [save-handle! (fn [opts] - (let [content (.-value (rum/deref *input))] + (when-let [content (some-> (rum/deref *input) (.-value))] (when on-save! (prn :debug "save block content:" content opts) (on-save! content opts)))) @@ -52,19 +52,25 @@ (let [ekey (.-key e) target (.-target e) enter? (= ekey "Enter") + esc? (= ekey "Escape") backspace? (= ekey "Backspace")] - (cond - (and enter? (cursor/end? target)) - (do (save-handle! {:enter? true}) - (util/stop e)) + (when (or (nil? on-keydown!) + (not (false? (on-keydown! e)))) + (cond + (or (and enter? (cursor/end? target)) esc?) + (do (save-handle! {:enter? enter? :esc? esc?}) + (util/stop e)) - (and backspace? (cursor/start? target)) - (do (delete-handle! {}) - (util/stop e)) + (and backspace? (cursor/start? target)) + (do (delete-handle! {}) + (util/stop e)) - :else (debounce-save-handle!) - ))) + :else (debounce-save-handle!) + )))) + :on-key-up (fn [^js e] + (when on-keyup! + (on-keyup! e))) :default-value content})))) (rum/defc content-aux diff --git a/src/main/capacitor/state.cljs b/src/main/capacitor/state.cljs index 077719bfd0..4c4fdaf2f4 100644 --- a/src/main/capacitor/state.cljs +++ b/src/main/capacitor/state.cljs @@ -6,8 +6,9 @@ (defonce *state (atom {:version 0 :editing-block nil + :editing-opts nil :modified-pages {} - :modified-blocks {} ;; {:uuid timestamp} + :modified-blocks {} ;; {:uuid timestamp} })) (defn use-nav-root [] (r/use-atom *nav-root)) @@ -50,5 +51,14 @@ (defn get-editing-block [] (:editing-block @*state)) -(defn set-editing-block! [block] - (set-state! :editing-block block)) \ No newline at end of file +(defn edit-block! + ([block] (edit-block! block nil)) + ([block opts] + (set-state! :editing-block block) + (set-state! :editing-opts opts))) + +(defn exit-editing! [] + (edit-block! nil nil)) + +(defn get-editing-opts [] + (:editing-opts @*state))