Today I needed to know whether a Range object (obtained from a selection) intersected with a particular node within an HTML document, which is a relatively common scenario when developing WYSWIYG editors. Mozilla’s implementation of Range used to have a proprietary intersectsNode method, which was ideal. However, they’ve removed this in Gecko 1.9 (and therefore Firefox 3) and provided an example function that does the same job. Unfortunately this function doesn’t work in WebKit (and hence Safari and Chrome) because of a bug in WebKit: they seem to have managed to invert the behaviour of compareBoundaryPoints with END_TO_START and START_TO_END. Tsk.

So I’ve modified the Mozilla example to work consistently with all browsers that support Range:

function rangeIntersectsNode(range, node) {
    var nodeRange = node.ownerDocument.createRange();
    try {
        nodeRange.selectNode(node);
    } catch (e) {
        nodeRange.selectNodeContents(node);
    }

    var rangeStartRange = range.cloneRange();
    rangeStartRange.collapse(true);

    var rangeEndRange = range.cloneRange();
    rangeEndRange.collapse(false);

    var nodeStartRange = nodeRange.cloneRange();
    nodeStartRange.collapse(true);

    var nodeEndRange = nodeRange.cloneRange();
    nodeEndRange.collapse(false);

    return rangeStartRange.compareBoundaryPoints(
             Range.START_TO_START, nodeEndRange) == -1 &&
           rangeEndRange.compareBoundaryPoints(
             Range.START_TO_START, nodeStartRange) == 1;
}

Note: WebKit does implement the intersectsNode method on Range. However, I prefer not to use it in the above function because it’s not specified in the DOM standard for Range and may therefore end up being removed from WebKit, and there’s more chance of the function behaving consistently between browsers if it uses the same code in each.