76 votes

Insérer du html au niveau du caret dans une div contenteditable

J'ai une div avec contenteditable et je capture la pression des touches en utilisant jquery pour appeler preventDefault() quand la touche entrée est pressée. Similaire à cette question qui insère du texte au niveau du curseur, j'aimerais insérer directement du html, par souci de concision, nous dirons qu'il s'agit d'une balise br. L'utilisation de la réponse à la question ci-dessus fonctionne dans IE car elle utilise la méthode range.pasteHTML, mais dans les autres navigateurs, la balise br apparaîtrait comme du texte brut et non comme du html. Comment puis-je modifier la réponse pour insérer du html et non du texte ?

190voto

Tim Down Points 124501

Dans la plupart des navigateurs, vous pouvez utiliser la fonction insertNode() de la plage obtenue à partir de la sélection. Dans IE < 9, vous pouvez utiliser pasteHTML() comme vous l'avez mentionné. Vous trouverez ci-dessous une fonction permettant d'effectuer cette opération dans tous les principaux navigateurs. Si le contenu est déjà sélectionné, il est remplacé, de sorte qu'il s'agit en fait d'une opération de collage. J'ai également ajouté du code pour placer le caret après la fin du contenu inséré.

jsFiddle : http://jsfiddle.net/jwvha/1/

Code :

function pasteHtmlAtCaret(html) {
    var sel, range;
    if (window.getSelection) {
        // IE9 and non-IE
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            range = sel.getRangeAt(0);
            range.deleteContents();

            // Range.createContextualFragment() would be useful here but is
            // only relatively recently standardized and is not supported in
            // some browsers (IE9, for one)
            var el = document.createElement("div");
            el.innerHTML = html;
            var frag = document.createDocumentFragment(), node, lastNode;
            while ( (node = el.firstChild) ) {
                lastNode = frag.appendChild(node);
            }
            range.insertNode(frag);

            // Preserve the selection
            if (lastNode) {
                range = range.cloneRange();
                range.setStartAfter(lastNode);
                range.collapse(true);
                sel.removeAllRanges();
                sel.addRange(range);
            }
        }
    } else if (document.selection && document.selection.type != "Control") {
        // IE < 9
        document.selection.createRange().pasteHTML(html);
    }
}

MISE À JOUR 21 AOÛT 2013

Comme demandé dans les commentaires, voici un exemple mis à jour avec un paramètre supplémentaire qui spécifie si le contenu inséré doit être sélectionné ou non.

Démonstration : http://jsfiddle.net/timdown/jwvha/527/

Code :

function pasteHtmlAtCaret(html, selectPastedContent) {
    var sel, range;
    if (window.getSelection) {
        // IE9 and non-IE
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            range = sel.getRangeAt(0);
            range.deleteContents();

            // Range.createContextualFragment() would be useful here but is
            // only relatively recently standardized and is not supported in
            // some browsers (IE9, for one)
            var el = document.createElement("div");
            el.innerHTML = html;
            var frag = document.createDocumentFragment(), node, lastNode;
            while ( (node = el.firstChild) ) {
                lastNode = frag.appendChild(node);
            }
            var firstNode = frag.firstChild;
            range.insertNode(frag);

            // Preserve the selection
            if (lastNode) {
                range = range.cloneRange();
                range.setStartAfter(lastNode);
                if (selectPastedContent) {
                    range.setStartBefore(firstNode);
                } else {
                    range.collapse(true);
                }
                sel.removeAllRanges();
                sel.addRange(range);
            }
        }
    } else if ( (sel = document.selection) && sel.type != "Control") {
        // IE < 9
        var originalRange = sel.createRange();
        originalRange.collapse(true);
        sel.createRange().pasteHTML(html);
        if (selectPastedContent) {
            range = sel.createRange();
            range.setEndPoint("StartToStart", originalRange);
            range.select();
        }
    }
}

0 votes

@Tim Je me demandais juste, puisque je ne voudrais pas que les utilisateurs ajoutent du html partout (puisque la fonction est un bouton), comment est-il possible de faire fonctionner cela uniquement dans une certaine div ou un certain élément ?

1 votes

@think123 : Vous pourriez utiliser une fonction comme la suivante pour vérifier que la sélection est contenue dans un nœud particulier : stackoverflow.com/a/8340432/96100

0 votes

@TimDown est-il compatible avec jQuery ? (le isOrContains fonction)

14voto

user3126867 Points 51
var doc = document.getElementById("your_iframe").contentWindow.document;

// IE <= 10
if (document.selection){
    var range = doc.selection.createRange();
        range.pasteHTML("<b>Some bold text</b>");

// IE 11 && Firefox, Opera .....
}else if(document.getSelection){
    var range = doc.getSelection().getRangeAt(0);
    var nnode = doc.createElement("b");
    range.surroundContents(nnode);
    nnode.innerHTML = "Some bold text";
};

1voto

delaio Points 21

En lisant rapidement et en espérant ne pas être hors sujet, voici une piste pour ceux qui, comme moi, ont besoin d'insérer du code au niveau du curseur d'une div :

document.getElementById('editeur').contentWindow.document.execCommand('insertHTML', false, '<br />');

'editeur' est une iframe :

<iframe id="editeur" src="contenu_editeur_wysiwyg.php">
</iframe>

contenu_editeur_wysiwyg.php :

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<div>
</div>
</body>
</html>

n'oubliez pas :

document.getElementById('editeur').contentDocument.designMode = "on";

-1voto

Alex G Points 67
var r = getSelection().getRangeAt(0);
r.insertNode(r.createContextualFragment('<b>Hello</b>'));

//select this range
getSelection().removeAllRanges();
getSelection().addRange(r);
//collapse to end/start 
getSelection().collapseToEnd()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X