Wstawianie tekstu, w którym kursor używa Javascript / jquery

167

Mam stronę z wieloma polami tekstowymi. Kiedy ktoś kliknie łącze, chcę wstawić słowo lub dwa w miejscu kursora lub dołączyć do pola tekstowego, na którym jest fokus.

Na przykład, jeśli kursor / fokus znajduje się na polu tekstowym z napisem „jabłko” i kliknie łącze „[e-mail]”, chcę, aby w polu tekstowym było napisane „jabłko [email protected]”.

W jaki sposób mogę to zrobić? Czy jest to w ogóle możliwe, ponieważ co, jeśli fokus znajduje się na elemencie radio / dropdown / non textbox? Czy można zapamiętać ostatni skupiony na polu tekstowym?

Kliknij opcję Głos za
źródło
Zakładam, że to możliwe, bo to podstawa redaktorów WYSISYG, jak to zrobić, nie wiem.
Ian Elliott
Dziękuję za zadanie tego pytania… teraz mogę wstawić „[wersja]” pod kursorem za pomocą mojego rozszerzenia do Chrome!
Haykam
Jeśli szukasz prostego modułu z obsługą cofania, wypróbuj wstaw-tekst- obszar -tekst . Jeśli potrzebujesz obsługi IE8 +, wypróbuj pakiet wstawiania tekstu w miejscu kursora .
fregante

Odpowiedzi:

241

Użyj tego stąd :

function insertAtCaret(areaId, text) {
  var txtarea = document.getElementById(areaId);
  if (!txtarea) {
    return;
  }

  var scrollPos = txtarea.scrollTop;
  var strPos = 0;
  var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ?
    "ff" : (document.selection ? "ie" : false));
  if (br == "ie") {
    txtarea.focus();
    var range = document.selection.createRange();
    range.moveStart('character', -txtarea.value.length);
    strPos = range.text.length;
  } else if (br == "ff") {
    strPos = txtarea.selectionStart;
  }

  var front = (txtarea.value).substring(0, strPos);
  var back = (txtarea.value).substring(strPos, txtarea.value.length);
  txtarea.value = front + text + back;
  strPos = strPos + text.length;
  if (br == "ie") {
    txtarea.focus();
    var ieRange = document.selection.createRange();
    ieRange.moveStart('character', -txtarea.value.length);
    ieRange.moveStart('character', strPos);
    ieRange.moveEnd('character', 0);
    ieRange.select();
  } else if (br == "ff") {
    txtarea.selectionStart = strPos;
    txtarea.selectionEnd = strPos;
    txtarea.focus();
  }

  txtarea.scrollTop = scrollPos;
}
<textarea id="textareaid"></textarea>
<a href="#" onclick="insertAtCaret('textareaid', 'text to insert');return false;">Click Here to Insert</a>

George Claghorn
źródło
7
To działało świetnie, ale nie obsługuje zastępowania zaznaczonego tekstu, jak robią to wszystkie edytory tekstu. Może to nie być potrzebne w przypadku oryginalnego pytania autora, ale jeśli tego potrzebujesz, możesz po prostu zamienić „strPos” na „txtArea.selectionEnd”. Moja odpowiedź poniżej pokazuje to, wraz z usunięciem kodu wykrywania przeglądarki, jeśli nie potrzebujesz obsługi starszych wersji IE.
Jeffrey Harmon,
Czy istnieje sposób na wybranie wszystkich elementów areaId?
Haykam
1
Możesz osiągnąć automatyczne usuwanie zaznaczonego tekstu, wstawiając taką funkcję. function deleteTxt() { var ele = document.getElementById('yourTextarea'); var text = ele.value; text = text.slice(0, ele.selectionStart) + text.slice(ele.selectionEnd); ele.value = text; return text; }
NSTuttle
Jak wstawić tekst w miejscu myszy?
Thamarai T
Jesteś najlepszy!
Ecko Santoso
156

