views:

1231

answers:

2

You can select a part of a web page with the mouse.

I know that I can get the currently selected text but how can I get the DOM element which contains the start or end of the current selection?

+6  A: 

In IE, use document.selection.createRange().parentElement() and in real browsers use window.getSelection().getRangeAt(0).startContainer.parentNode. Something like this:

function getSelectedNode()
{
    if (document.selection)
     return document.selection.createRange().parentElement();
    else
    {
     var selection = window.getSelection();
     if (selection.rangeCount > 0)
      return selection.getRangeAt(0).startContainer.parentNode;
    }
}
InvisibleBacon
This will give inconsistent results between browsers and doesn't answer the original question. In IE you get the element that contains the whole selection, while in other browsers you will get the parent of the node that contains the start of the selection (which could be a text node or an element).
Tim Down
+8  A: 

InvisibleBacon's solution won't work in older versions of WebKit, including (I think) Safari 2, which is missing the getRangeAt method of the selection object. You need to use the anchorNode and focusNode properties of the selection object in that browser.

It will also give you inconsistent results between browsers. In the IE case you will get the innermost element that contains the whole selection, while the case for other browsers will merely give you the parent of the container node for the start of the selection, which assumes the boundary is a text node (not necessarily the case).

The following will return the container element of the start or end boundary of the current selection, using the boolean isStart to specify whether you want the start or end boundary. It will work in most mainstream browsers. Add feature tests for more robustness.

function getSelectionBoundaryElement(isStart) {
    var range, sel, container;
    if (document.selection) {
        range = document.selection.createRange();
        range.collapse(isStart);
        return range.parentElement();
    } else {
        sel = window.getSelection();
        if (sel.getRangeAt) {
            if (sel.rangeCount > 0) {
                range = sel.getRangeAt(0);
            }
        } else {
            // Old WebKit
            range = document.createRange();
            range.setStart(sel.anchorNode, sel.anchorOffset);
            range.setEnd(sel.focusNode, sel.focusOffset);

            // Handle the case when the selection was selected backwards (from the end to the start in the document)
            if (range.collapsed !== sel.isCollapsed) {
                range.setStart(sel.focusNode, sel.focusOffset);
                range.setEnd(sel.anchorNode, sel.anchorOffset);
            }
       }

        if (range) {
           container = range[isStart ? "startContainer" : "endContainer"];

           // Check if the container is a text node and return its parent if so
           return container.nodeType === 3 ? container.parentNode : container;
        }   
    }
}
Tim Down