From 90949431f58a6ba20189a35629b5b3aa8114a59a Mon Sep 17 00:00:00 2001 From: mike-thompson-day8 Date: Fri, 8 May 2015 11:53:55 +1000 Subject: [PATCH 1/3] Fix #79 - position cursor after resetting an input's value --- src/reagent/impl/template.cljs | 42 ++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/reagent/impl/template.cljs b/src/reagent/impl/template.cljs index fa2d8b0..bea7b3a 100644 --- a/src/reagent/impl/template.cljs +++ b/src/reagent/impl/template.cljs @@ -90,12 +90,46 @@ (defn input-unmount [this] (.! this :cljsInputValue nil)) +;; +(def these-inputs-have-a-cursor #{"text" "password" "email" "number" "search" "tel" "url"}) + +(defn has-cursor? + [input-type] + (contains? these-inputs-have-a-cursor input-type)) + (defn input-set-value [this] (when-some [value (.' this :cljsInputValue)] - (.! this :cljsInputDirty false) - (let [node (.' this getDOMNode)] - (when (not= value (.' node :value)) - (.! node :value value))))) + (.! this :cljsInputDirty false) + (let [node (.' this getDOMNode) + node-value (.' node :value)] + (when (not= value node-value) + (if-not (has-cursor? (.' node :type)) + ; just set the value, no need to worry about a cursor + (.! node :value value) + + ;; Setting "value" (below) moves the cursor position to the end which + ;; gives the user a jarring experience. + ;; + ;; But repositioning the cursor within the text, turns out + ;; to be quite a challenge because changes in the text can be + ;; triggered by various events like: + ;; - a validation function rejecting a certain user inputted char + ;; - the user enters a lower case char, but is transformed to upper. + ;; - the user selects multiple chars and deletes text + ;; - the user pastes in multiple chars, and some of them are rejected + ;; by a validator. + ;; - the user selects multiple chars and then types in a single + ;; new char to repalce them all. + ;; Coming up with a sane cursor repositioning strategy hasn't been easy + ;; ALTHOUGH in the end, it kinda fell out nicely, and it appears to sanely + ;; handle all the cases we could think of. + ;; So this is just a warning. The code below is simple enough, but if + ;; you are tempted to change it, be aware of all the scenarios you have handle. + (let [existing-offset-from-end (- (count node-value) (.' node :selectionStart)) + new-cursor-offset (- (count value) existing-offset-from-end)] + (.! node :value value) + (.! node :selectionStart new-cursor-offset) + (.! node :selectionEnd new-cursor-offset))))))) (defn input-handle-change [this on-change e] (let [res (on-change e)] From 985641d847faa0fcaaaf313c7f438929bd8b8290 Mon Sep 17 00:00:00 2001 From: mike-thompson-day8 Date: Mon, 11 May 2015 17:30:00 +1000 Subject: [PATCH 2/3] Make cursor position work for