How to extend selection to the word boundary using JavaScript only once?

I use the method shown in this answer to expand the selection of a webpage to the word boundary:

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) { // 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); if (backwards) { sel.modify("move", "forward", "word"); sel.extend(endNode, endOffset); sel.modify("extend", "backward", "word"); } else { sel.modify("move", "backward", "word"); sel.extend(endNode, endOffset); sel.modify("extend", "forward", "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 trailing space(s), // if necessary while (/\s$/.test(textRange.text)) { textRange.moveEnd("character", -1); } textRange.select(); } } }​ 

So far so good. But if you call the snapSelectionToWord function more than once to choose from, it expands outward by one word in both directions with each call, which is not very good if you want to call it more than once when choosing text.

Here's a live jsFiddle example that allows you to repeatedly press the "Snap" button, which demonstrates the problem.

How can I fix the original solution so that it does not expand the selection if it is already at the word boundary?

  • I would prefer to leave a comment on the original solution , but, unfortunately, I was not yet decorated with enough karma by the StackOverflow career team - otherwise, I would just ask there. And I'm not sure how to fix the problem, so I will not edit the original solution.

Edit: add code snippet for request

+6
source share
3 answers

Perhaps try to pull the character in any direction before proceeding with the 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/

+5
source

I wrote this sample. I was never happy with this because you specify, and also because it does not work consistently in all browsers (or even in Opera).

I was working on a cross-browser solution for my Rangy library. The current release is described as alpha, but it works very well. Here is a demo:

http://rangy.googlecode.com/svn/trunk/demos/textrange.html

And here is your demo modified to use Rangy:

http://jsfiddle.net/timdown/RgZ8r/

The most important line is

 rangy.getSelection().expand("word"); 

If you do not want to use something heavy like Rangy (this is approximately 50 Kbytes of code for using the TextRange module), then you can improve the source code (like Matt M in your answer), but it will still have limitations.

+9
source

your code is not working properly in arabic text you can try this nstead snippet

 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 trailing space(s), // if necessary while (/\s$/.test(textRange.text)) { textRange.moveEnd("character", -1); } textRange.select(); } } } 
0
source

Source: https://habr.com/ru/post/897101/


All Articles