I try to modify the selection a user has done to always be complete words. For example, given the Text "Report: President Obama seeks to keep 9,800 US troops in Afghanistan...after this year, source says", if as user just selects "fghanist" I would like that the selection modifies to "Afghanistan". After some searching I stumbled, here on Stackoverflow, upon the following solution:
snapSelectionToWord : function() {
var sel;
if (window.getSelection && (sel = window.getSelection()).modify) {
sel = window.getSelection();
if (!sel.isCollapsed) {
// Detect if selection is backwards
var range = document.createRange();
range.setStart(sel.anchorNode, sel.anchorOffset);
range.setEnd(sel.focusNode, sel.focusOffset);
var backwards = range.collapsed;
range.detach();
// modify() works on the focus of the selection
var endNode = sel.focusNode, endOffset = sel.focusOffset;
sel.collapse(sel.anchorNode, sel.anchorOffset);
var direction = [];
if (backwards) {
direction = ['backward', 'forward'];
} else {
direction = ['forward', 'backward'];
}
sel.modify("move", direction[0], "character");
sel.modify("move", direction[1], "word");
sel.extend(endNode, endOffset);
sel.modify("extend", direction[1], "character");
sel.modify("extend", direction[0], "word");
}
} 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();
}
}
},
In principle, it works pretty well. However, there are some pathelogical cases. For examle, the selection "fghanistan.." it snaps to "Afghanistan...after" (I would like to have "Afghanistan"). The same result I get for selection ".afte" (desired result here: "after"). The main problem seems to be that the granularity word
only considers whitespace but not other punctuation marks.
My idea was now to change the granularity from word
to character
and put this into a loop until a punctuation signs is reached. This works pretty well for the sel.modify("extend", ...);
lines, but not (as intended) for the sel.modify("move", ...);
lines. Both after the collapse
and the first move
modification, sel.toString()
is empty. Hence, I cannot loop of the first/last character to move character by character. After sel.extend(endNode, endOffset);
, sel.toString()
is set again, and the approach using a loop works.
I simply cannot get my head around this.