A common behavior found in web applications is to select the text within an input type box when the user clicks the box. Example uses for this behavior are placing direction text within the box that says how to use it, for example, "Search." When the user selects the search box, the "Search" is selected so the user can quickly type in new text. At Ubernote, I have been doing this for the last couple of years, but I recently changed the way we did it and ran into some problems I forgot about. When I first coded the behavior, I saw examples all over the web of things like:
<input type='text' value='search' onfocus='this.select()' />
There are a ton of variations on this, including using jQuery, and instead of registering a listener on onfocus use onclick, etc.
My expectations for the full behavior are:
1) Select all text in the input box when the user clicks into the input. 2) When clicking again into the input box, place the cursor in that position. 3) If clicking outside of the input box and then into the input box again, go to behavior 1.
Using the solutions I found on the web, there is a problem with Firefox 2.0+, as well as the newer Webkit based browsers Safari 4 and Chrome 2. The problem is sometimes the text gets selected and stays selected, and at other times the text is selected, but immediately unselects and the cursor is placed where the user clicked. Not the desired behavior. Try it below.
The first time I coded up a solution, I didn't put much thought into it and noticed that if I did the select inside of a setTimeout with a short delay, things seemed to work, but I was never really sure why. Today I decided to delve into this a bit more and come up with a reasonable solution that did not depend on using setTimeout.
I wanted to figure out what was happening that made the browsers act funny, so I decided to set up a simple test script to find out what was happening and if there was any difference in the DOM events that were being raised when the text stayed selected and when the text did the select/unselect. I made a simple page with with an <input type="text"> element and using jQuery, attached several listeners to the element. I attached listeners for click, mousedown, mouseup, focus, select, and blur.
This is a short text snippet showing the test code.
The full test page is found here (Does not work in IE, depends on there being a window.console object).
Alternately clicking into the input box and then the body, I was able to see the difference. When the text selects and then unselects, the following series of events happen:
mousedown focus select mouseup click blur
The select is happening BEFORE the mouseup. When the text remains selected, the following series of events happen:
mousedown focus select mouseup select click blur
Two selects, one before and one after the mouseup? Something is going on here. I kept trying different events and preventing their default behaviors until I found out for sure that it was mouseup causing the problems. If preventDefault was called on the mouseup event, the text always stayed selected.
So I called preventDefault on mouseup. But then I found that I could not put the cursor into the input box after the initial click. This isn't the desired behavior either. I wanted the first click to select the text, and the second+ to put the cursor into the position I clicked at. So, really, I only want to call preventDefault on the FIRST mouseup event. To be able to re-enable the highlighting if we click somewhere else on the page (causing a blur event on the input), we again have to preventDefault on the first mouseup when clicking into the input. I ended up using a global variable called bPreventMouseUp to keep track of when to do this. If bPreventMouseUp is true, in mouseUpHandler, prevent the default. Set bPreventMouseUp to true on startup, and on blur.
The final solution code snippet is:
The full solution can be found here
So in the end, I get a smooth text selection working across all browsers and with fully expected behavior. Just what I wanted.