web-dev-qa-db-fra.com

Comment obtenir la position de la colonne de curseur (pas les pixels) dans une zone de texte, en caractères, depuis le début?

Comment obtenez-vous la position du curseur dans un <textarea> en utilisant JavaScript?

Par exemple: This is| a text

Cela devrait retourner 7.

Comment voulez-vous qu'il retourne les chaînes entourant le curseur/la sélection?

Par exemple.: 'This is', '', ' a text'.

Si le mot "est" est mis en surbrillance, il renverrait 'This ', 'is', ' a text'.

174

Avec Firefox, Safari (et les autres navigateurs basés sur Gecko), vous pouvez facilement utiliser textarea.selectionStart, mais pour IE, cela ne fonctionne pas, vous devrez donc faire quelque chose comme ceci:

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;
}

( code complet ici )

Je vous recommande également de vérifier le plugin jQuery FieldSelection , cela vous permet de le faire et bien plus encore ...

Edit: En fait, j'ai ré-implémenté le code ci-dessus:

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; 
}

Vérifiez un exemple ici .

173
CMS

Mis à jour le 5 septembre 2010

Puisque tout le monde semble être dirigé ici pour ce problème, j'ajoute ma réponse à une question similaire, qui contient le même code que cette réponse, mais avec un historique complet pour ceux qui sont intéressés:

document.selection.createRange d'IE n'inclut pas les lignes vides de début ou de fin

Il est difficile de prendre en compte les sauts de ligne en fin de ligne dans IE, et je n’ai pas vu de solution permettant de le faire correctement, y compris d’autres réponses à cette question. Il est toutefois possible d'utiliser la fonction suivante, qui vous renverra le début et la fin de la sélection (identiques dans le cas d'un curseur) dans un <textarea> Ou un texte <input> .

Notez que la zone de texte doit avoir le focus pour que cette fonction fonctionne correctement dans IE. En cas de doute, appelez d'abord la méthode focus() de textarea.

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
    };
}
57
Tim Down

J'ai modifié la fonction ci-dessus pour tenir compte des retours à la ligne dans IE. Cela n'a pas été testé mais j'ai fait quelque chose de similaire avec cela dans mon code donc ça devrait être faisable.

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); 

    var add_newlines = 0;
    for (var i=0; i<rc.text.length; i++) {
      if (rc.text.substr(i, 2) == '\r\n') {
        add_newlines += 2;
        i++;
      }
    }

    //return rc.text.length + add_newlines;

    //We need to substract the no. of lines
    return rc.text.length - add_newlines; 
  }  
  return 0; 
}
3
mark

Si vous n'avez pas à supporter IE, vous pouvez utiliser les attributs selectionStart et selectionEnd de textarea.

Pour obtenir la position du curseur, utilisez simplement selectionStart:

function getCaretPosition(textarea) {
  return textarea.selectionStart
}

Pour obtenir les chaînes entourant la sélection, utilisez le code suivant:

function getSurroundingSelection(textarea) {
  return [textarea.value.substring(0, textarea.selectionStart)
         ,textarea.value.substring(textarea.selectionStart, textarea.selectionEnd)
         ,textarea.value.substring(textarea.selectionEnd, textarea.value.length)]
}

Démo sur JSFiddle .

Voir aussi documents HTMLTextAreaElement .

2