Closed dontcallmedom closed 2 years ago
some very rough check on which specs links to cancelable
and bubbles
:
webref/ed/links$ grep -l dom-event-cancelable *
app-history.json
close-watcher.json
cookie-store.json
event-timing.json
html.json
IndexedDB-3.json
keyboard-map.json
notifications.json
pointerevents3.json
service-workers-1.json
uievents.json
xhr.json
webref/ed/links$ grep -l dom-event-bubbles *
cookie-store.json
CSP3.json
fullscreen.json
html.json
IndexedDB-3.json
keyboard-map.json
picture-in-picture.json
pointerevents3.json
serial.json
uievents.json
web-bluetooth.json
xhr.json
(curtesy of rg -A1 "Cancelable" files/en-us/web/api/*/**event/index.md|grep "Yes"
in a checkout of mdn/content)
(curtesy of rg -A1 "Bubbles" files/en-us/web/api/*/**event/index.md|grep "Yes"
in a checkout of mdn/content)
filed https://github.com/mdn/content/pull/10006 while exploring cancelability of DOMContentLoaded
my exploration here focused on bubbles/cancelability; but a maybe simpler and maybe more directly useful extraction would be tie event handlers with the interface of the events they generate (see https://github.com/w3c/webref/issues/469). This may be possible by going through extracted definitions with the event
type and their for
scope, or through some less formally reliable heuristics.
I think this would be very useful. I'd see it as a list of event types (the event.type
string) with the following information for each:
Because some event types like "error" are used a lot there would be repeated types. I would not suggest organizing this around event targets instead, because there are events that are arguably the same but just fire on multiple targets, and keeping them together retains that information. The "change" event fired at AudioTrackList
or VideoTrackList
is an example of this. https://html.spec.whatwg.org/#common-input-element-events has additional examples.
[ { "type": "backgroundfetchsuccess", "interfaces": [ "ServiceWorkerGlobalScope" ] }, { "type": "backgroundfetchfail", "interfaces": [ "ServiceWorkerGlobalScope" ] }, { "type": "backgroundfetchabort", "interfaces": [ "ServiceWorkerGlobalScope" ] }, { "type": "backgroundfetchclick", "interfaces": [ "ServiceWorkerGlobalScope" ] }, { "type": "progress", "interfaces": [ "BackgroundFetchRegistration" ] }, { "type": "cancel", "interfaces": [ "CloseWatcher" ] }, { "type": "close", "interfaces": [ "CloseWatcher" ] }, { "type": "contentdelete", "interfaces": [ "ServiceWorkerGlobalScope" ] }, { "type": "animationstart", "interfaces": [ "animationevent" ] }, { "type": "animationend", "interfaces": [ "animationevent" ] }, { "type": "animationiteration", "interfaces": [ "animationevent" ] }, { "type": "animationcancel", "interfaces": [ "animationevent" ] }, { "type": "loading", "interfaces": [ "FontFaceSet" ] }, { "type": "loadingdone", "interfaces": [ "FontFaceSet" ] }, { "type": "loadingerror", "interfaces": [ "FontFaceSet" ] }, { "type": "navbeforefocus", "interfaces": [ "NavigationEvent" ] }, { "type": "navnotarget", "interfaces": [ "NavigationEvent" ] }, { "type": "change", "interfaces": [ "MediaQueryList" ] }, { "type": "resize", "interfaces": [ "Window" ] }, { "type": "scroll", "interfaces": [ "Document", "Element" ] }, { "type": "transitionrun", "interfaces": [ "transitionevent" ] }, { "type": "transitionstart", "interfaces": [ "transitionevent" ] }, { "type": "transitionend", "interfaces": [ "transitionevent" ] }, { "type": "transitioncancel", "interfaces": [ "transitionevent" ] }, { "type": "abort", "interfaces": [ "AbortSignal" ] }, { "type": "loadstart", "interfaces": [ "FileReader" ] }, { "type": "progress", "interfaces": [ "FileReader" ] }, { "type": "abort", "interfaces": [ "FileReader" ] }, { "type": "error", "interfaces": [ "FileReader" ] }, { "type": "load", "interfaces": [ "FileReader" ] }, { "type": "loadend", "interfaces": [ "FileReader" ] }, { "type": "fullscreenchange", "interfaces": [ "Document", "Element" ] }, { "type": "fullscreenerror", "interfaces": [ "Document", "Element" ] }, { "type": "gamepadconnected", "interfaces": [] }, { "type": "gamepaddisconnected", "interfaces": [] }, { "type": "loadstart", "interfaces": [ "HTMLMediaElement" ] }, { "type": "progress", "interfaces": [ "HTMLMediaElement" ] }, { "type": "suspend", "interfaces": [ "HTMLMediaElement" ] }, { "type": "abort", "interfaces": [ "HTMLMediaElement" ] }, { "type": "error", "interfaces": [ "HTMLMediaElement" ] }, { "type": "emptied", "interfaces": [ "HTMLMediaElement" ] }, { "type": "stalled", "interfaces": [ "HTMLMediaElement" ] }, { "type": "loadedmetadata", "interfaces": [ "HTMLMediaElement" ] }, { "type": "loadeddata", "interfaces": [ "HTMLMediaElement" ] }, { "type": "canplay", "interfaces": [ "HTMLMediaElement" ] }, { "type": "canplaythrough", "interfaces": [ "HTMLMediaElement" ] }, { "type": "playing", "interfaces": [ "HTMLMediaElement" ] }, { "type": "waiting", "interfaces": [ "HTMLMediaElement" ] }, { "type": "seeking", "interfaces": [ "HTMLMediaElement" ] }, { "type": "seeked", "interfaces": [ "HTMLMediaElement" ] }, { "type": "ended", "interfaces": [ "HTMLMediaElement" ] }, { "type": "durationchange", "interfaces": [ "HTMLMediaElement" ] }, { "type": "timeupdate", "interfaces": [ "HTMLMediaElement" ] }, { "type": "play", "interfaces": [ "HTMLMediaElement" ] }, { "type": "pause", "interfaces": [ "HTMLMediaElement" ] }, { "type": "ratechange", "interfaces": [ "HTMLMediaElement" ] }, { "type": "resize", "interfaces": [ "HTMLMediaElement" ] }, { "type": "volumechange", "interfaces": [ "HTMLMediaElement" ] }, { "type": "error", "interfaces": [ "HTMLSourceElement" ] }, { "type": "change", "interfaces": [ "AudioTrackList", "VideoTrackList", "TextTrackList" ] }, { "type": "addtrack", "interfaces": [ "AudioTrackList", "VideoTrackList", "TextTrackList" ] }, { "type": "removetrack", "interfaces": [ "AudioTrackList", "VideoTrackList", "TextTrackList" ] }, { "type": "cuechange", "interfaces": [ "HTMLMediaElement" ] }, { "type": "error", "interfaces": [ "HTMLTrackElement" ] }, { "type": "load", "interfaces": [ "HTMLTrackElement" ] }, { "type": "enter", "interfaces": [ "HTMLMediaElement" ] }, { "type": "exit", "interfaces": [ "HTMLMediaElement" ] }, { "type": "dragstart", "interfaces": [ "GlobalEventHandlers" ] }, { "type": "drag", "interfaces": [ "GlobalEventHandlers" ] }, { "type": "dragenter", "interfaces": [ "GlobalEventHandlers" ] }, { "type": "dragleave", "interfaces": [ "GlobalEventHandlers" ] }, { "type": "dragover", "interfaces": [ "GlobalEventHandlers" ] }, { "type": "drop", "interfaces": [ "GlobalEventHandlers" ] }, { "type": "dragend", "interfaces": [ "GlobalEventHandlers" ] }, { "type": "DOMContentLoaded", "interfaces": [ "Document" ] }, { "type": "afterprint", "interfaces": [ "Window" ] }, { "type": "beforeprint", "interfaces": [ "Window" ] }, { "type": "beforematch", "interfaces": [ "HTMLElement" ] }, { "type": "beforeunload", "interfaces": [ "Window" ] }, { "type": "blur", "interfaces": [ "Window", "HTMLElement" ] }, { "type": "cancel", "interfaces": [ "HTMLElement" ] }, { "type": "change", "interfaces": [ "HTMLElement" ] }, { "type": "close", "interfaces": [ "HTMLElement" ] }, { "type": "connect", "interfaces": [ "SharedWorkerGlobalScope" ] }, { "type": "contextlost", "interfaces": [ "HTMLElement", "OffscreenCanvas" ] }, { "type": "contextrestored", "interfaces": [ "HTMLElement", "OffscreenCanvas" ] }, { "type": "copy", "interfaces": [ "HTMLElement" ] }, { "type": "cut", "interfaces": [ "HTMLElement" ] }, { "type": "error", "interfaces": [ "Window", "WorkerGlobalScope", "HTMLElement", "EventSource", "Worker", "SharedWorker", "AbstractWorker" ] }, { "type": "focus", "interfaces": [ "Window", "HTMLElement" ] }, { "type": "formdata", "interfaces": [ "HTMLElement" ] }, { "type": "hashchange", "interfaces": [ "Window" ] }, { "type": "input", "interfaces": [ "HTMLElement" ] }, { "type": "invalid", "interfaces": [ "HTMLElement" ] }, { "type": "languagechange", "interfaces": [ "Window", "WorkerGlobalScope" ] }, { "type": "load", "interfaces": [ "Window", "HTMLElement" ] }, { "type": "message", "interfaces": [ "Window", "EventSource", "MessagePort", "BroadcastChannel", "DedicatedWorkerGlobalScope", "Worker", "ServiceWorkerContainer" ] }, { "type": "messageerror", "interfaces": [ "Window", "MessagePort", "BroadcastChannel", "DedicatedWorkerGlobalScope", "Worker", "ServiceWorkerContainer" ] }, { "type": "offline", "interfaces": [ "Window", "WorkerGlobalScope" ] }, { "type": "online", "interfaces": [ "Window", "WorkerGlobalScope" ] }, { "type": "open", "interfaces": [ "EventSource" ] }, { "type": "pagehide", "interfaces": [ "Window" ] }, { "type": "pageshow", "interfaces": [ "Window" ] }, { "type": "paste", "interfaces": [ "HTMLElement" ] }, { "type": "popstate", "interfaces": [ "Window" ] }, { "type": "readystatechange", "interfaces": [ "Document" ] }, { "type": "rejectionhandled", "interfaces": [ "Window", "WorkerGlobalScope" ] }, { "type": "reset", "interfaces": [ "HTMLElement" ] }, { "type": "securitypolicyviolation", "interfaces": [ "HTMLElement" ] }, { "type": "select", "interfaces": [ "HTMLElement" ] }, { "type": "slotchange", "interfaces": [ "HTMLSlotElement" ] }, { "type": "storage", "interfaces": [ "Window" ] }, { "type": "submit", "interfaces": [ "HTMLElement" ] }, { "type": "toggle", "interfaces": [ "HTMLElement" ] }, { "type": "unhandledrejection", "interfaces": [ "Window", "WorkerGlobalScope" ] }, { "type": "unload", "interfaces": [ "Window" ] }, { "type": "visibilitychange", "interfaces": [ "Document" ] }, { "type": "versionchange", "interfaces": [ "connection" ] }, { "type": "complete", "interfaces": [ "transaction" ] }, { "type": "abort", "interfaces": [ "transaction" ] }, { "type": "success", "interfaces": [ "request" ] }, { "type": "error", "interfaces": [ "request" ] }, { "type": "blocked", "interfaces": [ "request" ] }, { "type": "upgradeneeded", "interfaces": [ "request" ] }, { "type": "reflectionchange", "interfaces": [ "XRLightProbe" ] }, { "type": "appinstalled", "interfaces": [] }, { "type": "beforeinstallprompt", "interfaces": [] }, { "type": "addtrack", "interfaces": [] }, { "type": "removetrack", "interfaces": [] }, { "type": "mute", "interfaces": [] }, { "type": "unmute", "interfaces": [] }, { "type": "ended", "interfaces": [] }, { "type": "devicechange", "interfaces": [] }, { "type": "start", "interfaces": [ "MediaRecorder" ] }, { "type": "stop", "interfaces": [ "MediaRecorder" ] }, { "type": "dataavailable", "interfaces": [ "MediaRecorder" ] }, { "type": "pause", "interfaces": [ "MediaRecorder" ] }, { "type": "resume", "interfaces": [ "MediaRecorder" ] }, { "type": "error", "interfaces": [ "MediaRecorder" ] }, { "type": "navigate", "interfaces": [ "Navigation" ] }, { "type": "navigatesuccess", "interfaces": [ "Navigation" ] }, { "type": "navigateerror", "interfaces": [ "Navigation" ] }, { "type": "currententrychange", "interfaces": [ "Navigation" ] }, { "type": "dispose", "interfaces": [ "NavigationHistoryEntry" ] }, { "type": "enterpictureinpicture", "interfaces": [ "HTMLVideoElement" ] }, { "type": "leavepictureinpicture", "interfaces": [ "HTMLVideoElement" ] }, { "type": "resize", "interfaces": [ "PictureInPictureWindow" ] }, { "type": "message", "interfaces": [ "HTMLPortalElement" ] }, { "type": "messageerror", "interfaces": [ "HTMLPortalElement" ] }, { "type": "message", "interfaces": [ "PortalHost" ] }, { "type": "messageerror", "interfaces": [ "PortalHost" ] }, { "type": "portalactivate", "interfaces": [ "Window" ] }, { "type": "prioritychange", "interfaces": [ "TaskSignal" ] }, { "type": "statechange", "interfaces": [ "ServiceWorker" ] }, { "type": "updatefound", "interfaces": [ "ServiceWorkerRegistration" ] }, { "type": "controllerchange", "interfaces": [ "ServiceWorkerContainer" ] }, { "type": "message", "interfaces": [ "ServiceWorkerContainer" ] }, { "type": "messageerror", "interfaces": [ "ServiceWorkerContainer" ] }, { "type": "install", "interfaces": [ "ServiceWorkerGlobalScope" ] }, { "type": "activate", "interfaces": [ "ServiceWorkerGlobalScope" ] }, { "type": "fetch", "interfaces": [ "ServiceWorkerGlobalScope" ] }, { "type": "message", "interfaces": [ "ServiceWorkerGlobalScope" ] }, { "type": "messageerror", "interfaces": [ "ServiceWorkerGlobalScope" ] }, { "type": "audiostart", "interfaces": [ "SpeechRecognition" ] }, { "type": "soundstart", "interfaces": [ "SpeechRecognition" ] }, { "type": "speechstart", "interfaces": [ "SpeechRecognition" ] }, { "type": "speechend", "interfaces": [ "SpeechRecognition" ] }, { "type": "soundend", "interfaces": [ "SpeechRecognition" ] }, { "type": "audioend", "interfaces": [ "SpeechRecognition" ] }, { "type": "result", "interfaces": [ "SpeechRecognition" ] }, { "type": "nomatch", "interfaces": [ "SpeechRecognition" ] }, { "type": "error", "interfaces": [ "SpeechRecognition" ] }, { "type": "start", "interfaces": [ "SpeechRecognition" ] }, { "type": "end", "interfaces": [ "SpeechRecognition" ] }, { "type": "voiceschanged", "interfaces": [ "SpeechSynthesis" ] }, { "type": "start", "interfaces": [ "SpeechSynthesisUtterance" ] }, { "type": "end", "interfaces": [ "SpeechSynthesisUtterance" ] }, { "type": "error", "interfaces": [ "SpeechSynthesisUtterance" ] }, { "type": "pause", "interfaces": [ "SpeechSynthesisUtterance" ] }, { "type": "resume", "interfaces": [ "SpeechSynthesisUtterance" ] }, { "type": "mark", "interfaces": [ "SpeechSynthesisUtterance" ] }, { "type": "boundary", "interfaces": [ "SpeechSynthesisUtterance" ] }, { "type": "touchstart", "interfaces": [] }, { "type": "touchend", "interfaces": [] }, { "type": "touchmove", "interfaces": [] }, { "type": "touchcancel", "interfaces": [] }, { "type": "advertisementreceived", "interfaces": [ "BluetoothDevice" ] }, { "type": "availabilitychanged", "interfaces": [ "Bluetooth" ] }, { "type": "characteristicvaluechanged", "interfaces": [ "BluetoothRemoteGATTCharacteristic" ] }, { "type": "gattserverdisconnected", "interfaces": [ "BluetoothDevice" ] }, { "type": "serviceadded", "interfaces": [ "BluetoothRemoteGATTService" ] }, { "type": "servicechanged", "interfaces": [ "BluetoothRemoteGATTService" ] }, { "type": "serviceremoved", "interfaces": [ "BluetoothRemoteGATTService" ] }, { "type": "change", "interfaces": [ "ImageTrack" ] }, { "type": "uncapturederror", "interfaces": [ "GPUDevice" ] }, { "type": "open", "interfaces": [ "RTCDataChannel" ] }, { "type": "message", "interfaces": [ "RTCDataChannel" ] }, { "type": "bufferedamountlow", "interfaces": [ "RTCDataChannel" ] }, { "type": "error", "interfaces": [ "RTCDataChannel" ] }, { "type": "closing", "interfaces": [ "RTCDataChannel" ] }, { "type": "close", "interfaces": [ "RTCDataChannel" ] }, { "type": "track", "interfaces": [ "RTCPeerConnection" ] }, { "type": "negotiationneeded", "interfaces": [ "RTCPeerConnection" ] }, { "type": "signalingstatechange", "interfaces": [ "RTCPeerConnection" ] }, { "type": "iceconnectionstatechange", "interfaces": [ "RTCPeerConnection" ] }, { "type": "icegatheringstatechange", "interfaces": [ "RTCPeerConnection" ] }, { "type": "icecandidate", "interfaces": [ "RTCPeerConnection" ] }, { "type": "connectionstatechange", "interfaces": [ "RTCPeerConnection" ] }, { "type": "icecandidateerror", "interfaces": [ "RTCPeerConnection" ] }, { "type": "datachannel", "interfaces": [ "RTCPeerConnection" ] }, { "type": "tonechange", "interfaces": [ "RTCDTMFSender" ] }, { "type": "statechange", "interfaces": [ "RTCIceTransport" ] }, { "type": "gatheringstatechange", "interfaces": [ "RTCIceTransport" ] }, { "type": "selectedcandidatepairchange", "interfaces": [ "RTCIceTransport" ] }, { "type": "statechange", "interfaces": [ "RTCDtlsTransport" ] }, { "type": "error", "interfaces": [ "RTCDtlsTransport" ] }, { "type": "statechange", "interfaces": [ "RTCSctpTransport" ] }, { "type": "open", "interfaces": [ "WebSocket" ] }, { "type": "message", "interfaces": [ "WebSocket" ] }, { "type": "error", "interfaces": [ "WebSocket" ] }, { "type": "close", "interfaces": [ "WebSocket" ] }, { "type": "devicechange", "interfaces": [ "XRSystem" ] }, { "type": "visibilitychange", "interfaces": [ "XRSession" ] }, { "type": "end", "interfaces": [ "XRSession" ] }, { "type": "inputsourceschange", "interfaces": [ "XRSession" ] }, { "type": "selectstart", "interfaces": [ "XRSession" ] }, { "type": "selectend", "interfaces": [ "XRSession" ] }, { "type": "select", "interfaces": [ "XRSession" ] }, { "type": "squeezestart", "interfaces": [ "XRSession" ] }, { "type": "squeezeend", "interfaces": [ "XRSession" ] }, { "type": "squeeze", "interfaces": [ "XRSession" ] }, { "type": "frameratechange", "interfaces": [ "XRSession" ] }, { "type": "reset", "interfaces": [ "XRReferenceSpace" ] }, { "type": "redraw", "interfaces": [ "XRLayer" ] }, { "type": "reflectionchange", "interfaces": [ "XRLightProbe" ] }, { "type": "change", "interfaces": [ "Screen" ] }, { "type": "screenschange", "interfaces": [ "ScreenDetails" ] }, { "type": "currentscreenchange", "interfaces": [ "ScreenDetails" ] }, { "type": "change", "interfaces": [ "ScreenDetailed" ] }, { "type": "readystatechange", "interfaces": [ "XMLHttpRequest" ] }, { "type": "loadstart", "interfaces": [ "XMLHttpRequest" ] }, { "type": "progress", "interfaces": [ "XMLHttpRequest" ] }, { "type": "abort", "interfaces": [ "XMLHttpRequest" ] }, { "type": "error", "interfaces": [ "XMLHttpRequest" ] }, { "type": "load", "interfaces": [ "XMLHttpRequest" ] }, { "type": "timeout", "interfaces": [ "XMLHttpRequest" ] }, { "type": "loadend", "interfaces": [ "XMLHttpRequest" ] } ]
via jq -s '[.[].dfns[]|select(.type == "event")|{type: .linkingText[0], interfaces: .for}]' *.json
in ed/dfns
That's 269 events, when MDN has 433 event pages.
From a quick look, the diffs are a mix of actual gaps and badly marked up specs.
In terms of associating events with the interface of the object they produce, the naive heuristic tying foo
and FooEvent
only generates 55 such associations, which I haven't verified the validity of.
A few specs (notably the HTML spec) have tables associating event types with event interfaces; not sure yet how easy they would be to parse generically, nor how much coverage this would bring.
The DOM spec suggests using the phrase "Fire an event named X using Y"; some specs are doing it, but again, not sure how many. I guess further exploration will require playing with a reffy module.
the naive heuristic tying
foo
andFooEvent
only generates 55 such associations
(that being said, there are "only" 106 Event interfaces defined across 59 specifications)
cat ed/idlnames/*Event.idl|grep " Source"|cut -d "(" -f 2|sort|uniq -c|sort -rn|sed -e "s/^//"|sed -e "s/)$//"
The current version of this PR extracts 435 events from 81 specifications, with event type, the interface the event is sent with, and the interfaces that the event targets.
Unfortunately, for 68 of these specifications, the extracted information is incomplete, primarily in its ability to detect the interface of the event object. I believe the patterns that the extractor detects could be applied to all of these specs to correct these gaps, but this is not an insignificant effort.
It may be that a bit more of heuristics would reduce that number a bit, but I still expect it would require a non insignificant amount of patches to specs.
I would be game to be part of a shared effort in that direction (as well a giving the actual directions for the kind of patches needed), but I would need to know who else would be willing to contribute, and what additional information we would want to extract (if any) before going through such an exercise.
The current version of this PR extracts 435 events from 81 specifications, with event type, the interface the event is sent with, and the interfaces that the event targets. Unfortunately, for 68 of these specifications, the extracted information is incomplete, primarily in its ability to detect the interface of the event object. I believe the patterns that the extractor detects could be applied to all of these specs to correct these gaps, but this is not an insignificant effort.
My error detection script was bogus (!) and I improved a bit the extraction code; the number of specifications with incomplete data is down to 50, and I've filed patches for 2 of them.
@foolip I'd be interested in your views on:
what's the minimally viable dataset for events? Would name + interface + targets be good enough as a starting point?
I think I'd add bubbling to that, since that determines whether document.addEventListener(type, callback)
makes sense for a lot of events fired on elements. It's tempting to add cancelable + composed to the list, but I don't think those are as important in practice.
would you be game to work with @tidoust and I on patching events-defining specs to make more of them automatically extractable? the instructions for that are still to-be-written, but it's essentially either using the DOM phrasing of "fire an event named X using Y", or using an event summary table as a few specs are already doing.
Yes, I could send some spec patches, if we have a burndown list.
See https://github.com/openwebdocs/project/issues/61#issuecomment-923172472 in the kind of data that would be useful to extract e.g. for MDN