Empêcher l'ajout de contenu modifiable <div> sur ENTER - Chrome


131

J'ai un contenteditableélément, et chaque fois que je tape des trucs et frappe, ENTERcela crée un nouveau<div> texte et y place le nouveau texte de ligne. Je n'aime pas ça du tout.

Est-il possible d'empêcher cela ou du moins de le remplacer par un <br>?

Voici la démo http://jsfiddle.net/jDvau/

Remarque: ce n'est pas un problème dans Firefox.


1
Firefox ajoute <br>, chrome - non, mais après avoir corrigé vos styles, les div supplémentaires ne cassent pas le rembourrage gauche. La question est pourquoi vous ne l'aimez pas? Pensez que c'est br ... jsfiddle.net/jDvau/1 Vous pouvez également utiliser l'événement DOMSubtreeModified pour capturer ces divs et les supprimer.
ViliusL

stackoverflow.com/questions/6024594/ ... cela pourrait vous aider, bonne chance!
Sirikon

1
Pour moi, la solution de Blake Plumb est la plus simple et de loin la meilleure ici.
svassr

1
@svassr ce n'est pas le but, ce n'est pas toi ou moi qui allons l'utiliser, c'est un client qui peut même ne pas savoir ce qu'est le changement.
iConnor du

2
En effet, cela change tout. Cela dit, c'est un comportement courant et un petit message d'aide ne serait pas armé. "Donnez un poisson à un homme et vous le nourrissez pendant un jour. Apprenez à un homme à pêcher et vous le nourrissez pour toute une vie."
svassr

Réponses:


161

Essaye ça:

$('div[contenteditable]').keydown(function(e) {
    // trap the return key being pressed
    if (e.keyCode === 13) {
        // insert 2 br tags (if only one br tag is inserted the cursor won't go to the next line)
        document.execCommand('insertHTML', false, '<br/>');
        // prevent the default behaviour of return key pressed
        return false;
    }
});

Cliquez ici pour une démo


Mais je trouve une petite différence ici. Placez votre curseur juste sur la ligne vide (en haut de "Tapez des trucs") et appuyez sur Entrée. Le curseur est maintenant juste avant le "Type", pas sur la nouvelle ligne vide.
Andrew

3
Cela ne fonctionne pas dans IE11 car il ne prend pas en charge insertHTML. Voir la réponse ci-dessous!
webprogrammer le

4
Si vous placez votre curseur entre les caractères, par exemple. «Ty [cursor] pe some stuff» et appuyez sur Entrée, vous obtenez 1 ligne de trop.
Chandrew

13
La réponse n'est pas acceptable. La solution serait de n'avoir qu'un seul <br />
raoulinski

3
ce retour à la fois <br> et <div>
Nishad Up

51

Vous pouvez le faire avec juste un changement CSS:

div{
    background: skyblue;
    padding:10px;
    display: inline-block;
}

pre{
    white-space: pre-wrap;
    background: #EEE;
}

http://jsfiddle.net/ayiem999/HW43Q/


1
Il y avait un problème lorsque j'ai utilisé inline-block, exécutez execCommand ("insertHTML", xxx) pour insérer quoi que ce soit, un "<br>" sera ajouté à la fin de l'élément inséré, testé dans Chrome33.
Imskull

5
Belle trouvaille. Malheureusement, cela ne fonctionnera pas sur la position: éléments absolus ou éléments qui sont les enfants directs d'un parent avec display: flex. Vous pouvez le pirater pour qu'il fonctionne en gardant cela à l'esprit. Assurez-vous simplement que ce n'est pas un enfant direct des éléments flex. Si vous en avez besoin position: absolu, donnez-lui simplement un parent supplémentaire avec ça.
Sceptique

@ReinoutvanKempen A commencé à utiliser flex il y a 3 mois déjà. Je suppose que ce hack ne fonctionnera pas
kittu

c'est une solution vraiment vraiment meilleure, elle est extrêmement propre et claire, rien ne sera inséré, même inclure br. et surtout cette solution sans js.
défendre l'orque

