Search This Blog

Saturday, February 14, 2009

Getting the HTML of a Range Created in JavaScript


Working on a mainly JavaScript-driven rich-text editor for the discussion forum on Mr. Renaissance, I wanted to include a feature that automatically inserted block quotations. Two days after the editor's debut, I suddenly noticed that this feature was losing its formatting: all line breaks and markup were gone, in its place one large, crunched-together paragraph that even ran sentences together in places.

A bit of Googling revealed that using range to retrieve the user's selection returns plain text (at least in non-IE browsers), not its formatted HTML:
The contents of userSelection

The userSelection variable is now either a Mozilla Selection or a Microsoft Text Range object. As such it grants access to all methods and properties defined on such objects.

However, the Mozilla Selection object that userSelection refers to in W3C-compliant browsers also contains the text the user has selected (as text, not as HTML).

From Introduction to Range, emphasis mine.
Frustrating, to say the least. I won't go into a list of all the things I tried, but I finally found the following (slightly modified) snippet of code at Snipplr, courtesy of David King of the entirely open-source OOPStudios in Newcastle, UK:
var getSelectionHTML = function() {
    var s;
    if (window.getSelection) {
        // W3C Ranges
        s = window.getSelection();
        // Get the range:
        if (s.getRangeAt) var r = s.getRangeAt(0);
        else {
            var r = document.createRange();
            r.setStart(s.anchorNode, s.anchorOffset);
            r.setEnd(s.focusNode, s.focusOffset);
        }
        // And the HTML:
        var clonedSelection = r.cloneContents(),
            div = document.createElement('div');
        div.appendChild(clonedSelection);
        return div.innerHTML;
    } else if (document.selection) {
        // Explorer selection, return the HTML
        s = document.selection.createRange();
        return s.htmlText;
    } else {
        return '';
    }
};
I am pleased to report that David has created a wonderful little function that returns the HTML of the user's selection rather than just plain, unformatted text.

Note: If you want to simulate the action of Cut (rather than Paste), change r.cloneContents() to r.extractContents(). Normally, there would be no reason to do so, but it is a possibility.

No comments:

Post a Comment