Może krótsza wersja byłaby łatwiejsza do zrozumienia?

    jQuery("#btn").on('click', function() {
        var $txt = jQuery("#txt");
        var caretPos = $txt[0].selectionStart;
        var textAreaTxt = $txt.val();
        var txtToAdd = "stuff";
        $txt.val(textAreaTxt.substring(0, caretPos) + txtToAdd + textAreaTxt.substring(caretPos) );
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<textarea id="txt" rows="15" cols="70">There is some text here.</textarea>
<input type="button" id="btn" value="OK" />

Napisałem to w odpowiedzi na Jak dodać tekst do pola tekstowego z aktualnej pozycji wskaźnika za pomocą jquery?

quik_silv
źródło
11
Można także przywrócić daszka pozycję po zmianie wartości z: document.getElementById("txt").selectionStart = caretPos + txtToAdd.length.
Bludwarf
1
pracował dla mnie, dzięki. FYI właściwość "selectionStart" nie istnieje za pośrednictwem selektora jquery $ ("#"). Musisz przejść przez document.getElementById ()
Lego
1
jsfiddle.net/NaHTw/802 to Twoje rozwiązanie z niewielkim dodatkiem, aby zastąpić wybrany obszar tym, co zostało wklejone
patrick,
3
Cóż, jeśli zamierzasz posunąć się tak daleko, usuwając jQuery, równie dobrze możesz usunąć to wszystko . ; ^)
ruffin
8
Aby pomóc, oto kompletne rozwiązanie z przywracaniem pozycji karetki i zastępowaniem wybranego obszaru wklejoną zawartością: jsfiddle.net/NaHTw/1028
AlfaTeK
41

Zatwierdzona odpowiedź od George'a Claghorna działała świetnie, gdy po prostu wstawiał tekst w miejscu kursora. Jeśli jednak użytkownik zaznaczył tekst i chcesz, aby ten tekst został zastąpiony (domyślne rozwiązanie z większością tekstu), musisz wprowadzić niewielką zmianę podczas ustawiania zmiennej „wstecz”.

Ponadto, jeśli nie potrzebujesz obsługi starszych wersji IE, nowoczesne wersje obsługują textarea.selectionStart, dzięki czemu możesz wyłączyć wszystkie funkcje wykrywania przeglądarki i kod specyficzny dla IE.

Oto uproszczona wersja, która działa przynajmniej w Chrome i IE11 i obsługuje zastępowanie zaznaczonego tekstu.

function insertAtCaret(areaId, text) {
    var txtarea = document.getElementById(areaId);
    var scrollPos = txtarea.scrollTop;
    var caretPos = txtarea.selectionStart;

    var front = (txtarea.value).substring(0, caretPos);
    var back = (txtarea.value).substring(txtarea.selectionEnd, txtarea.value.length);
    txtarea.value = front + text + back;
    caretPos = caretPos + text.length;
    txtarea.selectionStart = caretPos;
    txtarea.selectionEnd = caretPos;
    txtarea.focus();
    txtarea.scrollTop = scrollPos;
}
Jeffrey Harmon
źródło
To dobrze, ale nie bierze maxlengthpod uwagę elementu , więc wynikowa wartość po wstawieniu może być dłuższa niż maksymalna.
mbomb007
22

Powyższy kod nie działał dla mnie w IE. Oto kod oparty na tej odpowiedzi .

Wyciągnąłem element, getElementByIdwięc mogłem odwołać się do elementu w inny sposób.

function insertAtCaret(element, text) {
  if (document.selection) {
    element.focus();
    var sel = document.selection.createRange();
    sel.text = text;
    element.focus();
  } else if (element.selectionStart || element.selectionStart === 0) {
    var startPos = element.selectionStart;
    var endPos = element.selectionEnd;
    var scrollTop = element.scrollTop;
    element.value = element.value.substring(0, startPos) +
      text + element.value.substring(endPos, element.value.length);
    element.focus();
    element.selectionStart = startPos + text.length;
    element.selectionEnd = startPos + text.length;
    element.scrollTop = scrollTop;
  } else {
    element.value += text;
    element.focus();
  }
}
input{width:100px}
label{display:block;margin:10px 0}
<label for="in2copy">Copy text from: <input id="in2copy" type="text" value="x"></label>
<label for="in2ins">Element to insert: <input id="in2ins" type="text" value="1,2,3" autofocus></label>
<button onclick="insertAtCaret(document.getElementById('in2ins'),document.getElementById('in2copy').value)">Insert</button>

EDYCJA: Dodano działający fragment kodu, jQuery nie jest używany .

Collin Anderson
źródło
Czy element jest obiektem jquery, czy nie? element.value i element.focus () nie mogą działać jednocześnie ...
Scott Stafford,
7
element.focus()to legalna metoda JavaScript na DOMElements: w3schools.com/jsref/met_html_focus.asp
oliverseal
1
Najlepszym pomysłem jest rezygnacja z kompatybilności z IE.
ar2015
2
Tak, napisałem tę odpowiedź 7 lat temu. W tym momencie IE 11 jest dobrą minimalną obsługiwaną wersją, a powyższy kod tam działa.
Collin Anderson
6

używając @quick_sliv answer:

function insertAtCaret(el, text) {
    var caretPos = el.selectionStart;
    var textAreaTxt = el.value;
    el.value = textAreaTxt.substring(0, caretPos) + text + textAreaTxt.substring(caretPos);
};
math2001
źródło
4

Jak wstawić tekst do bieżącej pozycji kursora TextBox za pomocą JQuery i JavaScript

Proces

  1. Znajdź aktualną pozycję kursora
  2. Uzyskaj tekst do skopiowania
  3. Ustaw tam tekst
  4. Zaktualizuj pozycję kursora

Tutaj mam 2 pola tekstowe i przycisk. Muszę kliknąć określoną pozycję w polu tekstowym, a następnie kliknąć przycisk, aby wkleić tekst z drugiego pola tekstowego do pozycji poprzedniego pola tekstowego.

Głównym problemem jest to, że uzyskanie aktualnej pozycji kursora, w którym wkleimy tekst.

//Textbox on which to be pasted
<input type="text" id="txtOnWhichToBePasted" />

//Textbox from where to be pasted
<input type="text" id="txtFromWhichToBePasted" />


//Button on which click the text to be pasted
<input type="button" id="btnInsert" value="Insert"/>


<script type="text/javascript">

$(document).ready(function () {
    $('#btnInsert').bind('click', function () {
            var TextToBePasted = $('#txtFromWhichToBePasted').value;
            var ControlOnWhichToBePasted = $('#txtOnWhichToBePasted');

            //Paste the Text
            PasteTag(ControlOnWhichToBePasted, TextToBePasted);
        });
    });

//Function Pasting The Text
function PasteTag(ControlOnWhichToBePasted,TextToBePasted) {
    //Get the position where to be paste

    var CaretPos = 0;
    // IE Support
    if (document.selection) {

        ControlOnWhichToBePasted.focus();
        var Sel = document.selection.createRange();

        Sel.moveStart('character', -ctrl.value.length);

        CaretPos = Sel.text.length;
    }
    // Firefox support
    else if (ControlOnWhichToBePasted.selectionStart || ControlOnWhichToBePasted.selectionStart == '0')
        CaretPos = ControlOnWhichToBePasted.selectionStart;

    //paste the text
    var WholeString = ControlOnWhichToBePasted.value;
    var txt1 = WholeString.substring(0, CaretPos);
    var txt2 = WholeString.substring(CaretPos, WholeString.length);
    WholeString = txt1 + TextToBePasted + txt2;
    var CaretPos = txt1.length + TextToBePasted.length;
    ControlOnWhichToBePasted.value = WholeString;

    //update The cursor position 
    setCaretPosition(ControlOnWhichToBePasted, CaretPos);
}

function setCaretPosition(ControlOnWhichToBePasted, pos) {

    if (ControlOnWhichToBePasted.setSelectionRange) {
        ControlOnWhichToBePasted.focus();
        ControlOnWhichToBePasted.setSelectionRange(pos, pos);
    }
    else if (ControlOnWhichToBePasted.createTextRange) {
        var range = ControlOnWhichToBePasted.createTextRange();
        range.collapse(true);
        range.moveEnd('character', pos);
        range.moveStart('character', pos);
        range.select();
    }
}

</script>
Sunil K Behera -MindFire Sol-
źródło
3

Dodanie tekstu do aktualnej pozycji kursora obejmuje dwa kroki:

  1. Dodanie tekstu w aktualnej pozycji kursora
  2. Aktualizacja aktualnej pozycji kursora

Demo: https://codepen.io/anon/pen/qZXmgN

Przetestowano w Chrome 48, Firefox 45, IE 11 i Edge 25

JS:

function addTextAtCaret(textAreaId, text) {
    var textArea = document.getElementById(textAreaId);
    var cursorPosition = textArea.selectionStart;
    addTextAtCursorPosition(textArea, cursorPosition, text);
    updateCursorPosition(cursorPosition, text, textArea);
}
function addTextAtCursorPosition(textArea, cursorPosition, text) {
    var front = (textArea.value).substring(0, cursorPosition);
    var back = (textArea.value).substring(cursorPosition, textArea.value.length);
    textArea.value = front + text + back;
}
function updateCursorPosition(cursorPosition, text, textArea) {
    cursorPosition = cursorPosition + text.length;
    textArea.selectionStart = cursorPosition;
    textArea.selectionEnd = cursorPosition;
    textArea.focus();    
}

HTML:

<div>
    <button type="button" onclick="addTextAtCaret('textArea','Apple')">Insert Apple!</button>
    <button type="button" onclick="addTextAtCaret('textArea','Mango')">Insert Mango!</button>
    <button type="button" onclick="addTextAtCaret('textArea','Orange')">Insert Orange!</button>
</div>
<textarea id="textArea" rows="20" cols="50"></textarea>
Razan Paul
źródło
2

Myślę, że możesz użyć następującego JavaScript do śledzenia ostatniego pola tekstowego:

<script>
var holdFocus;

function updateFocus(x)
{
    holdFocus = x;
}

function appendTextToLastFocus(text)
{
    holdFocus.value += text;
}
</script>

Stosowanie:

<input type="textbox" onfocus="updateFocus(this)" />
<a href="#" onclick="appendTextToLastFocus('textToAppend')" />

Poprzednie rozwiązanie (rekwizyty do gclaghorn) używa textarea i oblicza również pozycję kursora, więc może być lepsze dla tego, co chcesz. Z drugiej strony ten byłby lżejszy, jeśli tego właśnie szukasz.

DreadPirateShawn
źródło
Dobry pomysł. Użyłem jquery, więc do każdego pola tekstowego, które miało określoną klasę, zastosowano to zdarzenie, zamiast umieszczać „onfocus = ...” w kodzie HTML każdego pola tekstowego. Ale dobre podejście :)
Kliknij „Upvote”
1

