74 votes

Traitement des sauts de ligne sur les DIV modifiables par le contenu

J'ai un problème avec contenteditable les sauts de ligne sur SAFARI/CHROME. Lorsque j'appuie sur "return" sur un contentEditable <div> au lieu de créer un <br> (comme Firefox), ils créent un nouveau <div> :

<div>Something</div>
<div>Something</div>

Cela ressemble à (sur le DIV contentEditable) :

Something
Something

Mais après la désinfection (élimination <div> ), j'obtiens ceci :

SomethingSomething

Dans Firefox, le contenteditable est :

Something
<br>
Something

Et qui, après désinfection, se ressemble :

Something
Something

Existe-t-il une solution pour "normaliser" cette situation entre les navigateurs ?

J'ai trouvé ce code sur Faire un <br>au lieu de <div></div> en appuyant sur Entrée sur un contenteditable

$(function(){

  $("#editable")

  // make sure br is always the lastChild of contenteditable
  .live("keyup mouseup", function(){
    if (!this.lastChild || this.lastChild.nodeName.toLowerCase() != "br") {
      this.appendChild(document.createChild("br"));
     }
  })

  // use br instead of div div
  .live("keypress", function(e){
    if (e.which == 13) {
      if (window.getSelection) {
        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);
        return false;
      }
    }
  });
});

Cela fonctionne, mais (en SAFARI et CHROME) Je dois appuyer deux fois sur la touche "retour" pour obtenir une nouvelle ligne...

Une idée ?

Modifier : Avec le code que j'ai trouvé ( au bas de cette question), tout fonctionne bien, sauf la fonction qui "s'assure qu'un <br> est toujours le dernier enfant... Une idée sur la façon de résoudre ce problème ?

Edit 2 : J'obtiens cette erreur sur la console : Uncaught TypeError: Object #<HTMLDocument> has no method 'createChild'

Edit 3 : Ok, j'ai changé le document.createChild("br"); à document.createElement("br"); et je pense l'avoir fait fonctionner dans FF/Safari/Chrome... Tout retour <br> pour les nouvelles lignes...

Le problème est que maintenant, lorsque je suis à l'intérieur d'une liste ordonnée ou non ordonnée, je dois obtenir une nouvelle ligne sans <br> ...

Edit 4 : Si quelqu'un est intéressé par la solution de la dernière modification : Éviter la fonction createElement si elle se trouve à l'intérieur d'un élément <LI> (contentEditable)

0 votes

À quoi ressemble votre méthode de désinfection ?

0 votes

@mdmullinax Il supprime simplement toutes les <div>... J'utilise github.com/gbirke/Sanitize.js Le problème est que Safari/Chrome, lorsque j'appuie sur retour, ils créent simplement un nouveau DIV au lieu de faire un <BR> comme Firefox.

1 votes

Vous pouvez peut-être utiliser $("div:empty").replaceWith("<br/>") ;

32voto

Myka Eyl Points 485

Cette technique semble éviter le bug de Chrome qui fait apparaître les RE la première fois (avec le code que vous avez mentionné, il faut appuyer deux fois sur la touche Entrée).

Ce n'est pas un hack parfait mais il fonctionne : il ajoute un espace après votre BR pour qu'il s'affiche correctement. Cependant, vous verrez que l'ajout d'un simple espace " " ne changera rien, il fonctionne avec d'autres lettres. Le navigateur ne l'affichera pas, probablement parce que c'est comme un espace vide dans une page html, il ne signifie simplement rien. Pour se débarrasser de ce bug, j'ai créé un div avec jQuery qui inclut un espace blanc " ". &nbsp; et je prends le text() pour le mettre dans le textnode sinon cela ne fonctionne pas.

$editables = $('[contenteditable=true]');

$editables.filter("p,span").on('keypress',function(e){
 if(e.keyCode==13){ //enter && shift

  e.preventDefault(); //Prevent default browser behavior
  if (window.getSelection) {
      var selection = window.getSelection(),
          range = selection.getRangeAt(0),
          br = document.createElement("br"),
          textNode = document.createTextNode("\u00a0"); //Passing " " directly will not end up being shown correctly
      range.deleteContents();//required or not?
      range.insertNode(br);
      range.collapse(false);
      range.insertNode(textNode);
      range.selectNodeContents(textNode);

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

   }
});

1 votes

Ajoutez range.deleteContents() ; avant selection.removeAllRanges();pour vous débarrasser de ces satanés &nbsp ; tout en gardant tout le travail ^^.

1 votes

L'ajout de document.execCommand('delete') juste avant "return false" fait l'affaire et ne montre pas la sélection des espaces blancs.

16voto

Prowla Points 1132

Écouter les frappes au clavier semble être un travail considérable. Est-ce que quelque chose d'aussi simple que ça serait faisable ?

var html = $('.content').html().replace(/<div>/gi,'<br>').replace(/<\/div>/gi,'');

Démonstration de JSFiddle ici .

Aussi, on dirait que sanitize.js permet une configuration personnalisée. Avez-vous essayé d'ajouter div comme un élément autorisé ?

Autoriser le HTML/CSS est dangereux, assurez-vous donc d'être très prudent.

EDIT : Suppression des commentaires côté serveur. La désinfection se fait au moment de l'utilisation - si le client veut contourner cette opération localement, il le fait à ses propres risques. Merci Vincent McNabb pour avoir souligné ce point.

3 votes

Il semble que l'assainissement soit effectué à des fins d'affichage et non de sécurité, auquel cas il est parfaitement raisonnable de le faire sur le client. Ils peuvent la contourner s'ils le souhaitent, et cela ne ferait qu'enlaidir les choses pour eux.

0 votes

Je pense que l'aseptisation est effectuée à des fins de sécurité au moment de l'utilisation (par exemple, suppression des jetons non sécurisés pour la sortie HTML). Vous faites remarquer que si le client veut contourner cette procédure localement, il le fait à ses propres risques.

3voto

Klim Lee Points 11

Les Webkits ne rendront pas un simple br s'il s'agit du dernier enfant (non vide) d'un conteneur. Pour Safari, la touche native permettant d'insérer un saut de ligne est Ctrl + Return. Si vous regardez attentivement, vous remarquerez que Safari insère en fait deux arrêts de ligne br tout en n'en rendant qu'une seule ; cependant, il insérera une seule br s'il y a du texte à la fin, ou se débarrasser des doublons. br une fois que vous en avez saisi (s'il y avait des doubles).

Apparemment, il semble qu'une solution pour les Webkits consiste à insérer des doubles br comme ils le font eux-mêmes, et laissez-les s'occuper du reste.

1voto

B T Points 4868

Vous pourriez vouloir vérifier le css white-space propriété. En définissant le style sur white-space: pre-wrap vous permet de vous débarrasser de tout ce javascript, car il modifie le comportement des espaces blancs pour les afficher au lieu de les réduire.

Et voyez cette réponse : HTML - Le caractère de nouvelle ligne dans le contenu d'un DIV peut être modifié ?

0 votes

Ce problème se produit toujours, quelle que soit la valeur de l'espace blanc, en rapport avec contentEditable.

0voto

user10 Points 2272

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