2

jQuery select event is limited to textarea and input:text only. Is there a way to handle a selection in ordinary elements such as <div>?

Gert Grenander
  • 16,866
  • 6
  • 40
  • 43
Viliam
  • 4,404
  • 3
  • 28
  • 30

2 Answers2

3

jQuery's select event wraps the native browser select event, which fires for any kind of selection in IE and WebKit but only for inputs and textareas in other browsers.

This question has come up several times before:

You'll see lots of answers similar to Luke's, none of which fully work. Firstly, you need to consider selections made by keyboard, and also via the "Select All" option in the Edit and context browser menus. Secondly, checking for a change in selection by looking at the selection text isn't entirely reliable: if the user selects the same text elsewhere in the document, it will not be picked up.

Here's some code that will fix most of the problems, although short of polling the selection there's nothing you can do about "Select All" from the Edit and context menus.

var addSelectHandler = function(callback) {
    var selectionChangeEventHandler;

    if (typeof window.getSelection != "undefined" && typeof document.addEventListener != "undefined") {
        var previouslySelected = null;

        var rangesEqual = function(r1, r2) {
            return r1.startContainer === r2.startContainer && r1.startOffset === r2.startOffset &&
                   r1.endContainer === r2.endContainer && r1.endOffset === r2.endOffset;
        };

        selectionChangeEventHandler = function() {
            var sel = window.getSelection(), selectedRanges = [], range;
            var changed = !previouslySelected || (sel.rangeCount != previouslySelected.length);
            for (var i = 0, len = sel.rangeCount; i < len; ++i) {
                range = sel.getRangeAt(0).cloneRange();
                selectedRanges[i] = range;
                if (!changed && !rangesEqual(range, previouslySelected[i])) {
                    changed = true;
                }
            }
            previouslySelected = selectedRanges;
            if (changed) {
                callback();
            }
        };

        document.addEventListener("mouseup", selectionChangeEventHandler, false);
        document.addEventListener("keyup", selectionChangeEventHandler, false);
    } else if (typeof document.selection != "undefined" && typeof document.attachEvent != "undefined") {
        // This is IE, which fires a selectionchange event for any selection
        document.attachEvent("onselectionchange", callback);
    }
};

addSelectHandler(function() {
    alert("Selection changed");
}
Community
  • 1
  • 1
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • I might add that by also listening to mousemove and mouseout, I was able to deal with the context menu's select all as well. So there is actually something that can be done about "Select all" after all. – sboisse Oct 26 '12 at 13:54
  • @sboisse: Presumably you have to check the selection whenever the `mousemove` event fires then? That seems pretty much the same as polling to me. – Tim Down Oct 26 '12 at 14:04
  • It is polling, but I was looking for a way to get it to work without using a timer so it is wasting less processing in the browser. – sboisse Oct 26 '12 at 15:06
2
function getSelText()
{
    var txt = '';
     if (window.getSelection)
    {
        txt = window.getSelection();
             }
    else if (document.getSelection)
    {
        txt = document.getSelection();
            }
    else if (document.selection)
    {
        txt = document.selection.createRange().text;
    }
    return txt;
}

$(document).mouseup(function() {
    alert(getSelText());
});

I dont know if jQuery has one but this can be used to make a new plugin, where you hook up an event for mouseup.

Luke
  • 8,235
  • 3
  • 22
  • 36
  • Yeah, you could get the selection if the position of the mouse recorded on mousedown is different of its position on mouseup. – Robin Feb 06 '11 at 01:42
  • the easier way i think is to just check if there is any text – Luke Feb 06 '11 at 01:45
  • Is there any practical reason why is select in jQuery limited to textarea and input-text only? – Viliam Feb 06 '11 at 01:45
  • @robin to use the mouseposition is not realy jquery like, i think it´s realy better then to write a plugin und to use it like this $("div.justmydiv").textSelect() and $("div.justmydiv").textSelect("destroy") – Luke Feb 06 '11 at 01:55
  • Yes, I meant if you were to write a plugin, it would be cool to check the mouse position to determine if the selection occured in the element. – Robin Feb 06 '11 at 01:56
  • yeah thats true, that´s a possiblity, but then it would not fire if the end position of the mouse is in another div – Luke Feb 06 '11 at 02:03
  • It depends, you could choose to fire when the start position or end position is inside the element. It would have to be tested to see what's best, or just be configurable ;) – Robin Feb 06 '11 at 02:06
  • The `getSelText()` function is wrong: `window.getSelection()` returns a `Selection` object, not a string. The reason why it appears to work is that the `alert()` implicitly calls `toString()` on its parameter. Secondly, the selection can also be altered via the keyboard, or by the "Select All" option in the Edit and context menus. Thirdly, checking for a change in selection by looking at the selection text isn't entirely reliable: if the user selects the same text elsewhere in the document, this will not pick that up. – Tim Down Feb 06 '11 at 11:25