2
Wow ... cela résout Chrome, mais fait que Firefox commence à ajouter des divs lors de l'entrée, ce qu'il ne fait pas par défaut.
cbdeveloper

40

Ajoutez du style display:inline-block;à contenteditable, il ne sera pas généré div, pet spanautomatiquement dans Chrome.


6
C'est une excellente solution. *[contenteditable="true"]{display: inline-block;}
ericjbasti

J'adore, simple mais efficace
user25794

Dans IE11, cela fera un extra <p></p> :(
Betty St

1
mais cela créera un autre bogue Chrome très ennuyeux (quel navigateur de merde)
vsync

4
Ne fonctionne plus avec Chrome Version 63.0.3239.84
Mikaël Mayer

21

Essaye ça:

$('div[contenteditable="true"]').keypress(function(event) {

    if (event.which != 13)
        return true;

    var docFragment = document.createDocumentFragment();

    //add a new line
    var newEle = document.createTextNode('\n');
    docFragment.appendChild(newEle);

    //add the br, or p, or something else
    newEle = document.createElement('br');
    docFragment.appendChild(newEle);

    //make the br replace selection
    var range = window.getSelection().getRangeAt(0);
    range.deleteContents();
    range.insertNode(docFragment);

    //create a new range
    range = document.createRange();
    range.setStartAfter(newEle);
    range.collapse(true);

    //make the cursor there
    var sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);

    return false;
});

http://jsfiddle.net/rooseve/jDvau/3/


Bon, ça marche :) J'attendrai plus d'attention avant de me décider, merci.
iConnor

ne fonctionne pas correctement sur Firefox. il ajoute une ligne supplémentaire.
agpt

Cela permet d' inputéviter que le ne se déclenche lorsque vous appuyez sur Entrée. Une solution simple: ajouter qc comme$(this).trigger('input')
LarsW

La insertHTMLsolution fait des choses étranges quand il y a des contenteditableéléments imbriqués , votre solution contourne cela mais il y a d'autres problèmes, je l'ai ajouté comme nouvelle solution possible.
skerit

Ne fonctionne pas sur Chrome. La première fois que vous appuyez sur Entrée à la fin de la chaîne, cela ajoute un espace. La deuxième fois, cela fonctionne cependant.

20
document.execCommand('defaultParagraphSeparator', false, 'p');

Il remplace le comportement par défaut pour avoir un paragraphe à la place.

Sur Chrome, le comportement par défaut lors de l'entrée est:

<div>
    <br>
</div>

Avec cette commande, ça va être

<p>
    <br>
</p>

Maintenant qu'il est plus linéaire à travers, il est facile de l'avoir seulement <br>si vous en avez besoin.


Lorsque vous appuyez sur Entrée, au lieu d'avoir div et br, vous aurez p et br dans le navigateur. Essayez-le.
Ced

Merci! Les explications sont toujours utiles
jpaugh

@jpaugh np, j'ai modifié ma réponse pour qu'elle explique mieux.
Ced