Zaakceptowana odpowiedź nie działała dla mnie w Internet Explorerze 9. Sprawdziłem to i wykrywanie przeglądarki nie działało poprawnie, wykryło ff (firefox), kiedy byłem w Internet Explorerze.

Właśnie dokonałem tej zmiany:

if ($.browser.msie) 

Zamiast:

if (br == "ie") { 

Wynikowy kod jest taki:

function insertAtCaret(areaId,text) {
    var txtarea = document.getElementById(areaId);
    var scrollPos = txtarea.scrollTop;
    var strPos = 0;
    var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ? 
        "ff" : (document.selection ? "ie" : false ) );

    if ($.browser.msie) { 
        txtarea.focus();
        var range = document.selection.createRange();
        range.moveStart ('character', -txtarea.value.length);
        strPos = range.text.length;
    }
    else if (br == "ff") strPos = txtarea.selectionStart;

    var front = (txtarea.value).substring(0,strPos);  
    var back = (txtarea.value).substring(strPos,txtarea.value.length); 
    txtarea.value=front+text+back;
    strPos = strPos + text.length;
    if (br == "ie") { 
        txtarea.focus();
        var range = document.selection.createRange();
        range.moveStart ('character', -txtarea.value.length);
        range.moveStart ('character', strPos);
        range.moveEnd ('character', 0);
        range.select();
    }
    else if (br == "ff") {
        txtarea.selectionStart = strPos;
        txtarea.selectionEnd = strPos;
        txtarea.focus();
    }
    txtarea.scrollTop = scrollPos;
}
Alvaro
źródło
1

