Zack105 Zack105 - 1 month ago 17
Javascript Question

Restore cursor position after .replace()

I'm making a phonetic keyboard- type in English, and it translates to the corresponding Ukrainian characters. However, some Ukrainian characters have complex sounds (ones that need to be represented by more than one English letter- for example, "ch")

So, when a user types "ch", the script replaces that with one character. However, since "c" and "h" translate into other sounds, it's a bit more complex. Say "c" translates to "1", and "h" translates into "2". So, instead of replacing "ch", I replace "12". (That's why I have unicode in the replace instead of characters.

My biggest problem is that after it's replaced, the cursor defaults to the end of the textarea. That's no issue if I'm typing, but if I'm going back and editing, it's really annoying. Here's what I tried (the id of the textarea is "area")

var el = e.area;

position = el.selectionStart; // Capture initial position

el.value = el.value.replace('\u0418\u0410', '\u042F');
el.selectionEnd = position; // Set the cursor back to the initial position.

Answer

You can try the following code snippet. In its current form, it replaces == with +, but it allows to replace any string with another one, shorter or longer.

In order to maintain the cursor position, you have to save and restore the selectionStart and the selectionEnd. An offset is calculated to account for the difference in length between the two strings, and the number of occurrences before the cursor.

The use of setTimeout ensures that the newly typed character has been inserted in the text before doing the processing.

var area = document.getElementById("area");

var getCount = function (str, search) {
    return str.split(search).length - 1;
};

var replaceText = function (search, replaceWith) {
    if (area.value.indexOf(search) >= 0) {
        var start = area.selectionStart;
        var end = area.selectionEnd;
        var textBefore = area.value.substr(0, end);
        var lengthDiff = (replaceWith.length - search.length) * getCount(textBefore, search);
        area.value = area.value.replace(search, replaceWith);
        area.selectionStart = start + lengthDiff;
        area.selectionEnd = end + lengthDiff;
    }
};

area.addEventListener("keypress", function (e) {
    setTimeout(function () {
        replaceText("==", "+");
    }, 0)
});
<textarea id="area" cols="40" rows="8"></textarea>

Comments