How to delete an HTML element inside a div with attribute contentEditable?
Asked Answered
P

2

7

have this html:

<div id="editable" contentEditable="true"  >
    <span contentEditable="false" >Text to delete</span>
</div>

need that the span (and all text inside) is removed with a single backspace, is it possible?

Pomiferous answered 1/2, 2010 at 15:52 Comment(1)
Please could you provide more information about what should happen when the user presses backspace when, for example, the caret is in the middle of a text node, or at the start of the editable area.Impolite
I
12

This turned out to be more complicated than I thought. Or I've made it more complicated than it needs to be. Anyway, this should work in all the big browsers:

function getLastTextNodeIn(node) {
    while (node) {
        if (node.nodeType == 3) {
            return node;
        } else {
            node = node.lastChild;
        }
    }
}

function isRangeAfterNode(range, node) {
    var nodeRange, lastTextNode;
    if (range.compareBoundaryPoints) {
        nodeRange = document.createRange();
        lastTextNode = getLastTextNodeIn(node);
        nodeRange.selectNodeContents(lastTextNode);
        nodeRange.collapse(false);
        return range.compareBoundaryPoints(range.START_TO_END, nodeRange) > -1;
    } else if (range.compareEndPoints) {
        if (node.nodeType == 1) {
            nodeRange = document.body.createTextRange();
            nodeRange.moveToElementText(node);
            nodeRange.collapse(false);
            return range.compareEndPoints("StartToEnd", nodeRange) > -1;
        } else {
            return false;
        }
    }
}

document.getElementById("editable").onkeydown = function(evt) {
    var sel, range, node, nodeToDelete, nextNode, nodeRange;
    evt = evt || window.event;
    if (evt.keyCode == 8) {
        // Get the DOM node containing the start of the selection
        if (window.getSelection && window.getSelection().getRangeAt) {
            range = window.getSelection().getRangeAt(0);
        } else if (document.selection && document.selection.createRange) {
            range = document.selection.createRange();
        }

        if (range) {
            node = this.lastChild;
            while (node) {
                if ( isRangeAfterNode(range, node) ) {
                    nodeToDelete = node;
                    break;
                } else {
                    node = node.previousSibling;
                }
            }

            if (nodeToDelete) {
                this.removeChild(nodeToDelete);
            }
        }
        return false;
    }
};
Impolite answered 1/2, 2010 at 16:16 Comment(4)
no, i need to remove only the element at the left of text cursor |Pomiferous
how can i make this code more dynamic by add span usnig Enter KeyDown Press and remove the span using backspace help me if you can.Liger
this works in crome but not in firefox. Is there any node related issue in firefox browser. I need help , please see attached link .Tympany
Dhananjay C: it works fine without the errors in your code - jsfiddle.net/dpx4f9hmDromond
C
11

Because you want to delete the whole element, it's better to make it contenteditable="false" so that browser won't let the contents of an element to be deleted.

Then you can use this attribute for tests in event handler as follows:

$('#editable').on('keydown', function (event) {
    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();
        }
    }
});

demo on jsfiddle

Colorful answered 1/6, 2015 at 13:19 Comment(4)
Exactly fixed my problemTangency
wow... what a alarming simple solution! setting the contenteditable to false of the div I wanted to delete let me delete the div in one go!Mariande
Great answer! Many thanks! One question though. What do you mean by "selection is in character mode."? I also cannot seem to trigger that event. /KFernandefernandel
I managed to trigger the section "selection is in character mode" by deleting a line break. /KFernandefernandel

© 2022 - 2024 — McMap. All rights reserved.