contenteditableBackspace

by Seth Van Booven

HTML

<div id="editr" contentEditable="true">
This text is editable. 
<a href="#" contentEditable="false">This is not.</a>
This text is also editable.
</div>

CSS

body { font:1rem/1.5 sans-serif;  margin:2rem; }
div {
    border:thin solid #ddd;
    padding:1rem;
    margin:1rem 0;
    color:black;
    font-size:1rem;
}

JavaScript

var elm = document.querySelector('#editr');
elm.addEventListener('keydown', function(e) {
    if (window.getSelection && event.which === 8) { // backspace
        // fix backspace bug in FF
        // https://bugzilla.mozilla.org/show_bug.cgi?id=685445
        var selection = window.getSelection();
        if (!selection.isCollapsed || !selection.rangeCount) {
            return;
        }

        var curRange = selection.getRangeAt(selection.rangeCount - 1);
        if (curRange.commonAncestorContainer.nodeType === 3 && curRange.startOffset > 0) {
            // we are in child selection. The characters of the text node is being deleted
            return;
        }

        var range = document.createRange();
        if (selection.anchorNode !== this) {
            // selection is in character mode. expand it to the whole editable field
            range.selectNodeContents(this);
            range.setEndBefore(selection.anchorNode);
        } else if (selection.anchorOffset > 0) {
            range.setEnd(this, selection.anchorOffset);
        } else {
            // reached the beginning of editable field
            return;
        }
        range.setStart(this, range.endOffset - 1);

        var previousNode = range.cloneContents().lastChild;
        if (previousNode && previousNode.contentEditable === 'false') {
            // this is some rich content, e.g. smile. We should help the user to delete it
            range.deleteContents();
            event.preventDefault();
        }
    }
}, false);