Or in a span, or any element that doesn't expose a
select()
method (like input and textarea do). These elements also don't expose the
selectionStart
range of properties to do the same thing.
This workaround is pretty old, but seems to work solidly in any browser these days.
var select = (function(s,r){
return function(e){
s.removeAllRanges();
r.selectNodeContents(e);
s.addRange(r);
};
})(getSelection(), document.createRange());
select(element1);
select(element2);
The cleaner version comes from
http://stackoverflow.com/questions/6139107/programatically-select-text-in-a-contenteditable-html-element :
function selectElementContents(el) {
var range = document.createRange();
range.selectNodeContents(el);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
var el = document.getElementById("foo");
selectElementContents(el);
It's just silly that the DOM doesn't expose these methods on any element.
In case you're curious. This works because
getSelection
returns an object, not the actual selection. It's
toString
method is "live", meaning it will return whatever the current selection is at the time of calling
toString
, rather than at the time of calling
getSelection
. This is kind of counter intuitive to me, but whatever.
Likewise,
document.createRange()
creates a re-usable object.
It's unfortunate that
range.selectNodeContents(e)
doesn't return the range value or we could simplify the code. Especially if
addRange(r)
would also call
removeAllRanges()
first. Ohwell.
Here's some boilerplate to do selection by index:
function selectRel(el, start, end) {
// end may be < 0 and is relative to start, start must be >=0
selectAbs(el, start, start + end);
}
function selectAbs(el, start, end){
// end may be 0 < end < start, start must be >=0
var s = getSelection();
s.removeAllRanges();
var r = new Range();
r.setStart(el, 0);
s.addRange(r);
if (typeof start === 'number' && start >= 0) {
if (typeof end === 'number') {
var d = end > start ? 'forward' : 'backward';
end = Math.abs(Math.abs(end) - start); // -5 - 10 = -15, 5 - 10 = -5
} else {
end = 0;
}
} else {
start = 0;
}
// modify api is quite tedious...
while (start--) {
s.modify('move', 'forward', 'character');
}
while (end--) {
s.modify('extend', d, 'character');
}
}