15

Is there a simple js function I can use to replace the current document's selection with some html of mine?

For instance say the document contains a <p>AHAHAHA</p> somewhere and user selects the 1st "ha" text chunk.

Now I want to replace this with something like: <span><font color="red">hoho</font></span>

When I google for *javascript replace selection * I can't get a simple straightforward answer!

Didier Levy
  • 3,393
  • 9
  • 35
  • 57

2 Answers2

26

Yes. The following will do it in all major browsers, with an option to select the inserted content afterwards as requested in the comments (although this part is not implemented for IE <= 8):

Live demo: http://jsfiddle.net/bXsWQ/147/

Code:

function replaceSelection(html, selectInserted) {
    var sel, range, fragment;

    if (typeof window.getSelection != "undefined") {
        // IE 9 and other non-IE browsers
        sel = window.getSelection();

        // Test that the Selection object contains at least one Range
        if (sel.getRangeAt && sel.rangeCount) {
            // Get the first Range (only Firefox supports more than one)
            range = window.getSelection().getRangeAt(0);
            range.deleteContents();

            // Create a DocumentFragment to insert and populate it with HTML
            // Need to test for the existence of range.createContextualFragment
            // because it's non-standard and IE 9 does not support it
            if (range.createContextualFragment) {
                fragment = range.createContextualFragment(html);
            } else {
                // In IE 9 we need to use innerHTML of a temporary element
                var div = document.createElement("div"), child;
                div.innerHTML = html;
                fragment = document.createDocumentFragment();
                while ( (child = div.firstChild) ) {
                    fragment.appendChild(child);
                }
            }
            var firstInsertedNode = fragment.firstChild;
            var lastInsertedNode = fragment.lastChild;
            range.insertNode(fragment);
            if (selectInserted) {
                if (firstInsertedNode) {
                    range.setStartBefore(firstInsertedNode);
                    range.setEndAfter(lastInsertedNode);
                }
                sel.removeAllRanges();
                sel.addRange(range);
            }
        }
    } else if (document.selection && document.selection.type != "Control") {
        // IE 8 and below
        range = document.selection.createRange();
        range.pasteHTML(html);
    }
}

Example:

replaceSelection('<span><font color="red">hoho</font></span>', true);
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • Cool! Could u plz add a small amount of comments, like wich conditions are for IE and which for other browsers, thanks! – Marco Demaio Mar 22 '11 at 16:35
  • Works on Safari 5.2.1 on snow leopard for me too. Thanks, i really looked for the ie9 thing! – xotix Mar 09 '12 at 15:00
  • How to get this to maintain the selection? So that 'hoho' is selected after the operation. – Timo Kähkönen May 03 '14 at 20:43
  • @TimDown: Thanks, it works! Is it possible to prevent replacing if the selection length is zero? Now it adds hoho, if I only click something. – Timo Kähkönen May 05 '14 at 11:09
  • @Timo: Test `window.getSelection().isCollapsed` in browsers other than old IE and `!!document.selection.createRange().text` in old IE. – Tim Down Aug 04 '14 at 11:15
7

You can use the Rangy library http://code.google.com/p/rangy/

You can then do

var sel = rangy.getSelection();
var range = sel.getRangeAt(0);

range.deleteContents();
var node = range.createContextualFragment('<span><font color="red">hoho</font></span>');
range.insertNode(node);
sakibfarid
  • 151
  • 2
  • 6