2012-06-28 9 views
6

Estoy tratando de extraer una sola palabra de un contenido editable div en la posición, cuando se hace clic en el mouse. Por ejemplo:¿Cómo puedo obtener la palabra que dice que está dentro de una div contenida?

Lorem ipsum dolor sit amet, cons|ectetur adipiscing elit. Cras vestibulum gravida 
tincidunt. Proin justo dolor, iaculis vulputate eleifend et, facilisis eu erat.* 

Uso del | para representar el símbolo de intercalación, la función debe devolver "consectetur".

Mi intento:

window.onload = function() { 
     document.getElementById("text-editor").onclick = function() { 
      var caretPos = 0, containerEl = null, sel, range; 
      if (window.getSelection) { 
       sel = window.getSelection(); 
       if (sel.rangeCount) { 
        range = sel.getRangeAt(0); 
        if (range.commonAncestorContainer.parentNode == this) { 
         caretPos = range.endOffset; 
        } 
       } 
      } else if (document.selection && document.selection.createRange) { 
       range = document.selection.createRange(); 
       if (range.parentElement() == this) { 
        var tempEl = document.createElement("span"); 
        this.insertBefore(tempEl, this.firstChild); 
        var tempRange = range.duplicate(); 
        tempRange.moveToElementText(tempEl); 
        tempRange.setEndPoint("EndToEnd", range); 
        caretPos = tempRange.text.length; 
       } 
      } 
      var prevSpace, nextSpace, text = this.innerText; 

      prevSpace = text.substring(0,caretPos).lastIndexOf(" "); 
      nextSpace = text.indexOf(" ", caretPos + 1); 
      nextSpace == -1 ? nextSpace = text.length - 1 : false; 
      prevSpace++; 
      console.log([prevSpace,caretPos,nextSpace].join("|")); 
      var word = text.substring(prevSpace, nextSpace); 
      //Removes punctuation and whitespace. 
      var patt = new RegExp("([A-Za-z0-9']*)","g"); 
      word = patt.exec(word)[0]; 
      document.getElementById("current-word").innerHTML = word; 
     }; 
    }; 

Una función está ligado al evento de clic de ratón de la div contenteditable, que calcula la posición de intercalación y luego encuentra los índices de los caracteres de espacios anteriores y posteriores (o principio o el final de la cadena por completo) y utiliza la subcadena para determinar la palabra. Hay una coincidencia rápida de expresiones regulares para eliminar la puntuación y el espacio en blanco, y finalmente terminamos con la palabra correcta.

Esto funcionó bien, cuando había un único nodo de texto dentro del div satisfactorio, pero tan pronto como comencé a descartar y otras etiquetas variadas, la parte del método que calculaba la posición de intercalación dejó de funcionar, siempre calculando que era 0. ¿Hay alguna forma de calcular la posición de intercalación en HTML como lo hizo con el texto?

Si no es así, ¿alguien puede sugerir un método alternativo?

+0

Hice una pregunta similar y encontré otra solución usando Rangy: http://stackoverflow.com/questions/22076945/rangy-word-under-caret-again/22097787#22097787 –

Respuesta

12

Se podría utilizar el nuevo TextRange module de mi biblioteca Rangy para esto, aunque es enorme exageración sólo para que una característica. Aquí está el código que había necesidad:

var sel = rangy.getSelection(); 
sel.expand("word"); 
var word = sel.text(); 
alert(word); 

De lo contrario, si se puede vivir sin soporte para la pre-parpadeo Opera (hasta e incluyendo la versión 12) y Firefox < 4, se puede usar Selection.modify() (WebKit, Firefox) y el método expand() de TextRange (IE). Aquí hay un ejemplo.

Demostración: http://jsfiddle.net/timdown/dBgHn/1/

Código:

function getWord() { 
    var sel, word = ""; 
    if (window.getSelection && (sel = window.getSelection()).modify) { 
     var selectedRange = sel.getRangeAt(0); 
     sel.collapseToStart(); 
     sel.modify("move", "backward", "word"); 
     sel.modify("extend", "forward", "word"); 

     word = sel.toString(); 

     // Restore selection 
     sel.removeAllRanges(); 
     sel.addRange(selectedRange); 
    } else if ((sel = document.selection) && sel.type != "Control") { 
     var range = sel.createRange(); 
     range.collapse(true); 
     range.expand("word"); 
     word = range.text; 
    } 
    alert(word); 
} 
+0

¡Fantástico! Esto es perfecto. Cheers =) –

+0

@Tim Down - ¿hay alguna manera de cambiar esta función para devolver las posiciones de los límites de las palabras? El comienzo y el final de la palabra, como números. Por ejemplo: marcar 'one tw | o three' devolvería: '[4,7]' – ragulka

+0

@ragulka: ¿Qué versión? Rangy o 'Selection.modify()'? –

0

BitBucket han publicado su biblioteca Cursores.js que hace esto, es pequeño y enfocado que es agradable - http://cursores.bitbucket.org/

El único problema que tengo es que no recoge el token si no hay texto a la izquierda del símbolo de intercalación, por ejemplo, "t | est" funcionaría, pero "| test" no lo haría.

Cuestiones relacionadas