12

I want use the getSelection function to select words from articles to a view box.

Here is my code: http://jsfiddle.net/xQKNh/2/.

Now I want to ask, how to use JavaScript to select the whole word?

For explanation,

Is your question about programming?

In my code, if I choose r question about pro, the view box will show

r question about pro

But how to make the words completed? So that it outputs:

your question about programming. 

Javascript code:

function getSelected() {
  if(window.getSelection) { return window.getSelection(); }
  else if(document.getSelection) { return document.getSelection(); }
  else {
    var selection = document.selection && document.selection.createRange();
    if(selection.text) { return selection.text; }
    return false;
  }
  return false;
}
$(document).ready(function() {
  $('#content-area').mouseup(function() {
    var selection = getSelected();
    if(selection && (selection = new String(selection).replace(/^\s+|\s+$/g,''))) {
        $('#show-text').html(selection)
    }
  });
});
pimvdb
  • 151,816
  • 78
  • 307
  • 352
yuli chika
  • 9,053
  • 20
  • 75
  • 122

2 Answers2

24

Recent versions of Firefox and WebKit browsers have a built-in modify() (see also work-in-progress spec) method of the Selection object to do this. IE has had a completely different way to do this since version 4. In either case, this method has the significant advantage of working across element boundaries.

The following example works in IE 4+, Firefox 4+ and Safari and Chrome in versions released in the last couple of years. Opera as yet has no support for the modify() method of Selection objects.

UPDATE 20 October 2011

I've rewritten this to actually (mostly) work now (it didn't work properly in non-IE browsers before, as pointed out in the comments). Unfortunately, the selection expansion is too greedy in non-IE and expands the selection to the next word if a whole word is already selected, but I can't see an easy way round this at the moment.

UPDATE 11 June 2012

I've now updated this with an improvement from this answer to a related question. Thanks to Matt M and Fong-Wan Chau for this.

Live demo: http://jsfiddle.net/rrvw4/23/

Code:

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);

            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();
        }
    }
}
Community
  • 1
  • 1
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • 1
    Thanks for chiming in. This does look like a better answer. – James Sulak Sep 12 '11 at 13:08
  • @James: A Range-only answer coupled with a `TextRange`-based thing for older IE will cover more browsers than my answer though, so depending on the OP's requirements yours may be better. – Tim Down Sep 12 '11 at 13:34
  • two of you are great people. thanks two of you, so I change the mark to tim, but also thanks to james – yuli chika Sep 12 '11 at 19:14
  • Your demo works for me on IE8, but on FF4 it selects only the word under the mouse and the space after it, rather than expanding the current selection to include any partially selected words. This also means if the you move the mouse down off the text before releasing the button that the selection does not change at all. – Sam Oct 20 '11 at 09:38
  • @Sam: You're right. I did a better version of this more recently. I'll update this answer. – Tim Down Oct 20 '11 at 10:56
  • @Sam: Updated. There is still a problem with the new code, which I've mentioned in the revised answer. – Tim Down Oct 20 '11 at 11:02
  • The mouse down problem is also still there. – Sam Oct 21 '11 at 16:47
  • @Sam: Frankly I'm not that bothered about the mouse down issue: the jsFiddle example is supposed to demonstrate the selection expansion rather than show the best way to capture the selection changing. – Tim Down Oct 21 '11 at 17:22
  • Hi, @Tim Down, sorry to bother you again. I noticed you updated the code. so how to put `sel` into a `$('#show-text').html()`? I remove the `outer function` make a jquery mouseup, tested in ff and ie, ff can get the select value, but ie6 can not get the `alert(sel)`, it return `[object]`. Thanks. – yuli chika Nov 09 '11 at 00:16
  • @yulichika: For non-IE, call `toString()` on the selection. In IE < 9, use the `text` property of the TextRange. See http://stackoverflow.com/questions/5379120/jquery-get-the-highlighted-text/5379408#5379408, for example. – Tim Down Nov 12 '11 at 16:16
  • I've been using this code reliably, but it no longer works in the latest version of Chrome on Windows (it now selects following spaces and punctuation). Any suggestions on how to fix this? (or should I start a new question for the problem?) – Paul Nov 07 '13 at 23:53
  • 1
    @Paul: I'll take a look when I have a bit more time. In the meantime, I've solved the same problem (admittedly with a mountain of code) in my [Rangy](https://code.google.com/p/rangy/) library: http://rangy.googlecode.com/svn/trunk/demos/textrange.html – Tim Down Nov 08 '13 at 09:32
  • I realize this is a serious necro, but this does not work in iOS safari. – Our_Benefactors Jun 23 '17 at 17:24
  • Found edge case scenario - when you try to select `+` inside `1 + 2` string, it will select everything. Same for `-`. Not sure why. If you put there e.g. `1 w 2` and try select `w` - it will work fine. – lukaszkups May 17 '19 at 14:15
  • 1
    @lukaszkups: So it does (in Chrome, at least). Must be down to what the browser considers a word. – Tim Down May 17 '19 at 14:20
  • ah ok :) I've found it in Firefox and Chrome on Ubuntu. – lukaszkups May 17 '19 at 14:23
  • 2023, this doesnt work on android google chrome browsers @TimDown – fmsthird Jul 14 '23 at 12:00
  • @fmsthird: I find that surprising because the browser APIs this answer uses have not changed. However, I don't have an Android device to test on. – Tim Down Jul 15 '23 at 23:13
  • yeah it's super weird – fmsthird Jul 17 '23 at 00:02
7

The trick here is to use DOM ranges. You can then expand the range in either direction until you hit a space. So (warning, not extensively tested):

function getSelected() {
  if(window.getSelection) { return window.getSelection(); }
  else if(document.getSelection) { return document.getSelection(); }
  else {
    var selection = document.selection && document.selection.createRange();
    if(selection.text) { return selection.text; }
    return false;
  }
  return false;
}

function expand(range) {
    if (range.collapsed) {
        return;
    }

    while (range.toString()[0].match(/\w/)) {
        range.setStart(range.startContainer, range.startOffset - 1);   
    }

    while (range.toString()[range.toString().length - 1].match(/\w/)) {
        range.setEnd(range.endContainer, range.endOffset + 1);
    }
}

$(document).ready(function() {
  $('#content-area').mouseup(function() {
    var selectionRange = getSelected().getRangeAt(0);
    var start = selectionRange.startOffset; 
    expand(selectionRange);
    var selection = selectionRange.toString();
    if(selection && (selection = new String(selection).replace(/^\s+|\s+$/g,''))) {
        $('#show-text').html(selection)
    }
  });
});

Optimization is left as an exercise for the reader.

James Sulak
  • 31,389
  • 11
  • 53
  • 57
  • 1
    This won't work when the parts of a word are contained in different elements. It also won't work in IE < 9, which have no support for `window.getSelection()` or `Range`. – Tim Down Sep 11 '11 at 22:08