tags:

views:

490

answers:

1

I am looking for a solution that works cross browser i.e. IE, Firefox and Safari.

+5  A: 

By "editable content window" I'm going to assume you mean an element with contenteditable turned on or a document with designMode turned on.

There are also two cases to consider: the case when the user has made a selection and the case where there is just a caret. The code below will work in both cases, and will give you the innermost element that completely contains the selection. If the selection is completely contained within a text node it's slightly complicated to get that text node in IE (trivial in other browsers), so I haven't provided that code here. If you need it, I can dig it out.

function getSelectionContainerElement() {
    var range, sel, container;
    if (document.selection && document.selection.createRange) {
        // IE case
        range = document.selection.createRange();
        return range.parentElement();
    } else if (window.getSelection) {
        sel = window.getSelection();
        if (sel.getRangeAt) {
            if (sel.rangeCount > 0) {
                range = sel.getRangeAt(0);
            }
        } else {
            // Old WebKit selection object has no getRangeAt, so
            // create a range from other selection properties
            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.commonAncestorContainer;

           // Check if the container is a text node and return its parent if so
           return container.nodeType === 3 ? container.parentNode : container;
        }   
    }
}
Tim Down
Tim, this is exactly what I was looking for. I would appreciate if you can also dig in the IE case where selection is contained with in a text node. Thanks.
Murali VP
Btw, the IE case where you return range.parentElement() always seems to return the body element even though the caret was in text that inside an anchor node eg. In this HTML <a href="http://www.stackoverflow.com">xyz</a> if the caret was in between say 'x' and 'y', shouldn't parentElement() return the 'a' node?
Murali VP
Yes, it should. I haven't had problems with `parentElement()` before - have you got a page I can look at showing the problem?
Tim Down
The IE code is quite involved. I use my own optimizations of the algorithms in IERange (http://code.google.com/p/ierange/).
Tim Down
@Tim, great code. But there is a problem with IE when you want to get the parent without selecting any text, just positioning a caret. How to fix that?
markiz
Still works for me in IE. Can you post an example showing your problem?
Tim Down