Ta wtyczka jQuery daje ci gotowy sposób selekcji / manipulacji daszkiem.

Chris S.
źródło
0

możesz zaznaczyć tylko wymagane pole tekstowe i wstawić tam tekst. nie ma sposobu, aby dowiedzieć się, na czym skupia się AFAIK (może współdziałanie ze wszystkimi węzłami DOM?).

sprawdź ten stackoverflow - ma dla Ciebie rozwiązanie: Jak sprawdzić, który element DOM jest aktywny?

dusoft
źródło
0

Możliwość edycji treści, HTML lub dowolny inny element DOM

Jeśli próbujesz wstawić z daszkiem na a <div contenteditable="true">, staje się to znacznie trudniejsze, zwłaszcza jeśli w edytowalnym kontenerze znajdują się elementy podrzędne.

Miałem naprawdę wielkie szczęście korzystając z biblioteki Rangy :

Posiada mnóstwo wspaniałych funkcji, takich jak:

  • Zapisz pozycję lub wybór
  • Później przywróć pozycję lub zaznaczenie
  • Uzyskaj wybór HTML lub zwykły tekst
  • Wśród wielu innych

Demo online nie działało ostatnio, gdy sprawdzałem, jednak repozytorium ma działające wersje demonstracyjne. Aby rozpocząć, po prostu pobierz repozytorium z Git lub NPM, a następnie otwórz ./rangy/demos/index.html

