Friday, November 11, 2011

Working with Selections and Ranges in CKEditor

Working with ranges and selections in CKEditor is almost unbearable. In order to make it a bit easier, i recommend using rangy, a free library that makes the html selection/range api cross-browser-proof. Well, at least it made what i was trying to accomplish cross-browser...

/**
* allows you to wrap or insert an html tag over a selection/range using rangy
* @param iframe the CKEditor iframe html element
* @param tagName string representation of the tag, such as 'a' for anchor
* @param withNodeFunc function to allow outside modification of the element before injecting/wrapping
*/
function wrapOrInsert(iframe, tagName, withNodeFunc) {
var iframedoc = iframe.contentDocument || iframe.contentWindow.document,
tag = iframedoc.createElement(tagName),
selection = rangy.getIframeSelection(iframe),
selectionRange = selection.getRangeAt(0);
//let the caller do something with the element
withNodeFunc(tag);
//since you can't wrap something with an image tag
if (tagName === 'img') {
selectionRange.collapse(false);
selectionRange.insertNode(tag);
} else if (tagName === "a" && selection.isCollapsed) {
//provide some default text for an anchor
selectionRange.collapse(false);
tag.appendChild(iframedoc.createTextNode('link'));
selectionRange.insertNode(tag);
} else {
selectionRange.surroundContents(tag);
}
//detach rangy
selection.detach();
}
/**
* Example on how to call the function, let's say on a jquery document.ready
* It'll wrap the selection in a span
*/
$(function(){
//first, lets get the iframe that the ckeditor is in
var iframe=$(".ckeditor iframe");
//we put the [0] on the end of the jquery item, since that will cast it to a DOM element (see http://stackoverflow.com/questions/6974582/jquery-object-and-dom-element)
// and, we'll pass an empty callback, since we don't want to do anything with the span after its created
wrapOrInsert(iframe[0],"span",function(){});
});

6 comments:

  1. Hi Smith,

    I am facing the same problem. Need to wrap a span around selected text in CKEditor. Need some information about the function you wrote. If I am trying my own plugin then what should be the value of iframe here in the function parameter. and in withNodeFunc we need to create an element... do we need to return anything from the function

    ReplyDelete
  2. I've updated the code-- feel free to take a look

    ReplyDelete
  3. hi there, I am using the ckeditor in drupal, and I don't think it uses iframes, is this possible?

    ReplyDelete
  4. If you're using the version of CKEDITOR that is at Drupal.ckeditor.com, then no. From what i can tell, that is an html textarea on steriods. This code is for CKEDITOR >= 3.5, the "iframe on steroids" version.

    In other words, if you inspect the HTML of your editor and don't see an iframe, this code will not work.

    Thanks for asking!

    ReplyDelete
  5. that is great
    i also faced same issue and on this i have got solution.

    thanks Micah Smith
    Facebook Game Development

    ReplyDelete
  6. Is this code still valid? I'm gettin' some errors while using it (i.e. null iframedoc).

    ReplyDelete