2014-04-08 5 views

risposta

22

Il problema sembra essere specifico per WebKit; Non sono riuscito a riprodurlo in IE o Firefox. Come OP già accennato, l'errore su Google Chrome è:

Uncaught IndexSizeError: Failed to execute 'getRangeAt' on 'Selection': 0 is not a valid index

Safari ha lo stesso problema, ma il messaggio è diverso:

INDEX_SIZE_ERR: DOM Exception 1: Index or size was negative, or greater than the allowed value.

si verifica in genere in semplici editor WYSIWYG. Esempio:

<form name="frm"> 
 
    <div contenteditable="true" style="border:1px solid grey;height:8em;width:100%;"> 
 
    Text inside my editor. 
 
    </div> 
 
    Click this button to insert some text into the text editor: 
 
    <button type="button" onclick="doInsert('TEST');">Insert</button> 
 
    </form> 
 
    <script> 
 
    function doInsert(text) { 
 
     var sel = window.getSelection && window.getSelection(); 
 
     if (sel) { 
 
      var range = sel.getRangeAt(0);    // error here 
 
      var node = document.createTextNode(text); 
 
      range.deleteContents(); 
 
      range.insertNode(node); 
 
     } 
 
    } 
 
    </script>

Una volta caricata la pagina, fare clic sul pulsante; vedrai il messaggio di errore nella console JavaScript (Chrome) o nella console degli errori (Safari). Ma se si fa clic in qualsiasi punto all'interno della sezione dell'editor prima del facendo clic sul pulsante, si verificherà l'errore non.

Questo problema è facile da prevenire; controllare sempre prima di chiamare rangeCountgetRangeAt:

function doInsert(text) { 
    var sel = window.getSelection && window.getSelection(); 
    if (sel && sel.rangeCount > 0) { 
     var range = sel.getRangeAt(0); 
     ... 

Naturalmente, si può evitare la situazione dando il focus Editor (con il metodo focus) al caricamento della pagina.

Tuttavia, ci sono eventi rari che causano la perdita del range di selezione del tuo editor in seguito. Finora, sono stato solo in grado di riprodurre questo con un controllo di elenco di selezione multipla:

<form name="frm"> 
 
    <div contenteditable="true" style="border:1px solid grey;height:8em;width:100%;"> 
 
    Click to position the caret anywhere inside this editor section. 
 
    </div> 
 
    Next, select an item from this list: 
 
    <select id="insertables" multiple="multiple"> 
 
    <option>foo</option> 
 
    <option>bar</option> 
 
    <option>baz</option> 
 
    </select> 
 
    <br />Finally, click this button to insert the list item into the text editor: 
 
    <button type="button" onclick="doInsert(frm.insertables.value);">Insert</button> 
 
</form> 
 
<script> 
 
    function doInsert(text) { 
 
    var sel = window.getSelection && window.getSelection(); 
 
    if (sel) { 
 
     var range = sel.getRangeAt(0); // error here 
 
     var node = document.createTextNode(text); 
 
     range.deleteContents(); 
 
     range.insertNode(node); 
 
    } 
 
    } 
 
</script>

Ancora una volta, posso evitare l'errore controllando rangeCount. Ma il problema rimane che il mio pulsante non inserisce la voce della lista selezionata nell'ultima posizione nota del cursore, come avrebbe dovuto fare. Il metodo focus non aiuta; ripristinerà la posizione del cursore in alto a sinistra nell'editor.

Una soluzione è quella di salvare continuamente l'intervallo di selezione corrente (per questo scopo, evento trap SelectionChange):

var savedRange = null; 

document.addEventListener("selectionchange", HandleSelectionChange, false); 

function HandleSelectionChange() { 
    var sel = window.getSelection && window.getSelection(); 
    if (sel && sel.rangeCount > 0) { 
     savedRange = sel.getRangeAt(0); 
    } 
} 

e ripristinare quando viene cliccato il pulsante:

function doInsert(text) { 
    var sel = window.getSelection && window.getSelection(); 
    if (sel && sel.rangeCount == 0 && savedRange != null) { 
     sel.addRange(savedRange); 
    } 
    if (sel && sel.rangeCount > 0) { 
     var range = sel.getRangeAt(0); 
     var node = document.createTextNode(text); 
     range.deleteContents(); 
     range.insertNode(node); 
    } 
} 

Fiddle: http://jsfiddle.net/stXDu/

+0

Ottima soluzione compagno. Questa seconda opzione sembra così semplice per qualcuno con una buona esperienza in JS, ma in qualche modo non ci ha mai pensato. Grazie per l'idea e sì questo sembra essere uno specifico per il webkit. In Chrome v24, ottengo lo stesso messaggio di eccezione di Safari. – Harry

0

Qui c'è qualcosa da considerare: hai selezionato disattivato da qualche parte nel tuo codice?In tal caso, è possibile che prima di selezionare , attivare prima la selezione, preferibilmente in un evento con promemoria o prima di concentrarsi sull'elemento (NB!), Prima di ottenere l'intervallo. Fare questo ha risolto la mia versione del problema.

$('#MyEditableDiv').on('mousedown', function (e) { 

    $(document).enableSelection(); 


}); 
2

ho qualche soluzione nel mio progetto

uso iframe come editor WYSIWYG

abbiamo impostato il editwin come la finestra del iframe

ogni volta prima di inserire qualcosa di per l'editor di codice, è necessario utilizzare prima il codice riportato di seguito.

editwin.focus(); 
editwin.document.body.focus(); 

uso textarea come redattore

impostato textobj come il DOM del textarea

stesso modo come in su, ma codice diverso

textobj.focus(); 
+0

Questo non sembra rispondere alla domanda. –

+0

@JeffreyBosboom con il focus editor, ** 'getRangeAt' su 'Selection': 0 non è un indice valido ** il problema può risolvere – shuizhongyuemin

+0

Risolto in wysiwyg.js, riga 490: function insertNodeAtSelection (insertNode, n) { \t document.getElementById ('wysiwyg' + n) .focus(); // Aggiungi questa linea –

Problemi correlati