2

I'm building a programmable calculator that uses a contenteditable div as a place to enter the expression you need evaluated. The div listens for the user to strike the return key, then passes its text content to the calculator engine, clears itself, and then displays the result of the expression.

Everything works as expected on desktop browsers, but under mobile browsers, there is some strange behaviour when the return key is pressed when the caret is not at the end of the text. Sometimes hitting the return key will insert a space or newline, sometimes it will submit and clear everything before the caret, and under Chrome it seems to create a new div element. Any ideas what I'm doing wrong?

I have successfully tested the code in Firefox 59.0.2 and Chromium 65.0.3325.181 running on Ubuntu 17.10, and Firefox 59.0.2 running on Windows 7. I have unsuccessfully tested the code in Firefox 59.0.2 and Chrome 65.0.3325.109 running on Android 8.1.0.

window.addEventListener("load", function () {
    "use strict";

    var i = document.getElementById("i");
    var o = document.getElementById("o");

    i.addEventListener("keypress", function (e) {
        if (e.key === "Enter") {
            e.preventDefault();

            o.textContent = i.textContent;
            i.textContent = "";

            return false;
        }
        return true;
    });
});
div {
    font-size: 24px;
    padding: 1em;
    border: 1px solid black;
    min-height: 1em;
    box-sizing: content-box;
    margin: 1em;
}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=0">
        <title>Test</title>
    </head>

    <body>
        <div id="i" contenteditable="true"></div>
        <div id="o"></div>
    </body>
</html>

Demo of what happens on mobile

EDIT:

After some work, I've made an alternate method of detecting input, copying the text, and clearing the box. It no longer listens for keystrokes but watches for changes in the box itself. It works on desktop but fails in similar ways on mobile. It also has the added problem that it will crash Firefox mobile if you type too quickly. I've tested the code on the same browsers as before.

window.addEventListener("load", function () {
    "use strict";

    var i = document.getElementById("i");
    var o = document.getElementById("o");
    var getText;
    var input;

    getText = function (e) {
        var s = [];

        e.childNodes.forEach(function (n) { // get every child
            switch (n.nodeType) {
            case 1: // element, so recurse
                s.push(getText(n));
                break;
            case 3: // text
                s.push(n.nodeValue);
                break;
            }
        });

        return s.join("");
    };

    input = function (e) {
        if (i.childNodes.length > 1  || (i.firstChild && i.firstChild.nodeType != 3)) { // checking for added <br />
            e.preventDefault();

            o.textContent = getText(i);
            while (i.firstChild) { // clear element
                i.removeChild(i.firstChild);
            }

            // add and remove listener to prevent event from firing on clear
            i.removeEventListener("input", input);
            setTimeout(function () {
                i.addEventListener("input", input, true);
            }, 100);

            return false;
        }
        return true;
    };

    i.addEventListener("input", input, true);
});
div {
    font-size: 24px;
    padding: 1em;
    border: 1px solid black;
    min-height: 1em;
    box-sizing: content-box;
    margin: 1em;
}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=0">
        <title>Test</title>
    </head>

    <body>
        <div id="i" contenteditable="true"></div>
        <div id="o"></div>
    </body>
</html>

EDIT 2 (with workaround):

After some thinking, I realized I don't need to use a contenteditable div, so I've re-worked it to use a styled text input field which works properly.

window.addEventListener("load", function () {
    "use strict";

    var f = document.getElementById("f");
    var i = document.getElementById("i");
    var o = document.getElementById("o");

    f.addEventListener("submit", function (e) {
        e.preventDefault();

        o.textContent = i.value;
        i.value = "";

        return false;
    });
});
input[type="text"] {
    display: block;
    width: 100%;
    overflow: auto;
    outline: none;
    border: none;
    border-radius: 0;
    box-shadow: none;
    box-sizing: content-box;
}

#i, div {
    width: calc(100% - 4em - 2px);
    min-height: 1em;
    font-size: 24px;
    padding: 1em;
    border: 1px solid black;
    min-height: 1em;
    margin: 1em;
    color: black;
    font-family: serif;
}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=0">
        <title>Test</title>
    </head>

    <body>
        <form id="f" name="f">
            <input id="i" name="i" type="text" >
        </form>
        <div id="o"></div>
    </body>
</html>
Phinet
  • 527
  • 3
  • 14
  • `console.log` `e.key` and see what it logs when you press the enter key. – ibrahim mahrir Apr 09 '18 at 23:36
  • 1
    Also I advise you to use `e.keyCode === 13` instead of `e.key === "Enter"` as the latter is [**not supported**](https://stackoverflow.com/questions/39982279/e-key-is-not-supported-in-most-browser) by some browsers. – ibrahim mahrir Apr 09 '18 at 23:40
  • On desktop, on every keypress, e.key logs to the correct name of the key, "Enter" when you hit the return key. Strangely, under mobile, not every keypress logs something, only the return key consistently working (still "Enter"). That seems to suggest the event does not fire with every keypress. – Phinet Apr 09 '18 at 23:46
  • BTW, I've just noticed, use `keydown` instead of `keypress`. – ibrahim mahrir Apr 09 '18 at 23:52
  • Using `keydown` doesn't seem to have an effect – Phinet Apr 09 '18 at 23:57
  • [**Weird! I was kind of certain it will work.**](https://stackoverflow.com/questions/3396754/onkeypress-vs-onkeyup-and-onkeydown) – ibrahim mahrir Apr 09 '18 at 23:59

0 Answers0