2016-02-29 38 views
17

Quando si preme Invio su un elemento contentEditable, ogni browser gestisce il codice risultante in modo diverso: Firefox inserisce un tag BR, Chrome inserisce un tag DIV Internet Explorer inserisce un tag P.Modo cross-browser per inserire il tag BR o P quando si preme Invio su un contenutoElemento modificabile

stavo disperatamente cercando una soluzione ad almeno usare un BR o P per tutti i browser e la risposta più comune è stata questa:

inserendo tag BR:

$("#editableElement").on("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); 
      selection.removeAllRanges(); 
      selection.addRange(range); 
      return false; 
     } 
     } 
    }); 

Ma questo non funziona perché sembra che i browser non sappiano come impostare il punto di inserimento dopo <br> il che significa che il seguente è che non sta facendo nulla di utile (specialmente se premi Invio quando il cursore è inserito Ed alla fine del testo):

range.setStartAfter(br); 
range.setEndAfter(br); 

Qualcuno direbbe: utilizzare il doppio <br><br> ma questo si traduce in due interruzioni di riga quando si colpisce entrare all'interno di un nodo di testo.

Altri direbbero sempre aggiungere un ulteriore <br> alla fine di contentEditable, ma se si dispone di un <div contenteditable><p>text here</p></div> e si posiziona il cursore alla fine del testo, quindi premere Invio, si otterrà il comportamento sbagliato.

così ho detto a me stesso forse possiamo usare P invece di BR, e la risposta comune è:

inserimento di tag P:

document.execCommand('formatBlock', false, 'p'); 

Ma questo non funziona in modo coerente o.

Come potete vedere, tutte queste soluzioni lasciano a desiderare. C'è un'altra soluzione che risolve questo problema?

+1

io ti senti ... sto affrontando lo stesso problema fastidioso :) – Swag

risposta

8

Una possibile soluzione: aggiungere un nodo di testo con un carattere zero-width space dopo l'elemento <br>. Questo è un non-stampa di carattere zero-width che è specificamente progettato per:

... indicano i confini di parola in testo elaborazione sistemi quando si utilizzano gli script che non utilizzano la spaziatura esplicita, o di personaggi (come il barra) che non sono seguiti da uno spazio visibile ma dopo il quale lo potrebbe tuttavia essere un'interruzione di riga.

(Wikipedia)

testato in Chrome 48, Firefox 43, e IE11.

$("#editableElement").on("keypress", function(e) { 
 
    //if the last character is a zero-width space, remove it 
 
    var contentEditableHTML = $("#editableElement").html(); 
 
    var lastCharCode = contentEditableHTML.charCodeAt(contentEditableHTML.length - 1); 
 
    if (lastCharCode == 8203) { 
 
    $("#editableElement").html(contentEditableHTML.slice(0, -1)); 
 
    } 
 
    // handle "Enter" keypress 
 
    if (e.which == 13) { 
 
    if (window.getSelection) { 
 
     var selection = window.getSelection(); 
 
     var range = selection.getRangeAt(0); 
 
     var br = document.createElement("br"); 
 
     var zwsp = document.createTextNode("\u200B"); 
 
     var textNodeParent = document.getSelection().anchorNode.parentNode; 
 
     var inSpan = textNodeParent.nodeName == "SPAN"; 
 
     var span = document.createElement("span"); 
 
     
 
     // if the carat is inside a <span>, move it out of the <span> tag 
 
     if (inSpan) { 
 
     range.setStartAfter(textNodeParent); 
 
     range.setEndAfter(textNodeParent); 
 
     } 
 

 
     // insert the <br> 
 
     range.deleteContents(); 
 
     range.insertNode(br); 
 
     range.setStartAfter(br); 
 
     range.setEndAfter(br); 
 
     
 
     // create a new span on the next line 
 
     if (inSpan) { 
 
     range.insertNode(span); 
 
     range.setStart(span, 0); 
 
     range.setEnd(span, 0); 
 
     } 
 

 
     // add a zero-width character 
 
     range.insertNode(zwsp); 
 
     range.setStartBefore(zwsp); 
 
     range.setEndBefore(zwsp); 
 
     
 
     // insert the new range 
 
     selection.removeAllRanges(); 
 
     selection.addRange(range); 
 
     return false; 
 
    } 
 
    } 
 
});
#editableElement { 
 
    height: 150px; 
 
    width: 500px; 
 
    border: 1px solid black; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div contenteditable=true id="editableElement"> 
 
    <span>sample text</span> 
 
</div>

+0

molto cool. Fino ad ora ho usato un approccio quasi identico, ma con uno spazio invece di uno ZWNJ. Questo ovviamente richiedeva un controllo che l'injected '
' fosse l'ultimo nodo non vuoto nel parent 'contenteditable', altrimenti gli spazi visibili erano lasciati dappertutto. Questo è molto meglio. –

+0

grazie per la risposta, C'è un modo per eliminare il precedente aggiunto ‌ in ogni tasto Invio? – medBo

+0

Certo, ma dovrai aspettare che un altro carattere venga inserito nel 'TextNode', altrimenti sei tornato dove hai iniziato (con il cursore posizionato rispetto a un' TextNode' vuoto). Ho inserito del codice all'inizio del gestore 'keypress' che controlla se l'ultimo carattere è un' zwsp' e lo rimuove. – rphv

1

Si può vedere un'implementazione cross browser completo here. Ci sono così tanti hack per farlo funzionare. Questo codice dal collegamento ti aiuterà a dispositivo una soluzione.

Esempio di Geko e IE incidere:

doc.createElement('br').insertAfter(startBlock); 

// A text node is required by Gecko only to make the cursor blink. 
if (CKEDITOR.env.gecko) 
    doc.createText('').insertAfter(startBlock); 

// IE has different behaviors regarding position. 
range.setStartAt(startBlock.getNext(), 
    CKEDITOR.env.ie ? CKEDITOR.POSITION_BEFORE_START : 
     CKEDITOR.POSITION_AFTER_START);