I have a <div />
which is contenteditable
and can contain several types of HTML elements such as <span />
, <a />
, <b />
, <u />
and so on.
Now when I select text in my contenteditable
I would like to have a button that removes all the styles within the selection.
Example 1:
The Selection:
Hello <b>there</b>. I am <u>a selection</u>
would become:
Hello there. I am a selection
Example 2:
The Selection:
<a href="#">I am a link</a>
would become:
I am a link
You get the idea...
I have found this helpful function https://stackoverflow.com/a/3997896/1503476 which replaces the current selection with custom text. But I just cannot get the content of the selection first and strip the tags out before replacing it. How can I do that?
The way I would do this is to iterate over the nodes within the selection and remove inline nodes (maybe leaving <br>
elements alone). Here's an example, using my Rangy library for convenience. It works in all major browsers (including IE 6) but is not quite perfect: for example, it does not split partially selected formatting elements, meaning that a partially selected formatting element is completely removed rather than just the selected portion. To fix this would be more tricky.
Demo: http://jsfiddle.net/fQCZT/4/
Code:
var getComputedDisplay = (typeof window.getComputedStyle != "undefined") ?
function(el) {
return window.getComputedStyle(el, null).display;
} :
function(el) {
return el.currentStyle.display;
};
function replaceWithOwnChildren(el) {
var parent = el.parentNode;
while (el.hasChildNodes()) {
parent.insertBefore(el.firstChild, el);
}
parent.removeChild(el);
}
function removeSelectionFormatting() {
var sel = rangy.getSelection();
if (!sel.isCollapsed) {
for (var i = 0, range; i < sel.rangeCount; ++i) {
range = sel.getRangeAt(i);
// Split partially selected nodes
range.splitBoundaries();
// Get formatting elements. For this example, we'll count any
// element with display: inline, except <br>s.
var formattingEls = range.getNodes([1], function(el) {
return el.tagName != "BR" && getComputedDisplay(el) == "inline";
});
// Remove the formatting elements
for (var i = 0, el; el = formattingEls[i++]; ) {
replaceWithOwnChildren(el);
}
}
}
}