Emoticons to emojis again, with live typing
Tags: javascript, emoticons, emojis, fun
Published: 2021-10-29 14:22:33

Last time, I covered [Using string's replaceAll function to convert emoticons into emojis](https://dev.to/namdx1987/using-strings-replaceall-function-to-convert-emoticons-into-emojis-7b8) and hope you enjoy. This time, we improve the functionality with live typing emoticons upon `<input/>` or `<textarea/>` will result in emojis. As you can see, in many situations, this live typing is much more pleasant then having to convert the whole text to emojis so here we go. 

## The code
### The UI
Copy the code here to your main html file
```html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, viewport-fit=cover" />
        <meta name="apple-mobile-web-app-capable" content="yes" />
        <title>Emoticons to Emojis</title>
        <script src="regex.js"></script>
        <script src="run.js"></script>
    </head>
    <body>
        <h1>Emoticons to Emojis live typing
        </h1>
        <p>Type emoticons in the textarea below to see emojis :D</p>
        <div>
            <textarea id="live" rows="10" cols="80"></textarea>
        </div>
    </body>
</html>
```

### Get the helper library

My script I write use a regex builder from https://github.com/wyantb/js-regex so grab the script file at https://github.com/wyantb/js-regex/raw/master/regex.js and put it into directory. Its name is regex.js as referenced by the html.

### Create the main script file

Create a `run.js` file and copy the following code to it
```javascript
let emoticons = {
    "(:": "🙃",
    ":)": "🙂",
    ":')": "🥲",
    ":))": "😂",
    "=))": "🤣",
    ";)": "😉",
    ":D": "😀",
    ":P": "😋",
    "B)": "😎",
    ":*": "😗",
    ":(": "🙁",
    ":'(": "😥",
    ":((": "😭",
    ":o": "😮",
    ">:(": "😠",
    ">:-(": "😡",
}

const pattern = (function () {
    let r = regex.create().either();
    let cmp = function (a, b) {
        let d = a.length - b.length;

        if (d)
            return -d;

        if (a < b)
            return -1;

        if (a > b)
            return 1;

        return 0;
    }

    for (let key of Object.keys(emoticons).sort(cmp))
        r.literals(key)

    return new RegExp(r.endEither().peek(), "gu");
})();

const mlength = (function () {
    let m = 0;

    for (let key of Object.keys(emoticons))
        if (key.length > m)
            m = key.length;

    return ++m;
})();

function getEmoji(emoticon) {
    if (emoticon in emoticons)
        return emoticons[emoticon];

    return "";
}

function cvE2E(str) {
    return str.replaceAll(pattern, getEmoji)
}

function handleInput(e) {
    if (e.type == "input" && e.inputType == "insertText" && e.data == " ") {
        let input = e.target;
        let start = Math.max(input.selectionEnd - mlength, 0) | 0;

        input.setSelectionRange(start, input.selectionEnd);

        let replaced = cvE2E(input.value.substring(start, input.selectionEnd));

        input.setRangeText(replaced, start, input.selectionEnd, 'end');
    }
}

function install(input) {
    input.addEventListener('input', handleInput);
}

document.addEventListener('DOMContentLoaded', function () {
    install(document.getElementById('live'));
});
```

## Understand how it works 
To do live typing emoticons to emojis, we will have to attach a listener to the `input` event of the `input` or `textarea`, thus the `install` and `handleInput` functions. Every time user inputs a blank space, we will extract the text, convert any emoticons found to emojis and put it back into the element. About the replacing, you can read my previous article (link above) to grab the main idea. This time, the idea is basically the same but we have to do a little trick to improve the performance. Rather than extract the whole text, we will extract a short sub string from input position indicated by the `selectionEnd` property. To know the length, we will have to iterate through the `emoticons` object's keys to find the max length of the emoticons (remember to increase it to 1 to also count the blank space inserted) and store it to the `mlength` constant. So now, when user insert a blank space, just extract the sub string with `mlength` characters from the inserted position backward and do the replacement. After that, just put the text back and you have the live typing result.

Again, hope you enjoy the article and have fun typing emoticons^^