diff --git a/src/main/frontend/components/find_in_page.cljs b/src/main/frontend/components/find_in_page.cljs index 114a9435c5..703830d770 100644 --- a/src/main/frontend/components/find_in_page.cljs +++ b/src/main/frontend/components/find_in_page.cljs @@ -3,30 +3,43 @@ [frontend.ui :as ui] [frontend.state :as state] [frontend.util :as util] - [frontend.handler.search :as search-handler :refer [debounced-search]] + [frontend.handler.search :as search-handler :refer [debounced-search, stop-debounced-search!]] + [goog.object :as gobj] [goog.dom :as gdom] [frontend.mixins :as mixins] [clojure.string :as string])) (rum/defc search-input [q matches] - [:div.flex.w-48.relative - [:input#search-in-page-input.form-input.block.sm:text-sm.sm:leading-5.my-2.border-none.mr-4.outline-none - {:auto-focus true - :placeholder "Find in page" - :aria-label "Find in page" - :value q - :on-change (fn [e] - (let [value (util/evalue e)] - (state/set-state! [:ui/find-in-page :q] value) - (debounced-search)))}] - (when-not (string/blank? q) - (when-let [total (:matches matches)] - [:div.text-sm.absolute.top-2.right-0.py-2.px-4 - (:activeMatchOrdinal matches 0) - "/" - total])) - [:div#search-in-page-placeholder.absolute.top-2.left-0.p-2.sm:text-sm]]) + (let [*composing? (rum/use-ref false) + on-change-fn (fn [e] + (let [value (util/evalue e) + e-type (gobj/getValueByKeys e "type")] + (state/set-state! [:ui/find-in-page :q] value) + (cond (= e-type "compositionstart") + (do (rum/set-ref! *composing? true) + (stop-debounced-search!)) + + (= e-type "compositionend") + (rum/set-ref! *composing? false)) + (when-not (rum/deref *composing?) + (debounced-search))))] + [:div.flex.w-48.relative + [:input#search-in-page-input.form-input.block.sm:text-sm.sm:leading-5.my-2.border-none.mr-4.outline-none + {:auto-focus true + :placeholder "Find in page" + :aria-label "Find in page" + :value q + :on-composition-start on-change-fn + :on-composition-end on-change-fn + :on-change on-change-fn}] + (when-not (string/blank? q) + (when-let [total (:matches matches)] + [:div.text-sm.absolute.top-2.right-0.py-2.px-4 + (:activeMatchOrdinal matches 0) + "/" + total])) + [:div#search-in-page-placeholder.absolute.top-2.left-0.p-2.sm:text-sm]])) (rum/defc search-inner < rum/static (mixins/event-mixin diff --git a/src/main/frontend/handler/search.cljs b/src/main/frontend/handler/search.cljs index 4a75c1a177..a288c2041b 100644 --- a/src/main/frontend/handler/search.cljs +++ b/src/main/frontend/handler/search.cljs @@ -10,7 +10,6 @@ [promesa.core :as p] [logseq.graph-parser.text :as text] [electron.ipc :as ipc] - [goog.functions :refer [debounce]] [dommy.core :as dom])) (defn add-search-to-recent! @@ -87,7 +86,9 @@ (str " " (subs q 1))))) (ipc/ipc "find-in-page" q option))))) -(defonce debounced-search (debounce electron-find-in-page! 500)) +(let [cancelable-debounce-search (util/cancelable-debounce electron-find-in-page! 500)] + (defonce debounced-search (first cancelable-debounce-search)) + (defonce stop-debounced-search! (second cancelable-debounce-search))) (defn loop-find-in-page! [backward?] diff --git a/src/main/frontend/util.cljc b/src/main/frontend/util.cljc index a533fe4708..a968ddb892 100644 --- a/src/main/frontend/util.cljc +++ b/src/main/frontend/util.cljc @@ -30,6 +30,7 @@ [cljs.core.async.impl.channels :refer [ManyToManyChannel]] [medley.core :as medley] [frontend.pubsub :as pubsub])) + #?(:cljs (:import [goog.async Debouncer])) (:require [clojure.pprint] [clojure.string :as string] @@ -296,6 +297,20 @@ (reset! t nil) (apply f args)) threshold))))))) +#?(:cljs + (defn cancelable-debounce + "Create a stateful debounce function with specified interval + + Returns [fire-fn, cancel-fn] + + Use `fire-fn` to call the function(debounced) + + Use `cancel-fn` to cancel pending callback if there is" + [f interval] + (let [debouncer (Debouncer. f interval)] + (js/console.log debouncer) + [(fn [& args] (.apply (.-fire debouncer) debouncer (to-array args))) + (fn [] (.stop debouncer))]))) (defn nth-safe [c i] (if (or (< i 0) (>= i (count c)))