mdn / content

The content behind MDN Web Docs
https://developer.mozilla.org
Other
9k stars 22.44k forks source link

`onerror` (and others) missing from HTMLBodyElement "Event Handlers" section #34684

Open jdfm opened 2 weeks ago

jdfm commented 2 weeks ago

MDN URL

https://developer.mozilla.org/en-US/docs/Web/API/HTMLBodyElement

What specific section or headline is this issue about?

Event handlers

What information was incorrect, unhelpful, or incomplete?

The list in this section is incomplete. onerror is not listed, for example.

What did you expect to see?

onerror should be shown as one of the cases (along with a few others, see attached code).

Do you have any supporting links, references, or citations?

Notice that in the page documenting onerror on the window it mentions HTML event handler attributes, which wouldn't be possible to assign if not via the document's body.

Also of interest is the content found in the WHATWG HTML Standard that lists the body specifically as an alias for a number of window events which clued me to the possibility that onerror would be one of these cases (along with that MDN notice above), even if it isn't explicitly listed as such on this page.

Do you have anything more you want to share?

When running the following code we can get a fuller list of aliased events:

const checkAliasedEvents = (a = document.body, b = window) => {
    const aliases = []

    for (const key in a) {
        if (!key.startsWith('on')) continue;
        if (a[key] !== b[key]) continue;
        a[key] = () => {}
        if (a[key] === b[key]) aliases.push(key)
    }

    return aliases.sort()
}

console.log(checkAliasedEvents())

There are a few entries beyond onerror, that are listed when running the code above, that are not listed on the HTMLBodyElement page.

The list will only contain the events that the current browser actually supports, for example, theongamepadconnected event only showed up in Firefox, and not in Chrome. That being said, onerror showed up in both.

MDN metadata

Page report details * Folder: `en-us/web/api/htmlbodyelement` * MDN URL: https://developer.mozilla.org/en-US/docs/Web/API/HTMLBodyElement * GitHub URL: https://github.com/mdn/content/blob/main/files/en-us/web/api/htmlbodyelement/index.md * Last commit: https://github.com/mdn/content/commit/387d0d4d8690c0d2c9db1b85eae28ffea0f3ac1f * Document last modified: 2023-02-20T04:32:55.000Z
jdfm commented 2 weeks ago

I tested my code on MacOS Sonoma 14.5 with the browser versions listed below.

On Chrome v126.0.6478.127:

[ "onafterprint", "onbeforeprint", "onbeforeunload", "onblur", "onerror", "onfocus", "onhashchange", "onlanguagechange", "onload", "onmessage", "onmessageerror", "onoffline", "ononline", "onpagehide", "onpageshow", "onpopstate", "onrejectionhandled", "onresize", "onscroll", "onstorage", "onunhandledrejection", "onunload" ]

And on Firefox v127.0.2:

[ "onafterprint", "onbeforeprint", "onbeforeunload", "onblur", "onerror", "onfocus", "ongamepadconnected", "ongamepaddisconnected", "onhashchange", "onlanguagechange", "onload", "onmessage", "onmessageerror", "onoffline", "ononline", "onpagehide", "onpageshow", "onpopstate", "onrejectionhandled", "onresize", "onscroll", "onstorage", "onunhandledrejection", "onunload" ]

And on Safari v17.5:

[ "onafterprint", "onbeforeprint", "onbeforeunload", "onblur", "onerror", "onfocus", "ongamepadconnected", "ongamepaddisconnected", "onhashchange", "onlanguagechange", "onload", "onmessage", "onmessageerror", "onoffline", "ononline", "onpagehide", "onpageshow", "onpopstate", "onrejectionhandled", "onresize", "onscroll", "onstorage", "onunhandledrejection", "onunload" ]
Josh-Cena commented 1 week ago

Hi! Actually the document is correct. This page documents the event handlers that have special support on HTMLBodyElement. You can list them all using Object.getOwnPropertyNames(HTMLBodyElement.prototype).filter((x) => x.startsWith("on")). This list is in the spec here: https://html.spec.whatwg.org/multipage/sections.html#the-body-element

On the other hand, note that we have the following sentence:

The HTMLElement events are inherited.

If you go to the HTMLElement page, you will see the error event there. This is consistent with two facts:

  1. onerror is a global attribute that can be applied to any HTML element
  2. This property is defined on HTMLElement.prototype, not on HTMLBodyElement.prototype

Therefore the current documentation is accurate, and onerror is in fact not what the HTMLBodyElement should talk about, because it's not "[an] onXYZ event handler property also available as aliases targeting the window object"; it's actually an event handler for errors that bubble up to the body element, or error events generated by the body element itself.

jdfm commented 1 week ago

Hello @Josh-Cena , thanks for responding!

So, the code I provided in this issue assigns event handlers on the body element's event handler properties and then checks if the window now has the exact same handler (without an explicit assignment on the window) for the same event handler property. The lists I provided here show the cases where there was a match between the body and the window for different browsers.

Since we're not assigning these event handlers on the prototype, it seems to me that the mechanism that's transporting these event handlers onto the window would be the aliasing mechanism, no?

Also, the event handler attribute for onerror on the body element matches a number of details that were explained for the window objects onerror event handler property, whereas the onerror for something like an img doesn't.

I guess what I'm calling out in part is a difference between what's documented as being the case in the standards, and what currently is the case in browsers.

Josh-Cena commented 1 week ago

Note that even if you have never set an event listener, things like onerror, onscroll, etc. will always exist on objects that support them. If onXYZ does not exist, it does not mean that no event listeners are attached; it either means events of this type are never heard here, or the event does not support adding listeners with onXYZ (i.e. only addEventLisnter style, but I'm not aware of such a case). There's no magic with onXYZ properties: they are setter properties that, when set, register a corresponding event listener. I guess you started with a wrong assumption with what "onerror exists on window" means.

Josh-Cena commented 1 week ago

Actually you are correct—onerror is a Window-reflecting body element event handler, so it does proxy-handle window events instead of the HTML tree events!

I'm not sure how we should document this—the event delegation between window/document/body is very complex and we do a very bad job at capturing the different sets of events.