2012-06-09 7 views
6

Sto usando la tecnica mostrata in this answer per estendere la selezione di una pagina web per un limite di parola:Come estendere la selezione al limite della parola utilizzando JavaScript, una sola volta?

function snapSelectionToWord() { 
    var sel; 

    // Check for existence of window.getSelection() and that it has a 
    // modify() method. IE 9 has both selection APIs but no modify() method. 
    if (window.getSelection && (sel = window.getSelection()).modify) { 
     sel = window.getSelection(); 
     if (!sel.isCollapsed) { 

      // Detect if selection is backwards 
      var range = document.createRange(); 
      range.setStart(sel.anchorNode, sel.anchorOffset); 
      range.setEnd(sel.focusNode, sel.focusOffset); 
      var backwards = range.collapsed; 
      range.detach(); 

      // modify() works on the focus of the selection 
      var endNode = sel.focusNode, endOffset = sel.focusOffset; 
      sel.collapse(sel.anchorNode, sel.anchorOffset); 
      if (backwards) { 
       sel.modify("move", "forward", "word"); 
       sel.extend(endNode, endOffset); 
       sel.modify("extend", "backward", "word"); 

      } else { 
       sel.modify("move", "backward", "word"); 
       sel.extend(endNode, endOffset); 
       sel.modify("extend", "forward", "word"); 
      } 
     } 
    } else if ((sel = document.selection) && sel.type != "Control") { 
     var textRange = sel.createRange(); 
     if (textRange.text) { 
      textRange.expand("word"); 
      // Move the end back to not include the word's trailing space(s), 
      // if necessary 
      while (/\s$/.test(textRange.text)) { 
       textRange.moveEnd("character", -1); 
      } 
      textRange.select(); 
     } 
    } 
}​ 

Fin qui, tutto bene. Ma se chiami la funzione snapSelectionToWord più di una volta sulla selezione, è espansa verso l'esterno di una parola in entrambe le direzioni su ogni chiamata, il che non va bene se vuoi chiamarlo più di una volta mentre il testo è selezionato.

Ecco uno live jsFiddle example che consente di fare ripetutamente clic su un pulsante 'Snap', che dimostra il problema.

In che modo è possibile correggere la soluzione originale in modo che non espanda la selezione se si trova già su un limite di parole?

  • Preferirei lasciare un commento sul original solution ma, purtroppo, non ho ancora stato abbellito con sufficiente karma karma vigili StackOverflow - altrimenti, avevo appena chiedere lì. E non sono sicuro di come risolvere il problema, quindi non modificherò la soluzione originale.

Edit: L'aggiunta di frammento di codice per richiesta

+1

Si prega di inserire tutto il codice rilevante in questo post, invece di collegare ad esso. –

+3

Fatto. Ancora imparando l'etichetta StackOverflow. – Inactivist

+1

Ho aggiornato la soluzione originale con il cambiamento di Matt M. –

risposta

5

Forse provare popping un personaggio fuori in entrambe le direzioni prima di scattare alle parole:

 if (backwards) { 
      sel.modify("move", "backward", "character"); 
      sel.modify("move", "forward", "word"); 
      sel.extend(endNode, endOffset); 
      sel.modify("extend", "forward", "character"); 
      sel.modify("extend", "backward", "word"); 

     } else { 
      sel.modify("move", "forward", "character"); 
      sel.modify("move", "backward", "word"); 
      sel.extend(endNode, endOffset); 
      sel.modify("extend", "backward", "character"); 
      sel.modify("extend", "forward", "word"); 
     } 

http://jsfiddle.net/3RAkZ/

+1

Mi sembra buono. –

+2

+1. Lavora su Google Chrome. Ecco una versione più piccola che ha rimosso il codice ridondante: http: // jsfiddle.net/3RAkZ/1/ –

+0

Grazie. Funziona anche in Chrome qui. Proverò altri browser e riferirò. – Inactivist

9

ho scritto quel campione. Non ne sono mai stato contento, per il motivo che hai sottolineato, e anche perché non funziona in modo coerente in tutti i browser (o affatto in Opera).

Ho lavorato a una soluzione cross-browser per questo per la mia libreria Rangy. La versione corrente è descritta come alfa, ma funziona piuttosto bene. Ecco una demo:

http://rangy.googlecode.com/svn/trunk/demos/textrange.html

Ed ecco la vostra demo, modificati per utilizzare Rangy:

http://jsfiddle.net/timdown/RgZ8r/

La linea cruciale è

rangy.getSelection().expand("word"); 

Se non si desidera utilizzare qualcosa di pesante come Rangy (è qualcosa come 50 KB di codice per utilizzare il modulo TextRange), quindi è possibile migliorare l'originale codice (come Matt M ha nella sua risposta) ma avrà ancora dei limiti.

+0

Grazie per l'aggiornamento. Controllerò la tua soluzione aggiornata. – Inactivist

+0

Ho apportato una leggera modifica al violino - http://jsfiddle.net/dux4fqhL/1/. Controlla se la selezione viene compressa prima di espandersi, altrimenti potrebbe avere alcuni effetti indesiderati quando si seleziona nulla. – gat

0

il codice non funziona correttamente nel testo arabo si può provare questo frammento di nstead

function snapSelectionToWord() { 
 
    var sel; 
 

 
    // Check for existence of window.getSelection() and that it has a 
 
    // modify() method. IE 9 has both selection APIs but no modify() method. 
 
    if (window.getSelection && (sel = window.getSelection()).modify) { 
 
     sel = window.getSelection(); 
 
     if (sel.isCollapsed) { 
 
      
 
      var rng2 = sel.getRangeAt(0); 
 
      var startOffset = rng2.startOffset; 
 
      startOffset = 0 
 
      for (var i = rng2.startOffset; i >= 0; i--) { 
 
       if (rng2.startContainer.data[i].match(/\S/) != null) { 
 
       startOffset++; 
 
       } else 
 
       break; 
 
      } 
 
      var endOffset = rng2.endOffset; 
 
      endOffset = 0; 
 
      for (var i = rng2.endOffset; i < rng2.endContainer.data.length; i++) 
 
       if (rng2.endContainer.data[i].match(/\S/)) { 
 
       endOffset++; 
 
       } else 
 
       break; 
 

 
      startOffset = rng2.startOffset - startOffset; 
 
      startOffset = startOffset < 0 ? 0 : startOffset; 
 

 
      endOffset = rng2.endOffset + endOffset; 
 
      endOffset = endOffset >= rng2.endContainer.data.length ? rng2.endContainer.data.length - 1 : endOffset; 
 

 
      rng2.setStart(rng2.startContainer, startOffset); 
 
      rng2.setEnd(rng2.endContainer, endOffset); 
 
      sel.removeAllRanges(); 
 
      sel.addRange(rng2); 
 
      
 
     } 
 
    } else if ((sel = document.selection) && sel.type != "Control") { 
 
     var textRange = sel.createRange(); 
 
     if (textRange.text) { 
 
      textRange.expand("word"); 
 
      // Move the end back to not include the word's trailing space(s), 
 
      // if necessary 
 
      while (/\s$/.test(textRange.text)) { 
 
       textRange.moveEnd("character", -1); 
 
      } 
 
      textRange.select(); 
 
     } 
 
    } 
 
}

Problemi correlati