web-dev-qa-db-fra.com

Sélectionner par programme du texte dans un élément HTML contenteditable?

En JavaScript, il est possible de sélectionner un texte par programme dans un élément input ou textarea. Vous pouvez focaliser une entrée avec ipt.focus(), puis sélectionner son contenu avec ipt.select() . Vous pouvez même sélectionner une plage spécifique avec ipt.setSelectionRange(from,to) .

Ma question est la suivante: existe-t-il un moyen de faire cela dans un élément contenteditable également?

J'ai découvert que je pouvais faire elem.focus(), pour placer le curseur dans un élément contenteditable, mais par la suite, exécuter elem.select() ne fonctionnait pas (ni setSelectionRange). Je ne trouve rien sur le Web à ce sujet, mais je cherche peut-être la mauvaise chose ...

En passant, si cela fait une différence, je n’en ai besoin que pour fonctionner dans Google Chrome, comme pour une extension Chrome.

101
callum

Si vous souhaitez sélectionner tout le contenu d'un élément (contenteditable ou non) dans Chrome, voici comment procéder. Cela fonctionnera également dans Firefox, Safari 3+, Opera 9+ (éventuellement avec des versions antérieures également) et IE 9. Vous pouvez également créer des sélections allant jusqu'au Les API dont vous avez besoin sont DOM Range (la spécification actuelle est DOM niveau 2 , voir aussi MDN ) et Selection, qui est spécifié comme faisant partie de nouvelle spécification de plage ( MDN docs ).

function selectElementContents(el) {
    var range = document.createRange();
    range.selectNodeContents(el);
    var sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
}

var el = document.getElementById("foo");
selectElementContents(el);
153
Tim Down

En plus de réponse de Tim Downs , j’ai mis au point une solution qui fonctionne même dans oldIE:

var selectText = function() {
  var range, selection;
  if (document.body.createTextRange) {
    range = document.body.createTextRange();
    range.moveToElementText(this);
    range.select();
  } else if (window.getSelection) {
    selection = window.getSelection();
    range = document.createRange();
    range.selectNodeContents(this);
    selection.removeAllRanges();
    selection.addRange(range);
  }
};

document.getElementById('foo').ondblclick = selectText;​

Testé dans IE 8+, Firefox 3+, Opera 9+, & Chrome 2+. Même si j'ai configurez-le dans un plugin jQuery:

jQuery.fn.selectText = function() {
  var range, selection;
  return this.each(function() {
    if (document.body.createTextRange) {
      range = document.body.createTextRange();
      range.moveToElementText(this);
      range.select();
    } else if (window.getSelection) {
      selection = window.getSelection();
      range = document.createRange();
      range.selectNodeContents(this);
      selection.removeAllRanges();
      selection.addRange(range);
    }
  });
};

$('#foo').on('dblclick', function() {
  $(this).selectText();
});

... et qui est intéressé, voici la même chose pour tous les drogués du café:

jQuery.fn.selectText = ->
  @each ->
    if document.body.createTextRange
      range = document.body.createTextRange()
      range.moveToElementText @
      range.select()
    else if window.getSelection
      selection = window.getSelection()
      range = document.createRange()
      range.selectNodeContents @
      selection.removeAllRanges()
      selection.addRange range
    return

Mise à jour:

Si vous souhaitez sélectionner la page entière ou le contenu d'une région modifiable (marqué avec contentEditable), vous pouvez le faire beaucoup plus simplement en passant à designMode et en utilisant document.execCommand:

Il y a un bon point de départ chez MDN et ne petite documentation .

var selectText = function () {
  document.execCommand('selectAll', false, null);
};

(fonctionne bien dans IE6 +, Opera 9+, Firefoy 3+, Chrome 2+) http://caniuse.com/#search = execCommand

34
yckart

Puisque toutes les réponses existantes traitent des éléments div, je vais expliquer comment procéder avec spans.

Il y a une différence subtile lors de la sélection d'une plage de texte dans un span. Pour pouvoir passer les index de début et de fin du texte, vous devez utiliser un nœud Text, comme décrit ici :

Si startNode est un Node de type Text, Comment ou CDATASection, puis startOffset est le nombre de caractères à partir du début de startNode. Pour les autres Node types , startOffset est le nombre de nœuds enfants entre le début du startNode.

var e = document.getElementById("id of the span element you want to select text in");
var textNode = e.childNodes[0]; //text node is the first child node of a span

var r = document.createRange();
var startIndex = 0;
var endIndex = textNode.textContent.length;
r.setStart(textNode, startIndex);
r.setEnd(textNode, endIndex);

var s = window.getSelection();
s.removeAllRanges();
s.addRange(r);
7
Domysee

Rangy vous permet de faire ce multi-navigateur avec le même code. Rangy est une implémentation multi-navigateur des méthodes DOM pour les sélections. Il est bien testé et le rend beaucoup moins douloureux. Je refuse de toucher contenteditable sans elle.

Vous pouvez trouver rangy ici:

http://code.google.com/p/rangy/

Avec rangy dans votre projet, vous pouvez toujours écrire cela, même si le navigateur est IE 8 ou une version antérieure, et dispose d'une API native complètement différente pour les sélections:

var range = rangy.createRange();
range.selectNodeContents(contentEditableNode);
var sel = rangy.getSelection();
sel.removeAllRanges();
sel.addRange(range);

Où "contentEditableNode" est le noeud DOM qui a l'attribut contenteditable. Vous pourriez le chercher comme ça:

var contentEditable = document.getElementById('my-editable-thing');

Ou si jQuery fait déjà partie de votre projet et que vous le trouvez pratique:

var contentEditable = $('.some-selector')[0];
6
Tom Boutell

[Mis à jour pour corriger l'erreur]

Voici un exemple adapté de cette réponse qui semble bien fonctionner dans Chrome - sélection d'une plage dans contenteditable div

var Elm = document.getElementById("myText"),
    fc = Elm.firstChild,
    ec = Elm.lastChild,
    range = document.createRange(),
    sel;
Elm.focus();
range.setStart(fc,1);
range.setEnd(ec,3);
sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);

HTML est:

<div id="myText" contenteditable>test</div>
2
patorjk