Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Insert html at caret in a contenteditable div

I have a div with contenteditable set and I am capturing keypress using jquery to call preventDefault() when the enter key is pressed. Similar to this question which inserts text at the cursor, I would like to directly insert html, for brevity we'll say its a br tag. Using the answer to the question above actually works in IE as it uses the range.pasteHTML method, but in other browsers the br tag would appear as plain text and not html. How could I modify the answer to insert html and not text ?

like image 601
Niall Avatar asked Jul 14 '11 08:07

Niall


1 Answers

In most browsers, you can use the insertNode() method of the Range you obtain from the selection. In IE < 9 you can use pasteHTML(), as you mentioned. Below is a function to do this in all major browsers. If content is already selected, it is replaced, so this is effectively a paste operation. Also, I added code to place the caret after the end of the inserted content.

jsFiddle: http://jsfiddle.net/jwvha/1/

Code:

function pasteHtmlAtCaret(html) {     var sel, range;     if (window.getSelection) {         // IE9 and non-IE         sel = window.getSelection();         if (sel.getRangeAt && sel.rangeCount) {             range = sel.getRangeAt(0);             range.deleteContents();              // Range.createContextualFragment() would be useful here but is             // only relatively recently standardized and is not supported in             // some browsers (IE9, for one)             var el = document.createElement("div");             el.innerHTML = html;             var frag = document.createDocumentFragment(), node, lastNode;             while ( (node = el.firstChild) ) {                 lastNode = frag.appendChild(node);             }             range.insertNode(frag);              // Preserve the selection             if (lastNode) {                 range = range.cloneRange();                 range.setStartAfter(lastNode);                 range.collapse(true);                 sel.removeAllRanges();                 sel.addRange(range);             }         }     } else if (document.selection && document.selection.type != "Control") {         // IE < 9         document.selection.createRange().pasteHTML(html);     } } 

UPDATE 21 AUGUST 2013

As requested in the comments, here is an updated example with an extra parameter that specifies whether or not to select the inserted content.

Demo: http://jsfiddle.net/timdown/jwvha/527/

Code:

function pasteHtmlAtCaret(html, selectPastedContent) {     var sel, range;     if (window.getSelection) {         // IE9 and non-IE         sel = window.getSelection();         if (sel.getRangeAt && sel.rangeCount) {             range = sel.getRangeAt(0);             range.deleteContents();              // Range.createContextualFragment() would be useful here but is             // only relatively recently standardized and is not supported in             // some browsers (IE9, for one)             var el = document.createElement("div");             el.innerHTML = html;             var frag = document.createDocumentFragment(), node, lastNode;             while ( (node = el.firstChild) ) {                 lastNode = frag.appendChild(node);             }             var firstNode = frag.firstChild;             range.insertNode(frag);              // Preserve the selection             if (lastNode) {                 range = range.cloneRange();                 range.setStartAfter(lastNode);                 if (selectPastedContent) {                     range.setStartBefore(firstNode);                 } else {                     range.collapse(true);                 }                 sel.removeAllRanges();                 sel.addRange(range);             }         }     } else if ( (sel = document.selection) && sel.type != "Control") {         // IE < 9         var originalRange = sel.createRange();         originalRange.collapse(true);         sel.createRange().pasteHTML(html);         if (selectPastedContent) {             range = sel.createRange();             range.setEndPoint("StartToStart", originalRange);             range.select();         }     } } 
like image 145
Tim Down Avatar answered Sep 30 '22 09:09

Tim Down