DEV Community

Nam Phạm
Nam Phạm

Posted on

Emoticons to emojis again, with live typing

Last time, I covered Using string's replaceAll function to convert emoticons into emojis 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

<!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>
Enter fullscreen mode Exit fullscreen mode

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

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'));
});
Enter fullscreen mode Exit fullscreen mode

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^^

Top comments (0)