cela ne fonctionne pas sur Firefox (j'ai testé dans Chrome et Firefox uniquement)
medBouzid

FireFox a été corrigé pour respecter désormais defaultParagraphSeparator. À mon humble avis, cette réponse est la meilleure car elle rend tous les navigateurs désormais cohérents et conformes aux spécifications. Si vous ne voulez pas qu'une balise P ait un «espacement» de marge par rapport au bloc de texte précédent dans le contenu modifiable, vous pouvez utiliser css pour le modifier.
blackmamba

9

Utilisez shift+ enterau lieu de enterpour insérer une seule <br>balise ou envelopper votre texte de <p>balises.


9
+1 Merci, c'est très pratique à savoir, mais si vous avez un client qui écrit un livre, ce sera une douleur dans la ***
iConnor

1
Cela n'aide pas si vous collez du contenu
vsync

5

La façon dont contenteditablese comporte lorsque vous appuyez entersur dépend des navigateurs, <div>cela se produit sur Webkit (chrome, safari) et IE.

J'ai eu du mal avec cela il y a quelques mois et je l'ai corrigé de cette façon:

//I recommand you trigger this in case of focus on your contenteditable
if( navigator.userAgent.indexOf("msie") > 0 || navigator.userAgent.indexOf("webkit") > 0 ) {
    //Add <br> to the end of the field for chrome and safari to allow further insertion
    if(navigator.userAgent.indexOf("webkit") > 0)
    {
        if ( !this.lastChild || this.lastChild.nodeName.toLowerCase() != "br" ) {
            $(this).html( $(this).html()+'<br />' );
        }
    }

    $(this).keypress( function(e) {
        if( ( e.keyCode || e.witch ) == 13 ) {
            e.preventDefault();

            if( navigator.userAgent.indexOf("msie") > 0 ) {
                insertHtml('<br />');
            }
            else {
              var selection = window.getSelection(),
              range = selection.getRangeAt(0),
              br = document.createElement('br');

              range.deleteContents();
              range.insertNode(br);
              range.setStartAfter(br);
              range.setEndAfter(br);
              range.collapse(false);

              selection.removeAllRanges();
              selection.addRange(range);
            }
        }
    });
}

J'espère que cela aidera et désolé pour mon anglais s'il n'est pas aussi clair que nécessaire.

EDIT : Correction de la fonction jQuery suppriméejQuery.browser


Juste pour vous faire savoir, jQuery.browserne fait plus partie de jQuery.
iConnor

Vous avez raison, je devrais le mentionner et utiliser quelque chose comme navigator.userAgent.indexOf("msie") > 0etnavigator.userAgent.indexOf("webkit") > 0
Elie

1
if( ( e.keyCode || e.witch ) == 13 ) { ... }doit êtreif (e.keyCode === 13 || e.which === 13) { ... }
Sebastian Sandqvist

5

Vous pouvez avoir des <p>balises distinctes pour chaque ligne plutôt que d'utiliser des <br>balises et obtenir une meilleure compatibilité avec le navigateur dès le départ.

Pour ce faire, placez une <p>balise avec du texte par défaut à l'intérieur de la div contenteditable.

Par exemple, au lieu de:

<div contenteditable></div>

Utilisation:

<div contenteditable>
   <p>Replace this text with something awesome!</p>
</div>

jsfiddle

Testé dans Chrome, Firefox et Edge, et le second fonctionne de la même manière dans chacun.

Le premier, cependant, crée des divs dans Chrome, crée des sauts de ligne dans Firefox, et dans Edge crée des divs et le curseur est remis au début du div actuel au lieu de passer au suivant.

Testé dans Chrome, Firefox et Edge.


ce n'est en fait pas une mauvaise solution
AaronHS

5

J'aime utiliser Mousetrap pour gérer les raccourcis clavier: https://craig.is/killing/mice

Ensuite, je viens d'intercepter l'événement enter, en exécutant une commande insertLineBreak :

Mousetrap.bindGlobal('enter', (e)=>{
  window.document.execCommand('insertLineBreak', false, null);
  e.preventDefault();
});

Toutes les commandes: https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand

Il fonctionne avec Chrome 75 et l'élément modifiable suivant:

<pre contenteditable="true"></pre>

Il est également possible d'utiliser insertHTML :

window.document.execCommand('insertHTML', false, "\n");

4

ajouter une valeur par défaut au div

document.body.div.onkeydown = function(e) {
    if ( e.keycode == 13 ){
        e.preventDefault();
            //add a <br>
        div = document.getElementById("myDiv");
        div.innerHTML += "<br>";
    }
}

@connorspiracist désolé c'est document.body.div(vous aurez probablement besoin de mettre un autre code pour pointer pour corriger c'est divjuste l'idée générale)
Math chiller

4

J'utiliserais le style (Css) pour résoudre le problème.

div[contenteditable=true] > div {
  padding: 0;
} 

Firefox ajoute en effet une rupture d'élément de bloc
, alors que Chrome enveloppe chaque section dans une balise. Votre css donne aux div un remplissage de 10px avec la couleur d'arrière-plan.

div{
  background: skyblue;
  padding:10px;
}

Vous pouvez également répliquer le même effet souhaité dans jQuery:

var style = $('<style>p[contenteditable=true] > div { padding: 0;}</style>');
$('html > head').append(style);

Voici une fourchette de votre violon http://jsfiddle.net/R4Jdz/7/


1
Cela peut aider certaines personnes, mais j'étais plus préoccupé par le balisage inutile, car je prendrais le code HTML final du contenteditableet l'utiliser ailleurs
iConnor

3

Vous pouvez envelopper vos paragraphes avec une <p>balise par exemple, elle apparaîtrait sur une nouvelle ligne au lieu de div Exemple:
<div contenteditable="true"><p>Line</p></div>
Après avoir inséré une nouvelle chaîne:
<div contenteditable="true"><p>Line</p><p>New Line</p></div>


3

La inserHTMLsolution de commande fait des choses étranges lorsque vous avez des contenteditableéléments imbriqués .

J'ai pris quelques idées de plusieurs réponses ici, et cela semble répondre à mes besoins pour le moment:

element.addEventListener('keydown', function onKeyDown(e) {

    // Only listen for plain returns, without any modifier keys
    if (e.which != 13 || e.shiftKey || e.ctrlKey || e.altKey) {
        return;
    }

    let doc_fragment = document.createDocumentFragment();

    // Create a new break element
    let new_ele = document.createElement('br');
    doc_fragment.appendChild(new_ele);

    // Get the current selection, and make sure the content is removed (if any)
    let range = window.getSelection().getRangeAt(0);
    range.deleteContents();

    // See if the selection container has any next siblings
    // If not: add another break, otherwise the cursor won't move
    if (!hasNextSibling(range.endContainer)) {
        let extra_break = document.createElement('br');
        doc_fragment.appendChild(extra_break);
    }

    range.insertNode(doc_fragment);

    //create a new range
    range = document.createRange();
    range.setStartAfter(new_ele);
    range.collapse(true);

    //make the cursor there
    let sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);

    e.stopPropagation();
    e.preventDefault();

    return false;
});