To sprawia, że ​​praca z karetką i zaznaczaniem tekstu jest dziecinnie prosta!

factorypolaris
źródło
0

Odpowiedź na to pytanie została opublikowana tak dawno temu i natknąłem się na nią przez wyszukiwarkę Google. HTML5 udostępnia interfejs API HTMLInputElement, który zawiera metodę setRangeText () , która zastępuje zakres tekstu w elemencie <input>lub <textarea>nowym ciągiem znaków:

element.setRangeText('abc');

Powyższy zastąpi wybór dokonany wewnątrz elementz abc. Możesz również określić, która część wartości wejściowej ma zostać zastąpiona:

element.setRangeText('abc', 3, 5);

Powyższe zamieniłoby od 4 do 6 znaki wartości wejściowej na abc. Możesz również określić, w jaki sposób należy ustawić zaznaczenie po zamianie tekstu, podając jeden z następujących ciągów jako czwarty parametr:

  • 'preserve'próbuje zachować wybór. To jest ustawienie domyślne.
  • 'select' wybiera nowo wstawiony tekst.
  • 'start' przenosi zaznaczenie tuż przed wstawionym tekstem.
  • 'end' przenosi zaznaczenie tuż za wstawionym tekstem.

Zgodność z przeglądarkami

Strona MDN dla setRangeText nie dostarcza danych dotyczących zgodności przeglądarek, ale myślę, że byłaby taka sama jak HTMLInputElement.setSelectionRange () , czyli w zasadzie wszystkie nowoczesne przeglądarki, IE 9 i nowsze , Edge 12 i nowsze .

A. Genedy
źródło