Búsqueda de sitios web

javascript - ¿Cómo obtener la posición de la columna del cursor (no en píxeles) en un área de texto, en caracteres, desde el inicio?


¿Cómo se obtiene la posición del cursor en un <textarea> usando JavaScript?

Por ejemplo: Esto es| un texto

Esto debería devolver 7.

¿Cómo harías para que devolviera las cadenas que rodean el cursor/la selección?

Por ejemplo: 'Esto es', '', ' un texto'.

Si la palabra “is ” está resaltada, entonces devolvería 'This ', 'is', ' a text'.

Respuesta #1

Con Firefox, Safari (y otros navegadores basados en Gecko) puedes usar fácilmente textarea.selectionStart, pero para IE eso no funciona, así que tendrás que hacer algo como esto:

function getCaret(node) {
  if (node.selectionStart) {
    return node.selectionStart;
  } else if (!document.selection) {
    return 0;
  }

  var c = "\001",
      sel = document.selection.createRange(),
      dul = sel.duplicate(),
      len = 0;

  dul.moveToElementText(node);
  sel.text = c;
  len = dul.text.indexOf(c);
  sel.moveStart('character',-1);
  sel.text = "";
  return len;
}

(código completo aquí)

También te recomiendo que revises el plugin jQuery FieldSelection, te permite hacer eso y mucho más...

Editar: En realidad, volví a implementar el código anterior:

function getCaret(el) { 
  if (el.selectionStart) { 
    return el.selectionStart; 
  } else if (document.selection) { 
    el.focus(); 

    var r = document.selection.createRange(); 
    if (r == null) { 
      return 0; 
    } 

    var re = el.createTextRange(), 
        rc = re.duplicate(); 
    re.moveToBookmark(r.getBookmark()); 
    rc.setEndPoint('EndToStart', re); 

    return rc.text.length; 
  }  
  return 0; 
}

Ver un ejemplo aquí.

Respuesta #2

Actualizado el 5 de septiembre de 2010

Viendo que parece que todos son dirigidos aquí por este problema, estoy añadiendo mi respuesta a una pregunta similar, que contiene el mismo código que esta respuesta pero con un contexto completo para aquellos que estén interesados:

El método document.selection.createRange de IE no incluye líneas en blanco al principio o al final

Tener en cuenta los saltos de línea al final es complicado en IE, y no he visto ninguna solución que haga esto correctamente, incluyendo cualquier otra respuesta a esta pregunta. Sin embargo, es posible, usando la siguiente función, la cual te devolverá el inicio y el fin de la selección (que son los mismos en el caso de un cursor) dentro de un <textarea> o un <input> de texto.

Tenga en cuenta que el área de texto debe tener el enfoque para que esta función funcione correctamente en IE. Si tiene dudas, llame primero al método focus() del área de texto.

function getInputSelection(el) {
    var start = 0, end = 0, normalizedValue, range,
        textInputRange, len, endRange;

    if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
        start = el.selectionStart;
        end = el.selectionEnd;
    } else {
        range = document.selection.createRange();

        if (range && range.parentElement() == el) {
            len = el.value.length;
            normalizedValue = el.value.replace(/\r\n/g, "\n");

            // Create a working TextRange that lives only in the input
            textInputRange = el.createTextRange();
            textInputRange.moveToBookmark(range.getBookmark());

            // Check if the start and end of the selection are at the very end
            // of the input, since moveStart/moveEnd doesn't return what we want
            // in those cases
            endRange = el.createTextRange();
            endRange.collapse(false);

            if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
                start = end = len;
            } else {
                start = -textInputRange.moveStart("character", -len);
                start += normalizedValue.slice(0, start).split("\n").length - 1;

                if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
                    end = len;
                } else {
                    end = -textInputRange.moveEnd("character", -len);
                    end += normalizedValue.slice(0, end).split("\n").length - 1;
                }
            }
        }
    }

    return {
        start: start,
        end: end
    };
}

Artículos relacionados