// See if the given node has a next sibling.
// Either any element or a non-empty node
function hasNextSibling(node) {

    if (node.nextElementSibling) {
        return true;
    }

    while (node.nextSibling) {
        node = node.nextSibling;

        if (node.length > 0) {
            return true;
        }
    }

    return false;
}


2

Nous devons d'abord capturer chaque entrée d'utilisateur clé pour voir si Entrée est enfoncée, puis nous empêchons la <div>création et nous créons la nôtre<br> balise.

Il y a un problème, lorsque nous le créons, notre curseur reste à la même position, nous utilisons l' API de sélection pour placer notre curseur à la fin.

N'oubliez pas d'ajouter une <br>balise à la fin de votre texte car si vous ne le faites pas, la première entrée ne fera pas de nouvelle ligne.

$('div[contenteditable]').on('keydown', function(e) {
    var key = e.keyCode,
        el  = $(this)[0];
    // If Enter    
    if (key === 13) {
        e.preventDefault(); // Prevent the <div /> creation.
        $(this).append('<br>'); // Add the <br at the end

        // Place selection at the end 
        // http://stackoverflow.com/questions/4233265/contenteditable-set-caret-at-the-end-of-the-text-cross-browser
        if (typeof window.getSelection != "undefined"
            && typeof document.createRange != "undefined") {
            var range = document.createRange();
            range.selectNodeContents(el);
            range.collapse(false);
            var sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        } else if (typeof document.body.createTextRange != "undefined") {
            var textRange = document.body.createTextRange();
            textRange.moveToElementText(el);
            textRange.collapse(false);
            textRange.select();
        }
    }
});

Violon


2

