mirror of https://github.com/logseq/logseq
Extract auto-complete component
parent
9b9f07c0f0
commit
34a3f5de83
|
@ -1,7 +1,8 @@
|
|||
(ns frontend.commands
|
||||
(:require [frontend.util :as util]
|
||||
[frontend.state :as state]
|
||||
[clojure.string :as string]))
|
||||
[clojure.string :as string]
|
||||
[goog.dom :as gdom]))
|
||||
|
||||
(defn ->page-reference
|
||||
[page]
|
||||
|
@ -18,7 +19,7 @@
|
|||
["Date Picker" [[:date/pick]]]
|
||||
["Page Reference" [[:editor/input "[[]]"]
|
||||
[:editor/cursor-back 2]
|
||||
[:search :page]]]
|
||||
[:editor/search-page]]]
|
||||
["Link" nil]
|
||||
["Upload a file" nil]]
|
||||
;; Allow user to modify or extend, should specify how to extend.
|
||||
|
@ -40,3 +41,29 @@
|
|||
(if (string/blank? result)
|
||||
nil
|
||||
result))))
|
||||
|
||||
(defmulti handle-step first)
|
||||
|
||||
(defmethod handle-step :editor/input [[_ append-value]]
|
||||
(when-let [edit-content (state/get-edit-content)]
|
||||
(let [new-value (util/replace-last "/" edit-content (str append-value))]
|
||||
(state/set-edit-content! new-value))))
|
||||
|
||||
(defmethod handle-step :editor/cursor-back [[_ n]]
|
||||
(when-let [input-id (state/get-edit-input-id)]
|
||||
(when-let [current-input (gdom/getElement input-id)]
|
||||
(util/cursor-move-back current-input n))))
|
||||
|
||||
(defmethod handle-step :editor/search-page [[_]]
|
||||
(when-let [input-id (state/get-edit-input-id)]
|
||||
(when-let [current-input (gdom/getElement input-id)]
|
||||
;; (util/cursor-move-back current-input n)
|
||||
)))
|
||||
|
||||
(defmethod handle-step :default [[type & _args]]
|
||||
(prn "No handler for step: " type))
|
||||
|
||||
(defn handle-steps
|
||||
[vector]
|
||||
(doseq [step vector]
|
||||
(handle-step step)))
|
||||
|
|
|
@ -15,55 +15,40 @@
|
|||
[medley.core :as medley]))
|
||||
|
||||
(defonce *show-commands (atom false))
|
||||
(defonce *matched-commands (atom commands/commands-map))
|
||||
(def *matched-commands (atom nil))
|
||||
(defonce *slash-caret-pos (atom nil))
|
||||
(defonce *command-current-idx (atom 0))
|
||||
|
||||
(defn- append-command!
|
||||
[id command-output]
|
||||
(handler/append-command! command-output)
|
||||
(cond
|
||||
;; replace string
|
||||
(string? command-output)
|
||||
(handler/append-command! command-output)
|
||||
|
||||
;; steps
|
||||
(vector? command-output)
|
||||
(commands/handle-steps command-output)
|
||||
|
||||
:else
|
||||
nil)
|
||||
|
||||
(.focus (gdom/getElement id))
|
||||
(reset! *show-commands false))
|
||||
|
||||
(rum/defc commands < rum/reactive
|
||||
{:will-mount (fn [state]
|
||||
(reset! *command-current-idx 0)
|
||||
(reset! *matched-commands commands/commands-map)
|
||||
state)}
|
||||
[id]
|
||||
(let [{:keys [top left]} (rum/react *slash-caret-pos)
|
||||
command-current-idx (rum/react *command-current-idx)]
|
||||
[:div.absolute.rounded-md.shadow-lg
|
||||
matched (rum/react *matched-commands)]
|
||||
(ui/auto-complete
|
||||
(map first matched)
|
||||
(fn [chosen]
|
||||
(append-command! id (get (into {} matched) chosen)))
|
||||
{:style {:top (+ top 20)
|
||||
:left left
|
||||
:width 400}}
|
||||
[:div.py-1.rounded-md.bg-white.shadow-xs
|
||||
(for [[idx [name handler]] (medley/indexed (rum/react *matched-commands))]
|
||||
(rum/with-key
|
||||
(ui/menu-link
|
||||
{:style (merge
|
||||
{:padding "6px"}
|
||||
(when (= command-current-idx idx)
|
||||
{:background-color "rgb(213, 218, 223)"}))
|
||||
:class "initial-color"
|
||||
:tab-index 0
|
||||
:on-click (fn [e]
|
||||
(util/stop e)
|
||||
(cond
|
||||
;; replace string
|
||||
(string? handler)
|
||||
(handler/append-command! handler)
|
||||
|
||||
;; steps
|
||||
(vector? handler)
|
||||
nil
|
||||
|
||||
:else
|
||||
nil)
|
||||
(.focus (gdom/getElement id))
|
||||
(reset! *show-commands false))}
|
||||
name)
|
||||
name))]]))
|
||||
:width 400}})))
|
||||
|
||||
(defn get-state
|
||||
[state]
|
||||
|
@ -129,6 +114,7 @@
|
|||
last-command (commands/get-command-input edit-content)]
|
||||
(or
|
||||
(and (= \/ (last edit-content))
|
||||
(= " " (nth edit-content (- (count edit-content) 2)))
|
||||
commands/commands-map)
|
||||
(and last-command
|
||||
(commands/get-matched-commands last-command)))))
|
||||
|
@ -150,38 +136,22 @@
|
|||
{
|
||||
;; up
|
||||
38 (fn [state e]
|
||||
(if (seq (get-matched-commands input))
|
||||
(do
|
||||
(util/stop e)
|
||||
(when (>= @*command-current-idx 1)
|
||||
(swap! *command-current-idx dec)))
|
||||
(when-not (seq (get-matched-commands input))
|
||||
(on-up-down state e true)))
|
||||
;; down
|
||||
40 (fn [state e]
|
||||
(if-let [matched (seq (get-matched-commands input))]
|
||||
(do
|
||||
(util/stop e)
|
||||
(let [total (count matched)]
|
||||
(if (>= @*command-current-idx (dec total))
|
||||
(reset! *command-current-idx 0)
|
||||
(swap! *command-current-idx inc))))
|
||||
(when-not (seq (get-matched-commands input))
|
||||
(on-up-down state e false)))
|
||||
|
||||
;; backspace
|
||||
8 (fn [state e] (on-backspace state e))
|
||||
|
||||
;; enter
|
||||
13 (fn [state e]
|
||||
(let [matched-commands (get-matched-commands input)]
|
||||
(when (seq matched-commands)
|
||||
(util/stop e)
|
||||
(append-command! input-id (last (nth matched-commands @*command-current-idx))))))}
|
||||
8 (fn [state e] (on-backspace state e))}
|
||||
nil)
|
||||
(mixins/on-key-up
|
||||
state
|
||||
{191 (fn [state e]
|
||||
(reset! *show-commands true)
|
||||
(reset! *slash-caret-pos (util/get-caret-pos input)))}
|
||||
(when-let [matched-commands (seq (get-matched-commands input))]
|
||||
(reset! *show-commands true)
|
||||
(reset! *slash-caret-pos (util/get-caret-pos input))))}
|
||||
(fn [e key-code]
|
||||
(when (not= key-code 191)
|
||||
(let [matched-commands (get-matched-commands input)]
|
||||
|
|
|
@ -505,11 +505,9 @@
|
|||
(defn periodically-pull-and-push
|
||||
[repo-url {:keys [pull-now?]
|
||||
:or {pull-now? true}}]
|
||||
;; (when-not config/dev?
|
||||
;; (periodically-pull repo-url pull-now?)
|
||||
;; (periodically-push-tasks repo-url))
|
||||
(periodically-pull repo-url pull-now?)
|
||||
(periodically-push-tasks repo-url))
|
||||
(when-not config/dev?
|
||||
(periodically-pull repo-url pull-now?)
|
||||
(periodically-push-tasks repo-url)))
|
||||
|
||||
(defn edit-journal!
|
||||
[journal]
|
||||
|
@ -637,11 +635,6 @@
|
|||
pos (if dummy? (+ 3 pos) pos)]
|
||||
(util/set-caret-pos! node pos))))))
|
||||
|
||||
(defn move-cursor-to-end [input]
|
||||
(let [n (count (.-value input))]
|
||||
(set! (.-selectionStart input) n)
|
||||
(set! (.-selectionEnd input) n)))
|
||||
|
||||
(defn remove-slash!
|
||||
[]
|
||||
(when-let [edit-content (state/get-edit-content)]
|
||||
|
@ -656,7 +649,7 @@
|
|||
(state/set-edit-content! new-value)
|
||||
(when-let [input-id (state/get-edit-input-id)]
|
||||
(when-let [current-input (gdom/getElement input-id)]
|
||||
(move-cursor-to-end current-input))))))
|
||||
(util/move-cursor-to-end current-input))))))
|
||||
|
||||
(defn append-command!
|
||||
[append-value]
|
||||
|
@ -665,7 +658,7 @@
|
|||
(state/set-edit-content! new-value)
|
||||
(when-let [input-id (state/get-edit-input-id)]
|
||||
(when-let [current-input (gdom/getElement input-id)]
|
||||
(move-cursor-to-end current-input))))))
|
||||
(util/move-cursor-to-end current-input))))))
|
||||
|
||||
(defn insert-image!
|
||||
[image-url]
|
||||
|
@ -676,7 +669,7 @@
|
|||
;; ]
|
||||
;; (state/set-edit-content! new-content)
|
||||
;; (set! (.-value node) new-content)
|
||||
;; (move-cursor-to-end node))
|
||||
;; (util/move-cursor-to-end node))
|
||||
)
|
||||
|
||||
(defn search
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
[frontend.state :as state]
|
||||
[clojure.string :as string]
|
||||
[goog.object :as gobj]
|
||||
[goog.dom :as gdom]))
|
||||
[goog.dom :as gdom]
|
||||
[medley.core :as medley]))
|
||||
|
||||
(defonce transition-group (r/adapt-class TransitionGroup))
|
||||
(defonce css-transition (r/adapt-class CSSTransition))
|
||||
|
@ -72,10 +73,10 @@
|
|||
(let [class "inline-flex.items-center.px-3.py-2.border.border-transparent.text-sm.leading-4.font-medium.rounded-md.text-white.bg-indigo-600.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.active:bg-indigo-700.transition.ease-in-out.duration-150.mt-1"
|
||||
class (if background (string/replace class "indigo" background) class)]
|
||||
[:button
|
||||
{:type "button"
|
||||
:class (util/hiccup->class class)
|
||||
:on-click on-click}
|
||||
text]))
|
||||
{:type "button"
|
||||
:class (util/hiccup->class class)
|
||||
:on-click on-click}
|
||||
text]))
|
||||
|
||||
(rum/defc notification-content
|
||||
[state content status]
|
||||
|
@ -179,3 +180,57 @@
|
|||
[state body {:keys [on-load]
|
||||
:as opts}]
|
||||
body)
|
||||
|
||||
(rum/defcs auto-complete <
|
||||
(rum/local nil ::matched)
|
||||
(rum/local 0 ::current-idx)
|
||||
(mixins/event-mixin
|
||||
(fn [state]
|
||||
(mixins/on-key-down
|
||||
state
|
||||
{
|
||||
;; up
|
||||
38 (fn [_ e]
|
||||
(let [current-idx (get state ::current-idx)]
|
||||
(util/stop e)
|
||||
(when (>= @current-idx 1)
|
||||
(swap! current-idx dec))))
|
||||
;; down
|
||||
40 (fn [state e]
|
||||
(let [current-idx (get state ::current-idx)
|
||||
matched (first (:rum/args state))]
|
||||
(util/stop e)
|
||||
(let [total (count matched)]
|
||||
(if (>= @current-idx (dec total))
|
||||
(reset! current-idx 0)
|
||||
(swap! current-idx inc)))))
|
||||
|
||||
;; enter
|
||||
13 (fn [state e]
|
||||
(let [current-idx (get state ::current-idx)
|
||||
matched (first (:rum/args state))
|
||||
on-chosen (nth (:rum/args state) 1)]
|
||||
(util/stop e)
|
||||
(on-chosen (nth matched @current-idx))))}
|
||||
nil)))
|
||||
[state matched on-chosen div-option]
|
||||
(when (seq matched)
|
||||
(let [current-idx (get state ::current-idx)]
|
||||
[:div.absolute.rounded-md.shadow-lg
|
||||
div-option
|
||||
[:div.py-1.rounded-md.bg-white.shadow-xs
|
||||
(for [[idx item] (medley/indexed matched)]
|
||||
(rum/with-key
|
||||
(menu-link
|
||||
{:style (merge
|
||||
{:padding "6px"}
|
||||
(when (= @current-idx idx)
|
||||
{:background-color "rgb(213, 218, 223)"}))
|
||||
:class "initial-color"
|
||||
:tab-index 0
|
||||
:on-click (fn [e]
|
||||
(util/stop e)
|
||||
(let [option (nth matched @current-idx)]
|
||||
(on-chosen option)))}
|
||||
item)
|
||||
idx))]])))
|
||||
|
|
|
@ -417,3 +417,13 @@
|
|||
(when-let [last-index (string/last-index-of s pattern)]
|
||||
(str (subs s 0 last-index)
|
||||
new-value)))
|
||||
|
||||
(defn move-cursor-to-end [input]
|
||||
(let [n (count (.-value input))]
|
||||
(set! (.-selectionStart input) n)
|
||||
(set! (.-selectionEnd input) n)))
|
||||
|
||||
(defn cursor-move-back [input n]
|
||||
(let [total (count (.-value input))]
|
||||
(set! (.-selectionStart input) (- total 2))
|
||||
(set! (.-selectionEnd input) (- total 2))))
|
||||
|
|
Loading…
Reference in New Issue