diff --git a/web/src/main/frontend/commands.cljs b/web/src/main/frontend/commands.cljs index 4bf0efdd8..bf01a6911 100644 --- a/web/src/main/frontend/commands.cljs +++ b/web/src/main/frontend/commands.cljs @@ -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))) diff --git a/web/src/main/frontend/components/editor.cljs b/web/src/main/frontend/components/editor.cljs index 0f00bed85..bab75ed96 100644 --- a/web/src/main/frontend/components/editor.cljs +++ b/web/src/main/frontend/components/editor.cljs @@ -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)] diff --git a/web/src/main/frontend/handler.cljs b/web/src/main/frontend/handler.cljs index a63009cb9..109c6820b 100644 --- a/web/src/main/frontend/handler.cljs +++ b/web/src/main/frontend/handler.cljs @@ -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 diff --git a/web/src/main/frontend/ui.cljs b/web/src/main/frontend/ui.cljs index 3d9cd9098..9702c5012 100644 --- a/web/src/main/frontend/ui.cljs +++ b/web/src/main/frontend/ui.cljs @@ -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))]]))) diff --git a/web/src/main/frontend/util.cljs b/web/src/main/frontend/util.cljs index 80f89d562..2c01b2d73 100644 --- a/web/src/main/frontend/util.cljs +++ b/web/src/main/frontend/util.cljs @@ -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))))