Il s'agit d'un éditeur HTML5 dirigé par un navigateur. Vous pouvez envelopper votre texte avec <p>...</p>, puis chaque fois que vous appuyez sur ENTRÉE, vous obtenez <p></p>. En outre, l'éditeur fonctionne de cette façon que chaque fois que vous appuyez sur MAJ + ENTRÉE, il insère <br />.

<div contenteditable="true"><p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor veniam asperiores laudantium repudiandae doloremque sed perferendis obcaecati delectus autem perspiciatis aut excepturi et nesciunt error ad incidunt impedit quia dolores rerum animi provident dolore corporis libero sunt enim. Ad magnam omnis quidem qui voluptas ut minima similique obcaecati doloremque atque!
<br /><br />
Type some stuff, hit ENTER a few times, then press the button.
</p>
</div>

Vérifiez ceci: http://jsfiddle.net/ZQztJ/


2

Cela fonctionne dans tous les principaux navigateurs (Chrome, Firefox, Safari, Edge)

document.addEventListener('keydown', event => {
  if (event.key === 'Enter') {
    document.execCommand('insertLineBreak')
    event.preventDefault()
  }
})
<div class="element" contenteditable="true">Sample text</div>
<p class="element" contenteditable="true">Sample text</p>

Il y a un inconvénient. Une fois l'édition terminée, les éléments peuvent contenir une fin à l' <br>intérieur. Mais vous pouvez ajouter du code pour réduire cela si vous en avez besoin.

Cochez cette réponse pour supprimer le https://stackoverflow.com/a/61237737/670839 de fin<br>


Que diable? Comment la seule solution qui a réellement fonctionné pour moi peut-elle être aussi loin dans la page? Merci beaucoup.
user12861

1
if (navigator.userAgent.toLowerCase().indexOf('msie') > -1) {
   var range = document.getSelection();
   range.pasteHTML(range.htmlText + '<br><br>');
}
else if(navigator.userAgent.toLocaleLowerCase().indexOf('trident') > -1)                           {
   var range = document.getSelection().getRangeAt(0); //get caret
   var nnode = document.createElement('br');
   var bnode = document.createTextNode('\u00A0'); //&nbsp;
   range.insertNode(nnode);
   this.appendChild(bnode);
   range.insertNode(nnode);                                
}
else
   document.execCommand('insertHTML', false, '<br><br>')

thisest le contexte réel qui signifie document.getElementById('test');.


0

Une autre façon de le faire

$('button').click(function(){
    $('pre').text($('div')[0].outerHTML)
});

$("#content-edit").keydown(function(e) {
    if(e.which == 13) {
       $(this).find("div").prepend('<br />').contents().unwrap();
      }
});

http://jsfiddle.net/jDvau/11/


Il ne laisse pas le curseur avancer pendant que vous tapez.
Jack Lu

C'est étrange, je viens d'essayer dans Chrome et IE 11 et cela fonctionne bien. Référence Pourriez-vous me dire quel navigateur vous utilisez? Plus de détails sur le comportement seraient utiles pour résoudre le problème
MrAJ

0

Empêcher la création de nouvelles Div dans le contenu éditable Div sur chaque touche d'entrée: La solution que j'ai trouvée est très simple:

var newdiv = document.createElement("div"); 
newdiv.innerHTML = "Your content of div goes here";
myEditablediv.appendChild(newdiv);

Ce contenu --- innerHTML empêche la création d'une nouvelle division dans un contenu div modifiable à chaque touche d'entrée.


0

Le brouillon de l'éditeur W3C contient des informations sur l'ajout d'états dans ContentEditable et vous pouvez utiliser pour empêcher le navigateur d'ajouter un nouvel élément lorsque vous appuyez sur Entrée plaintext-only.

<div contentEditable="plaintext-only"></div>

-1

Il est possible d'empêcher complètement ce comportement.

Voir ce violon

$('<div class="temp-contenteditable-el" contenteditable="true"></div>').appendTo('body').focus().remove();
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.