web-dev-qa-db-fra.com

Insérer du texte dans la zone de texte à la position du curseur (Javascript)

Je souhaite créer une fonction simple qui ajoute du texte dans une zone de texte à la position du curseur de l'utilisateur. Ce doit être une fonction propre. Juste les bases. Je peux comprendre le reste. 

84
JoshMWilliams
function insertAtCursor(myField, myValue) {
    //IE support
    if (document.selection) {
        myField.focus();
        sel = document.selection.createRange();
        sel.text = myValue;
    }
    //MOZILLA and others
    else if (myField.selectionStart || myField.selectionStart == '0') {
        var startPos = myField.selectionStart;
        var endPos = myField.selectionEnd;
        myField.value = myField.value.substring(0, startPos)
            + myValue
            + myField.value.substring(endPos, myField.value.length);
    } else {
        myField.value += myValue;
    }
}
83
Raab

Cet extrait de code pourrait vous aider avec quelques lignes de jQuery 1.9+: http://jsfiddle.net/4MBUG/2/

$('input[type=button]').on('click', function() {
    var cursorPos = $('#text').prop('selectionStart');
    var v = $('#text').val();
    var textBefore = v.substring(0,  cursorPos);
    var textAfter  = v.substring(cursorPos, v.length);

    $('#text').val(textBefore + $(this).val() + textAfter);
});
63
Adriano Alves

Pour le bon Javascript

HTMLTextAreaElement.prototype.insertAtCaret = function (text) {
  text = text || '';
  if (document.selection) {
    // IE
    this.focus();
    var sel = document.selection.createRange();
    sel.text = text;
  } else if (this.selectionStart || this.selectionStart === 0) {
    // Others
    var startPos = this.selectionStart;
    var endPos = this.selectionEnd;
    this.value = this.value.substring(0, startPos) +
      text +
      this.value.substring(endPos, this.value.length);
    this.selectionStart = startPos + text.length;
    this.selectionEnd = startPos + text.length;
  } else {
    this.value += text;
  }
};
25
Erik Aigner

Une pure modification de JS de la réponse d'Erik Pukinskis:

function typeInTextarea(el, newText) {
  var start = el.selectionStart
  var end = el.selectionEnd
  var text = el.value
  var before = text.substring(0, start)
  var after  = text.substring(end, text.length)
  el.value = (before + newText + after)
  el.selectionStart = el.selectionEnd = start + newText.length
  el.focus()
}

Testé sous Chrome 47 uniquement.

Si vous souhaitez modifier la valeur du texte sélectionné pendant que vous tapez dans le même champ (pour un effet de saisie semi-automatique ou similaire), transmettez document.activeElement en tant que premier paramètre.

Ce n'est pas la façon la plus élégante de faire cela, mais c'est assez simple.

11
Jayant Bhawal

La réponse de Rab fonctionne très bien, mais pas pour Microsoft Edge. J'ai donc ajouté une petite adaptation pour Edge également: 

https://jsfiddle.net/et9borp4/

function insertAtCursor(myField, myValue) {
    //IE support
    if (document.selection) {
        myField.focus();
        sel = document.selection.createRange();
        sel.text = myValue;
    }
    // Microsoft Edge
    else if(window.navigator.userAgent.indexOf("Edge") > -1) {
      var startPos = myField.selectionStart; 
      var endPos = myField.selectionEnd; 

      myField.value = myField.value.substring(0, startPos)+ myValue 
             + myField.value.substring(endPos, myField.value.length); 

      var pos = startPos + myValue.length;
      myField.focus();
      myField.setSelectionRange(pos, pos);
    }
    //MOZILLA and others
    else if (myField.selectionStart || myField.selectionStart == '0') {
        var startPos = myField.selectionStart;
        var endPos = myField.selectionEnd;
        myField.value = myField.value.substring(0, startPos)
            + myValue
            + myField.value.substring(endPos, myField.value.length);
    } else {
        myField.value += myValue;
    }
}
8
Snorvarg

J'aime le javascript simple, et jQuery est généralement utilisé. Voici ce que j'ai trouvé, basé sur mparkuk's :

function typeInTextarea(el, newText) {
  var start = el.prop("selectionStart")
  var end = el.prop("selectionEnd")
  var text = el.val()
  var before = text.substring(0, start)
  var after  = text.substring(end, text.length)
  el.val(before + newText + after)
  el[0].selectionStart = el[0].selectionEnd = start + newText.length
  el.focus()
}

$("button").on("click", function() {
  typeInTextarea($("textarea"), "some text")
  return false
})

Voici une démo: http://codepen.io/erikpukinskis/pen/EjaaMY?editors=101

7
Erik Pukinskis

Si l'utilisateur ne touche pas l'entrée une fois le texte inséré, l'événement 'input' n'est jamais déclenché et l'attribut value ne reflétera pas le changement. Par conséquent, il est important de déclencher l'événement d'entrée après l'insertion de texte par programme. Concentrer le champ n'est pas suffisant.

Ce qui suit est une copie de de la réponse de Snorvarg avec un déclencheur d’entrée à la fin:

function insertAtCursor(myField, myValue) {
    //IE support
    if (document.selection) {
        myField.focus();
        sel = document.selection.createRange();
        sel.text = myValue;
    }
    // Microsoft Edge
    else if(window.navigator.userAgent.indexOf("Edge") > -1) {
      var startPos = myField.selectionStart; 
      var endPos = myField.selectionEnd; 

      myField.value = myField.value.substring(0, startPos)+ myValue 
             + myField.value.substring(endPos, myField.value.length); 

      var pos = startPos + myValue.length;
      myField.focus();
      myField.setSelectionRange(pos, pos);
    }
    //MOZILLA and others
    else if (myField.selectionStart || myField.selectionStart == '0') {
        var startPos = myField.selectionStart;
        var endPos = myField.selectionEnd;
        myField.value = myField.value.substring(0, startPos)
            + myValue
            + myField.value.substring(endPos, myField.value.length);
    } else {
        myField.value += myValue;
    }
    triggerEvent(myField,'input');
}

function triggerEvent(el, type){
  if ('createEvent' in document) {
    // modern browsers, IE9+
    var e = document.createEvent('HTMLEvents');
    e.initEvent(type, false, true);
    el.dispatchEvent(e);
  } else {
    // IE 8
    var e = document.createEventObject();
    e.eventType = type;
    el.fireEvent('on'+e.eventType, e);
  }
}

Crédit à plainjs.com pour la fonction triggerEvent

Plus d'informations sur l'événement oninput sur w3schools.com

J'ai découvert cela en créant un emoji-picker pour un chat. Si l'utilisateur ne sélectionne que quelques émoticônes et clique sur le bouton "envoyer", le champ de saisie n'est jamais touché par l'utilisateur. Lors de la vérification de l'attribut value, il était toujours vide, même si l'unicodes emoji inséré était visible dans le champ de saisie. Il s'avère que si l'utilisateur ne touche pas le champ, l'événement 'input' ne se déclenche jamais et la solution consiste à le déclencher de cette manière. Il a fallu un bon bout de temps pour résoudre ce problème ... espérons que cela fera gagner du temps à quelqu'un.

4
Jette

Une solution simple qui fonctionne sur Firefox, Chrome, Opera, Safari et Edge mais ne fonctionnera probablement pas sur les anciens navigateurs IE.

  var target = document.getElementByID("mytextarea_id")

  if (target.setRangeText) {
     //if setRangeText function is supported by current browser
     target.setRangeText(data)
  } else {
    target.focus()
    document.execCommand('insertText', false /*no UI*/, data);
  }
}

La fonction setRangeText vous permet de remplacer la sélection actuelle par le texte fourni ou, en l’absence de sélection, d’insérer le texte à la position du curseur. Pour autant que je sache, il n’est supporté que par Firefox.

Pour les autres navigateurs, la commande "insertText" n'affecte que l'élément html actuellement ciblé et a le même comportement que setRangeText

Inspiré partiellement par cela article

2
Ramast
 /**
 * Usage "foo baz".insertInside(4, 0, "bar ") ==> "foo bar baz"
 */
String.prototype.insertInside = function(start, delCount, newSubStr) {
    return this.slice(0, start) + newSubStr + this.slice(start + Math.abs(delCount));
};


 $('textarea').bind("keydown keypress", function (event) {
   var val = $(this).val();
   var indexOf = $(this).prop('selectionStart');
   if(event.which === 13) {
       val = val.insertInside(indexOf, 0,  "<br>\n");
       $(this).val(val);
       $(this).focus();
    }
})
1
zaarour

Changé pour getElementById (myField)

 function insertAtCursor(myField, myValue) {
    //IE support
    if (document.selection) {
        document.getElementById(myField).focus();
        sel = document.selection.createRange();
        sel.text = myValue;
    }
    //MOZILLA and others
    else if (document.getElementById(myField).selectionStart || document.getElementById(myField).selectionStart == '0') {
        var startPos = document.getElementById(myField).selectionStart;
        var endPos = document.getElementById(myField).selectionEnd;
        document.getElementById(myField).value = document.getElementById(myField).value.substring(0, startPos)
            + myValue
            + document.getElementById(myField).value.substring(endPos, document.getElementById(myField).value.length);
    } else {
        document.getElementById(myField).value += myValue;
    }
}
0
tekagami

Enregistrement de la fonction modifiée pour propre référence. Cet exemple insère un élément sélectionné à partir de l'objet <select> et place le curseur entre les balises:

//Inserts a choicebox selected element into target by id
function insertTag(choicebox,id) {
    var ta=document.getElementById(id)
    ta.focus()
    var ss=ta.selectionStart
    var se=ta.selectionEnd
    ta.value=ta.value.substring(0,ss)+'<'+choicebox.value+'>'+'</'+choicebox.value+'>'+ta.value.substring(se,ta.value.length)
    ta.setSelectionRange(ss+choicebox.value.length+2,ss+choicebox.value.length+2)
}
0
Alexiy