Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add focusin and focusout events #10235

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 58 additions & 12 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -13135,6 +13135,8 @@ https://software.hixie.ch/utilities/js/live-dom-viewer/?%3C%21DOCTYPE%20HTML%3E%
<li><code data-x="handler-onended">onended</code></li>
<li><code data-x="handler-onerror">onerror</code>*</li>
<li><code data-x="handler-onfocus">onfocus</code>*</li>
<li><code data-x="handler-onfocusin">onfocusin</code>*</li>
<li><code data-x="handler-onfocusout">onfocusout</code>*</li>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This * means that they belong to the "Window-reflecting body element event handler set" instead of being the normal list at the top of https://whatpr.org/html/10235/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects .

Can you confirm that difference is tested? (I'm honestly not sure exactly how you would test, this will take a bit of research. Or maybe change something in the implementation and see if any tests start failing.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I see that for example onclick is in the first table and onfocus is in the second one.
I made a quick test page, and it would seem that document.body doesn't do onfocus, but it does to onclick, and that was the only difference that I found.

Does that match up with your understanding?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the difference in your test is due to the difference between click being bubbling and focus not.

The example below https://html.spec.whatwg.org/#the-body-element:window-reflecting-body-element-event-handler-set seems to have a possible test case at least for bubbling events.

I bet in Chromium there's some list hidden somewhere for the special ones.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, here it is: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/html_body_element.cc;l=115-216;drc=c0c69be50d661fd4952865e0aaf76952d9272f17
These are just for when they're set as HTML attributes rather than element.onfocusin which I am trying to implement in chromium to match safari.
It looks like chromium already implements onfocusin as an HTML attribute, but it is not included in the special body->window logic that onfocus has: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/html_element.cc;l=481-482;drc=040547c1a7d0987ca63e18ca010986113637bf51

So I guess that we should put onfocusin/onfocusout in the list that onfocus is not in? So I should remove that asterisk?

I also made a test page here, but the results only made me confused: https://jsfiddle.net/jarhar/84jLcptn/5/

Screenshot 2024-04-02 at 5 09 28 PM Screenshot 2024-04-02 at 5 11 08 PM

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I guess that we should put onfocusin/onfocusout in the list that onfocus is not in? So I should remove that asterisk?

Yes, I think that makes the most sense.

For testing, I figured out what we can do.

If you look at https://github.com/web-platform-tests/wpt/blob/master/html/webappapis/scripting/events/resources/event-handler-body.js , it pulls a list of all event handlers from the html.idl file. It then uses the windowReflectingBodyElementEventHandlerSet declaration to test how they should behave.

So, if we decide these should be in the "normal" list, we do no work. Updating the spec will eventually cause html.idl in the WPT repo to update, which will automatically make those tests start testing the right thing.

For your implementation, to verify everything is working correctly, you can modify the html.idl file locally, and make sure the tests still pass. When I do that right now, Chromium does not yet pass, I'd guess because the content attribute reflection isn't implemented. If you can confirm your patch makes such a local change pass, then I'll feel confident about our test coverage.

<li><code data-x="handler-onformdata">onformdata</code></li>
<li><code data-x="handler-oninput">oninput</code></li>
<li><code data-x="handler-oninvalid">oninvalid</code></li>
Expand Down Expand Up @@ -79840,9 +79842,17 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {
target</var> be null.</p></li>

<li>
<p>If <var>blur event target</var> is not null, <span>fire a focus event</span>
named <code data-x="event-blur">blur</code> at <var>blur event target</var>, with
<var>related blur target</var> as the related target.</p>
<p>If <var>blur event target</var> is not null:</p>

<ol>
<li><p><span>Fire a focus event</span> named <code data-x="event-blur">blur</code> at
<var>blur event target</var>, with <var>related blur target</var> as the related target and
bubbles set to false.</p></li>

<li><p><span>Fire a focus event</span> named <code data-x="event-focusout">focusout</code> at
<var>blur event target</var>, with <var>related blur target</var> as the related target and
bubbles set to true.</p></li>
</ol>

<p class="note" id="note-sometimes-no-blur-event">In some cases, e.g., if <var>entry</var> is
an <code>area</code> element's shape, a scrollable region, or a <span>viewport</span>, no
Expand Down Expand Up @@ -79890,9 +79900,17 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {
focus target</var> be null.</p></li>

<li>
<p>If <var>focus event target</var> is not null, <span>fire a focus event</span>
named <code data-x="event-focus">focus</code> at <var>focus event target</var>, with
<var>related focus target</var> as the related target.</p>
<p>If <var>focus event target</var> is not null:</p>

<ol>
<li><p><span>Fire a focus event</span> named <code data-x="event-focus">focus</code> at
<var>focus event target</var>, with <var>related focus target</var> as the related target and
bubbles set to false.</p></li>

<li><p><span>Fire a focus event</span> named <code data-x="event-focusin">focusin</code> at
<var>focus event target</var>, with <var>related focus target</var> as the related target and
bubbles set to true.</p></li>
</ol>

<p class="note">In some cases, e.g. if <var>entry</var> is an <code>area</code>
element's shape, a scrollable region, or a <span>viewport</span>, no event is fired.</p>
Expand All @@ -79902,12 +79920,12 @@ dictionary <dfn dictionary>ToggleEventInit</dfn> : <span>EventInit</span> {
</ol>

<p>To <dfn>fire a focus event</dfn> named <var>e</var> at an element <var>t</var> with a given
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make this more of a normal algorithm declaration:

To fire a focus event named event at an element target given an element relatedTarget and an optional boolean bubbles (default false), ...

And then update call sites to uniformly be either

[fire a focus event] named foo at bar given baz

or

[fire a focus event] named foo at bar given baz and true

related target <var>r</var>, <span data-x="concept-event-fire">fire an event</span> named
<var>e</var> at <var>t</var>, using <code>FocusEvent</code>, with the <code
related target <var>r</var> and bubbles <var>b</var>, <span data-x="concept-event-fire">fire an
event</span> named <var>e</var> at <var>t</var>, using <code>FocusEvent</code>, with the <code
data-x="dom-FocusEvent-relatedTarget">relatedTarget</code> attribute initialized to <var>r</var>,
the <code data-x="dom-UIEvent-view">view</code> attribute initialized to <var>t</var>'s
<span>node document</span>'s <span>relevant global object</span>, and the <span>composed
flag</span> set.</p>
the <code data-x="dom-UIEvent-view">view</code> attribute initialized to <var>t</var>'s <span>node
document</span>'s <span>relevant global object</span>, the <span>composed flag</span> set, and
<code data-x="dom-Event-bubbles">bubbles</code> attribute initialized to <var>b</var>.</p>

<hr>

Expand Down Expand Up @@ -111388,6 +111406,8 @@ typedef <span>OnBeforeUnloadEventHandlerNonNull</span>? <dfn typedef>OnBeforeUnl
<tr><td><dfn attribute for="GlobalEventHandlers"><code data-x="handler-onblur">onblur</code></dfn> <td> <code data-x="event-blur">blur</code> <!-- widely used -->
<tr><td><dfn attribute for="GlobalEventHandlers"><code data-x="handler-onerror">onerror</code></dfn> <td> <code data-x="event-error">error</code>
<tr><td><dfn attribute for="GlobalEventHandlers"><code data-x="handler-onfocus">onfocus</code></dfn> <td> <code data-x="event-focus">focus</code> <!-- widely used -->
<tr><td><dfn attribute for="GlobalEventHandlers"><code data-x="handler-onfocusin">onfocusin</code></dfn> <td> <code data-x="event-focusin">focusin</code>
<tr><td><dfn attribute for="GlobalEventHandlers"><code data-x="handler-onfocusout">onfocusout</code></dfn> <td> <code data-x="event-focusout">focusout</code>
<tr><td><dfn attribute for="GlobalEventHandlers"><code data-x="handler-onload">onload</code></dfn> <td> <code data-x="event-load">load</code>
<tr><td><dfn attribute for="GlobalEventHandlers"><code data-x="handler-onresize">onresize</code></dfn> <td> <code data-x="event-resize">resize</code>
<tr><td><dfn attribute for="GlobalEventHandlers"><code data-x="handler-onscroll">onscroll</code></dfn> <td> <code data-x="event-scroll">scroll</code>
Expand Down Expand Up @@ -111494,6 +111514,8 @@ typedef <span>OnBeforeUnloadEventHandlerNonNull</span>? <dfn typedef>OnBeforeUnl
attribute <span>EventHandler</span> <span data-x="handler-onended">onended</span>;
attribute <span>OnErrorEventHandler</span> <span data-x="handler-onerror">onerror</span>;
attribute <span>EventHandler</span> <span data-x="handler-onfocus">onfocus</span>;
attribute <span>EventHandler</span> <span data-x="handler-onfocusin">onfocusin</span>;
attribute <span>EventHandler</span> <span data-x="handler-onfocusout">onfocusout</span>;
attribute <span>EventHandler</span> <span data-x="handler-onformdata">onformdata</span>;
attribute <span>EventHandler</span> <span data-x="handler-oninput">oninput</span>;
attribute <span>EventHandler</span> <span data-x="handler-oninvalid">oninvalid</span>;
Expand Down Expand Up @@ -140506,6 +140528,18 @@ interface <dfn interface>External</dfn> {
<td> <code data-x="event-focus">focus</code> event handler
<td> <span data-x="event handler content attributes">Event handler content attribute</span>

<tr>
<th id="ix-handler-onfocusin"> <code data-x="">onfocusin</code>
<td> <span data-x="handler-onfocusin">HTML elements</span>
<td> <code data-x="event-focusin">focusin</code> event handler
<td> <span data-x="event handler content attributes">Event handler content attribute</span>

<tr>
<th id="ix-handler-onfocusout"> <code data-x="">onfocusout</code>
<td> <span data-x="handler-onfocusout">HTML elements</span>
<td> <code data-x="event-focusout">focusout</code> event handler
<td> <span data-x="event handler content attributes">Event handler content attribute</span>

<tr>
<th id="ix-handler-onformdata"> <code data-x="">onformdata</code>
<td> <span data-x="handler-onformdata">HTML elements</span>
Expand Down Expand Up @@ -141439,7 +141473,19 @@ INSERT INTERFACES HERE
<td> <dfn event for="Window,HTMLElement"><code data-x="event-focus">focus</code></dfn>
<td> <code>Event</code>
<td> <code>Window</code>, elements
<td> Fired at nodes <span data-x="gains focus">gaining focus</span>
<td> Fired at nodes <span data-x="gains focus">gaining focus</span> without bubbling

<tr> <!-- focusin -->
<td> <dfn event for="Window,HTMLElement"><code data-x="event-focusin">focusin</code></dfn>
<td> <code>Event</code>
<td> <code>Window</code>, elements
<td> Fired at nodes <span data-x="gains focus">gaining focus</span> after the <code data-x="event-focus">focus</code> event with bubbling

<tr> <!-- focusout -->
<td> <dfn event for="Window,HTMLElement"><code data-x="event-focusout">focusout</code></dfn>
<td> <code>Event</code>
<td> <code>Window</code>, elements
<td> Fired at nodes when they stop being <span>focused</span> after the <code data-x="event-blur">blur</code> event with bubbling

<tr> <!-- formdata -->
<td> <dfn event for="HTMLElement"><code data-x="event-formdata">formdata</code></dfn>
Expand Down
Loading