I\'m using the technique shown in this answer to extend a web page\'s selection to a word boundary:
function snapSelectionToWord() {
var sel;
// Che
your code does not work properly in arabic text you can try this snippet nstead
function snapSelectionToWord() {
var sel;
// Check for existence of window.getSelection() and that it has a
// modify() method. IE 9 has both selection APIs but no modify() method.
if (window.getSelection && (sel = window.getSelection()).modify) {
sel = window.getSelection();
if (sel.isCollapsed) {
var rng2 = sel.getRangeAt(0);
var startOffset = rng2.startOffset;
startOffset = 0
for (var i = rng2.startOffset; i >= 0; i--) {
if (rng2.startContainer.data[i].match(/\S/) != null) {
startOffset++;
} else
break;
}
var endOffset = rng2.endOffset;
endOffset = 0;
for (var i = rng2.endOffset; i < rng2.endContainer.data.length; i++)
if (rng2.endContainer.data[i].match(/\S/)) {
endOffset++;
} else
break;
startOffset = rng2.startOffset - startOffset;
startOffset = startOffset < 0 ? 0 : startOffset;
endOffset = rng2.endOffset + endOffset;
endOffset = endOffset >= rng2.endContainer.data.length ? rng2.endContainer.data.length - 1 : endOffset;
rng2.setStart(rng2.startContainer, startOffset);
rng2.setEnd(rng2.endContainer, endOffset);
sel.removeAllRanges();
sel.addRange(rng2);
}
} else if ( (sel = document.selection) && sel.type != "Control") {
var textRange = sel.createRange();
if (textRange.text) {
textRange.expand("word");
// Move the end back to not include the word's trailing space(s),
// if necessary
while (/\s$/.test(textRange.text)) {
textRange.moveEnd("character", -1);
}
textRange.select();
}
}
}
I wrote that sample. I've never been happy with it, for the reason you point out, and also because it doesn't work consistently in all browsers (or at all in Opera).
I've been working on a cross-browser solution to this for my Rangy library. The current release is described as an alpha but it works pretty well. Here's a demo:
http://rangy.googlecode.com/svn/trunk/demos/textrange.html
And here's your demo, modified to use Rangy:
http://jsfiddle.net/timdown/RgZ8r/
The crucial line is
rangy.getSelection().expand("word");
If you don't want to use something as heavyweight as Rangy (it's something like 50KB of code to use the TextRange module) then it's possible to improve the original code (as Matt M has in his answer) but it will still have limitations.
Maybe try popping a character off in either direction before you snap to words:
if (backwards) {
sel.modify("move", "backward", "character");
sel.modify("move", "forward", "word");
sel.extend(endNode, endOffset);
sel.modify("extend", "forward", "character");
sel.modify("extend", "backward", "word");
} else {
sel.modify("move", "forward", "character");
sel.modify("move", "backward", "word");
sel.extend(endNode, endOffset);
sel.modify("extend", "backward", "character");
sel.modify("extend", "forward", "word");
}
http://jsfiddle.net/3RAkZ/