From fb4a169e02f0f85873f87fd609d553dc6866bb02 Mon Sep 17 00:00:00 2001 From: Eva Marco Date: Wed, 25 Feb 2026 10:59:12 +0100 Subject: [PATCH] :bug: Fix some errors on navigation --- .../management/forms/controls/combobox.cljs | 24 +++++---- .../forms/controls/combobox_navigation.cljs | 29 ++++++----- .../forms/controls/token_parsing.cljs | 52 ++++++++++++------- .../management/forms/controls/utils.cljs | 29 +++++++---- frontend/src/app/util/dom.cljs | 5 ++ 5 files changed, 85 insertions(+), 54 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/combobox.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/combobox.cljs index 2f93b7ab89..b8f670f601 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/combobox.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/combobox.cljs @@ -137,9 +137,10 @@ (mf/deps value resolve-stream name) (fn [id] (let [input-node (mf/ref-val ref) - final-val (tp/select-option-by-id id options-ref input-node value)] - (fm/on-input-change form name final-val true) - (rx/push! resolve-stream final-val) + final-val (tp/select-option-by-id id options-ref input-node value)] + (when final-val + (fm/on-input-change form name final-val true) + (rx/push! resolve-stream final-val)) (reset! filter-term* "") (reset! is-open* false)))) @@ -180,16 +181,17 @@ id (dom/get-data node "id") final-val (tp/select-option-by-id id options-ref input-node value)] - (fm/on-input-change form name final-val true) - (rx/push! resolve-stream final-val) - (reset! filter-term* "") - (reset! is-open* false) - (dom/focus! input-node) - (let [new-cursor (+ (str/index-of final-val "}") 1)] - (set! (.-selectionStart input-node) new-cursor) - (set! (.-selectionEnd input-node) new-cursor))))) + + (when final-val + (reset! is-open* false) + (fm/on-input-change form name final-val true) + (rx/push! resolve-stream final-val) + + (let [new-cursor (+ (str/index-of final-val "}") 1)] + (set! (.-selectionStart input-node) new-cursor) + (set! (.-selectionEnd input-node) new-cursor)))))) hint* (mf/use-state {}) diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/combobox_navigation.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/combobox_navigation.cljs index de0f6f279f..976d0115e8 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/combobox_navigation.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/combobox_navigation.cljs @@ -6,6 +6,7 @@ (ns app.main.ui.workspace.tokens.management.forms.controls.combobox-navigation (:require + [app.main.ui.workspace.tokens.management.forms.controls.utils :refer [focusable-options]] [app.util.dom :as dom] [app.util.keyboard :as kbd] [app.util.object :as obj] @@ -51,16 +52,23 @@ options (if (delay? options) @options options)] (cond - down? (do (dom/prevent-default event) - (if is-open - (let [next-id (next-focus-id options focused-id :down)] - (reset! focused-id* next-id)) - (do - (toggle-dropdown event) - (reset! focused-id* (first-focusable-id options))))) + (let [focusables (focusable-options options)] + (cond + is-open + (when (seq focusables) + (let [next-id (next-focus-id options focused-id :down)] + (reset! focused-id* next-id))) + + (seq focusables) + (do + (toggle-dropdown event) + (reset! focused-id* (first-focusable-id focusables))) + + :else + nil))) up? (when is-open @@ -77,11 +85,8 @@ enter? (do (dom/prevent-default event) - (if is-open - (on-enter focused-id) - (do - (reset! focused-id* (first-focusable-id options)) - (toggle-dropdown event)))) + (when (and is-open focused-id) + (on-enter focused-id))) esc? (do (dom/prevent-default event) diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/token_parsing.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/token_parsing.cljs index e0a12e4018..46c4548caf 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/token_parsing.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/token_parsing.cljs @@ -20,28 +20,40 @@ {:start last-open :partial (subs text-before (inc last-open))}))) +;; (defn replace-active-token +;; [value cursor new-name] +;; +;; (let [before (subs value 0 cursor) +;; last-open (str/last-index-of before "{") +;; last-close (str/last-index-of before "}")] +;; +;; (if (and last-open +;; (or (nil? last-close) +;; (> last-open last-close))) +;; +;; (let [after-start (subs value last-open) +;; close-pos (str/index-of after-start "}") +;; end (if close-pos +;; (+ last-open close-pos 1) +;; cursor)] +;; (str (subs value 0 last-open) +;; "{" new-name "}" +;; (subs value end))) +;; (str (subs value 0 cursor) +;; "{" new-name "}" +;; (subs value cursor))))) + (defn replace-active-token [value cursor new-name] - - (let [before (subs value 0 cursor) - last-open (str/last-index-of before "{") - last-close (str/last-index-of before "}")] - - (if (and last-open - (or (nil? last-close) - (> last-open last-close))) - - (let [after-start (subs value last-open) - close-pos (str/index-of after-start "}") - end (if close-pos - (+ last-open close-pos 1) - cursor)] - (str (subs value 0 last-open) - "{" new-name "}" - (subs value end))) - (str (subs value 0 cursor) - "{" new-name "}" - (subs value cursor))))) + (if-let [{:keys [start]} (extract-partial-token value cursor)] + ;; Hay token activo + (str (subs value 0 start) + "{" new-name "}" + (subs value cursor)) + ;; No hay token activo → insertar en cursor + (str (subs value 0 cursor) + "{" new-name "}" + (subs value cursor)))) (defn active-token [value input-node] (let [cursor (dom/selection-start input-node)] diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/utils.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/utils.cljs index 2d887d9daf..82c77facb1 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/utils.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/utils.cljs @@ -14,24 +14,28 @@ (defn- generate-dropdown-options [tokens no-sets] - (if (empty? tokens) + (let [non-empty-groups + (->> tokens + (filter (fn [[_ items]] (seq items))))] + (if (empty? non-empty-groups) [{:type :empty :label (if no-sets (tr "ds.inputs.numeric-input.no-applicable-tokens") (tr "ds.inputs.numeric-input.no-matches"))}] - (->> tokens - (map (fn [[type items]] - (cons {:group true - :type :group - :id (dm/str "group-" (name type)) - :name (name type)} - (map token->dropdown-option items)))) + (->> non-empty-groups + (keep (fn [[type items]] + (when (seq? items) + (cons {:group true + :type :group + :id (dm/str "group-" (name type)) + :name (name type)} + (map token->dropdown-option items))))) (interpose [{:separator true :id "separator" :type :separator}]) (apply concat) (vec) - (not-empty)))) + (not-empty))))) (defn- extract-partial-brace-text [s] @@ -84,7 +88,7 @@ options (if (seq partial) (filter-token-groups-by-name sorted-tokens partial) sorted-tokens) - no-sets? (nil? sorted-tokens)] + no-sets? (empty? sorted-tokens)] (generate-dropdown-options options no-sets?)))) (defn filter-tokens-for-input @@ -92,4 +96,7 @@ (delay (-> (deref raw-tokens) (select-keys (get cto/tokens-by-input input-type)) - (not-empty)))) \ No newline at end of file + (not-empty)))) + +(defn focusable-options [options] + (filter #(= (:type %) :token) options)) \ No newline at end of file diff --git a/frontend/src/app/util/dom.cljs b/frontend/src/app/util/dom.cljs index 11a42cf2fb..0e9d15635d 100644 --- a/frontend/src/app/util/dom.cljs +++ b/frontend/src/app/util/dom.cljs @@ -282,6 +282,11 @@ (when (some? node) (.-selectionStart node))) +(defn set-selection-range! + [^js node start end] + (when (some? node) + (.setSelectionRange node start end))) + (defn ^boolean equals? [^js node-a ^js node-b]