Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

contenteditable div: IE8 not happy with backspace remove of HTML element

I am making use of a contenteditable div in combination with the rangy Javascript library to insert HTML at the cursor position.

End of the day the contents of the div commonly looks like:

<div contenteditable="true">
    "Hello "
    <button contenteditable="false" data-id="147">@John Smith</button>
    " "
</div>

Users get suggested upon pressing '@' and get subsequently inserted as a button when selected (ala Google Plus). I also insert a &nbsp; after this button.

The button gets removed in Chrome/Safari/Firefox when you hit backspace (after first removing the &nbsp;), but not in IE8. In IE8 the cursor merely jumps over the button without removing it. What's even more bizarre in IE8 is if you leave the &nbsp; next to the button - and rather place the cursor right next to the button - it removes the button on backspace. So it's happy when there's a &nbsp; to the right of the cursor.

Does anyone know what I need in order to make IE8 work i.t.o. removing the button upon backspace without the need for a &nbsp; to the right of the cursor? (some info on this strange behaviour might also help)

P.S. I haven't tested other versions of IE

like image 413
Markus Coetzee Avatar asked Apr 02 '12 21:04

Markus Coetzee


1 Answers

My suggestion would be to first check the caret is positioned after the non-editable node, and if so, create a range that starts immediately after the non-editable element and ends at the caret position. Check whether the text in this range is empty. If it is, that means the caret is placed directly after the non-editable element, so in that case remove the element. Finally, place the caret where the non-editable had been.

Live demo: http://jsfiddle.net/timdown/vu3ub/

Code:

document.onkeypress = function(e) {
    e = e || window.event;
    var keyCode = e.which || e.keyCode;
    if (keyCode !== 8) {
        return;
    }

    var sel = rangy.getSelection();
    if (sel.rangeCount === 0) {
        return;
    }

    var selRange = sel.getRangeAt(0);
    if (!selRange.collapsed) {
        return;
    }

    var nonEditable = document.getElementById("nonEditable");
    if (!nonEditable) {
        return;
    }

    // Check the caret is located after the non-editable element
    var range = rangy.createRange();
    range.collapseAfter(nonEditable);

    if (selRange.compareBoundaryPoints(range.START_TO_END, range) == -1) {
        return;
    }

    // Check whether there is any text between the caret and the
    // non-editable element. If not, delete the element and move
    // the caret to where it had been
    range.setEnd(selRange.startContainer, selRange.startOffset);
    if (range.toString() === "") {
        selRange.collapseBefore(nonEditable);
        nonEditable.parentNode.removeChild(nonEditable);
        sel.setSingleRange(selRange);

        // Prevent the default browser behaviour
        return false;
    }
};
like image 120
Tim Down Avatar answered Sep 30 '22 10:09

Tim Down