w3c / uievents

UI Events
https://w3c.github.io/uievents/
Other
147 stars 52 forks source link

Should require Input event to be fired within same event loop as keydown? keypress? neither? #238

Open dbates-wk opened 5 years ago

dbates-wk commented 5 years ago

Create a page with the following markup:

<!DOCTYPE html>
<html>
<body>
<p>Focus the text field below. Then press a key on the keyboard. The output will be the value of the field seen one event loop turn after the listed event dispatched.</p>
<input id="input">
<pre id="console"></pre>
<script>
// Note that scheduling a timer from an Input event handler is for aesthetics only: to make the
// logged Input event be ordered like the spec'ed DOM dispatch event order. By the time the Input
// event fires the DOM is guaranteed to have been updated. So, no timer is needed.
let input = document.getElementById("input");
for (let eventName of ["keydown", "keypress", "keyup", "input"]) {
    input.addEventListener(eventName, (event) => {
        window.setTimeout(() => {
            log(`${eventName}: ${input.value}`);
        }, 0);
    });
}

function log(message)
{
    document.getElementById("console").appendChild(document.createTextNode(message + "\n"));
}
</script>
</body>
</html>

Open ^^^ in your browser and follow the instructions. I'm seeing different things in different browsers™.

In Mac Firefox 67.0.4 I see, emphasis mine:

keydown: 
keypress: a
input: a
keyup: a

On iOS, I see the following (with auto capitalization is off under Settings > General > Keyboard > Hardware Keyboard), emphasis mine:

keydown: 
keypress: 
input: a
keyup: a

In Mac Safari and Chrome Canary for Mac version 77.0.3847.0, emphasis mine:

keydown: a
keypress: a
input: a
keyup: a

For the last two browsers above what is happening is that text insertion (i.e. a DOM update) is occurring within the same event loop as the the keydown.

Spec makes no mention that DOM update must occur in same event loop as keydown or keypress (that's what Firefox is doing). Spec only guarantees DOM is updated when input event is dispatched.

Real-world examples

I know of two sites that assume DOM is updated on keypress:

  1. Google Sheets

Repro steps: Create a new sheet. Tap on a cell. Type into it. Formula bar is updated with DOM value of cell on timer scheduled from keypress (read: not input event).

  1. Bitbucket Server (formerly known as Stash)

Repro steps: In a pull request comment, type @. Bitbucket schedules a timer on keypress and expects text insertion (i.e DOM update) when timer fires so that when it reads <textarea>'s value it will see the typed @ and trigger its suggestion UI.

What to do?

What is the expected behavior? Should spec require DOM be updated for text insertion/deletion in same event loop iteration that keydown is dispatched? same event loop iteration that keypress is dispatched? Should we keep the current spec text with no such requirement? Should we spec out explicitly that there is no such requirement?

dbates-wk commented 5 years ago

@garykac @travisleithead @othermaciej @hober @smfr

dbates-wk commented 5 years ago

@annevk

dbates-wk commented 5 years ago

Update: Mac Firefox 67.0.4 is non-deterministic.

Sometimes it is, emphasis mine:

keydown: 
keypress: a
input: a
keyup: a

and sometimes it is:

keydown: a
keypress: a
input: a
keyup: a
annevk commented 5 years ago

I do think we should spec this. In particular, there's some kind of abstract "key down operation" that user agents have to support which at some point queues a task to do various things (e.g., dispatching the event, handling whether it was canceled if appropriate?, mutating the DOM?, etc.).

See also #142.

(Think of "key down operation" as an abstract representation of the input you get from the OS / "kernel". Perhaps that's not actually "key down" in which case it should be adjusted somewhat. I haven't looked into this recently.)

garykac commented 4 years ago

I started working on a more formal algorithm for dispatching keyboard/input/composition events. It's in the early stages and is far from complete, but my goal is to be able to specify these behaviors enough to address your concerns.

https://docs.google.com/document/d/1LJQvjEmWZGzVgZnofpvdkxMj1hEnLniD72XD4DLJWx4/edit?usp=sharing

Note that we won't be defining any behaviors relative to keypress because that event has been deprecated.

annevk commented 4 years ago

Is it realistic to expect that it can be removed?

garykac commented 4 years ago

Hmm.. I guess I was answering the question from the title "should input be in same event loop as keypress" with "we could define input in same loop as keydown; and keypress in same loop as keydown" (or something like that) so that the definitions are relative to non-deprecated events.

But once there's a proper algorithm, then it doesn't make sense to think of it that way. Since it would be written more like:

Sorry about the confusion there. To more directly answer your question, we can't remove keypress and it needs to be included in the spec, I just want to ensure that it can (in theory) be removed without breaking the spec.