Focus and Select: a cross-browser bed time story

Here's an annoying little DOM'ism that stumped me last week (don't worry, there's a happy ending if you keep reading).  In Popcorn Maker's UI I wanted to fix a few places where we have textboxes that contain data from json manifests.  When you click on such a pre-populated textbox, it's nice if the contents of the textbox are selected.  And when you click again, it's nice if the selection is removed and you instead position the cursor.

These are nice enough that one would sort of expect them to just work, and as such, that the DOM would actually allow you to do it.  Well, it's easy to do on Firefox: just add a focus event to your input element, and call element.select().  Done.

Now test in WebKit and it doesn't work. Sniff around the web a bit and you'll uncover a nasty 4-digit WebKit bug from 2008 that causes mouseup to undo your selection.

"That's fine," you say to yourself, "just stop the mouseup event from doing its thing and clearing the selection." This is what everything on the web I could find said to do. The trouble is, I want to not only select the contents of the textbox on first click, but I want the opposite on subsequent clicks.

In the end, cross-browser compatible code means unnecessarily elaborate code, but here we are. I'll leave this for the next person who hits my same edge case--aka the default way a textbox should function. Here's a little jsfiddle demo of it running, and here's the code:

var selectaBox = (function(){  
  
  function __highlight( e ){  
    var input = e.target;  
    input.select();  
    input.removeEventListener( "focus", __highlight, false );  
  }  
  
  function __ignoreMouseUp( e ){  
    e.preventDefault();  
    var input = e.target;  
    input.removeEventListener( "mouseup", __ignoreMouseUp, false );  
  }  
  
 function __addListeners( input ){  
    input.addEventListener( "focus", __highlight, false );  
    input.addEventListener( "mouseup", __ignoreMouseUp, false );  
 }  
  
 return function(){  
   var input = document.createElement( "input" );  
   input.type = "text";  
   input.addEventListener(  
     "blur",  
     function( e ){  
       __addListeners( e.target );  
     },  
     false  
   );  
  
   __addListeners( input );  
  
   return input;  
 };  
  
}());  
  
var s = selectaBox();  
s.value = "This is some text."  
document.body.appendChild(s);
Show Comments