1

I'm building a function in which I would find it useful to determine if a string is intended to specify an event type. (e.g., click, keypress, blur..) Currently, I'm comparing it to an array of names I grabbed from the standard, but I don't like this solution for a few reasons:

  • It's ugly. A hard-coded array of 167 items seems awfully inelegant.

  • Different browser environments likely support different events. I could use different (or additional) lists per-browser, but that just exacerbates the prior issue, and would be godawful to maintain.

  • There are, I believe, situations where events can be dynamically created. I can't possibly detect those beforehand.

My search-fu seems to have failed me on this point, so I turn to my clever and generous fellow users of Stack Overflow. My question, in short, is this:

How can I get a list, at runtime, of currently recognized event types?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Jon Carter
  • 2,836
  • 1
  • 20
  • 26
  • Perhaps not an exact duplicate, but I think it has the answer you seek: [*Javascript IN operator compatibility*](http://stackoverflow.com/questions/2920765/javascript-in-operator-compatibility/2920832#2920832). – RobG Mar 28 '16 at 01:41

4 Answers4

1
Object.keys(HTMLElement.prototype).filter(function(k) { return /^on/.test(k); });
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • That's clever, and I like it. But for some reason, the only thing it returns in Firefox Developer Edition is 'onwheel'. And for Chrome, it returns eleven items, missing several common events such as 'onclick'. – Jon Carter Mar 28 '16 at 00:23
  • 1
    @JonCarter: Sorry; that should be `HTMLElement` – SLaks Mar 28 '16 at 00:31
  • The flaw here is that it assumes that the host implements prototype inheritance for DOM objects (which it isn't required to do), and that all events are available as members of *HTMLElement.prototype* (try it in Safari). – RobG Mar 28 '16 at 00:42
  • I'll mark this as accepted (@Gary's answer provides a longer list, but uses the same approach as first suggested in this answer.). But I'm still curious about what object's keys to use. I'm currently poring over the docs on MDN to see if HTMLElement, window, some other object, or some combination of objects is guaranteed to contain all events, according to the specifications. – Jon Carter Mar 28 '16 at 02:44
  • @JonCarter: "All events" is an ambiguous term. Different objects will have different events. – SLaks Mar 28 '16 at 03:02
  • Quite correct. I specifically meant "all event *types* currently defined in the runtime environment." In other words, the list containing 'click', 'blur', 'keypress', etc. I'm beginning to wonder if this is somehing that *can* be well-defined.. – Jon Carter Mar 28 '16 at 03:27
  • @JonCarter—so it's acceptable to return an empty array in Safari? According this answer, it has no "on" events. – RobG Mar 28 '16 at 07:35
  • @JonCarter: It's well-defined _for a given object type_. – SLaks Mar 28 '16 at 14:02
  • @RobG -- That's surprising -- I thought Safari uses webkit, similar to Chrome (though Chrome forked their engine off webkit, a few years back). At any rate, the standard calls for HTMLElement to implement the GlobalEventHandlers interface, at least [according to MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement). If Safari doesn't follow the standard, I'm happy not to worry about it, especially as this is a hobby project. – Jon Carter Mar 31 '16 at 01:01
  • 1
    @JonCarter—MDN isn't an authority and isn't specifically about Safari (but it's a very useful resource regardless). Not sure that any of the standards and specifications referenced require such properties to be enumerable. Browsers, standards and specifications are a constantly moving target. Feature testing and fall–backs are as important now as ever. None of the interfaces **require** inheritance, though recent specifications are written to infer it, probably for convenience. Everything is written to define behaviour, not implementation. – RobG Mar 31 '16 at 06:06
  • @RobG Ah. I finally see what you mean. Checking for the event type on the prototype doesn't necessarily indicate whether the event type in question is supported, with Safari being an example. But does checking for the property on the element itself (as you suggest in your answer) offer any greater reliability? Wouldn't it be possible for a host to create event types on the element as needed, at the time the event is attached? I feel like, though I know more about this now, I'm back at my original question - what *is* a good way to feature-detect event types? – Jon Carter Mar 31 '16 at 23:07
  • For that matter, how *does* Safari create elements with properties named after event types (implied by the supposition that @RobG's answer works for Safari), without having them on HTMLElement.prototype? Do elements inherit from something else, or do the properties get attached in the (e.g.) HTMLDivElement constructor? – Jon Carter Mar 31 '16 at 23:11
  • 1
    @JonCarter: They're host objects. They don't necessarily obey prototypes. – SLaks Mar 31 '16 at 23:44
1

Similar to SLaks' answer, but you could run it on the window object instead to get an exhaustive list of events.

Object.keys(window).filter(function(k) { return /^on/.test(k); });

Gary S.
  • 146
  • 5
1

You don't say why you want to do this, so answers can only address the specific question of "how to tell if a string is an 'on' event".

I don't think there's a definitive strategy for that. Using a list of all possible event types collated from implementations, standards or specifications might be reasonably reliable but will not be perfect since javascript implementations are free to introduce any new type of event they wish. So the list would need to be updated frequently and you'd have to at least test and possibly update the list on every new browser and version that is released. Also, all events may not be supported by all browsers.

Using strategies like collecting the enumerable "on" properties of a DOM object or it's prototype also don't suit since hosts aren't required to implement inheritance on DOM objects and some don't make them enumerable (such as Safari v9 at least).

Another solution is to see if 'on' + string is a standard property of a DOM object, so:

function isPossibleEventName(s) {
  var div = document.createElement('div');
  return ('on' + s) in div;
}

['click','input','blur','foo','bar','paste'].forEach(function(s){
  document.write('<br>Possible event ' + s + ': ' + isPossibleEventName(s));
});

That will at least tell you if the host supports a particular event type, however it may need to be tested on different element types since not all elements necessarily support all events. Also, it doesn't tell you if the string might be an "on" event in some other host (but neither will collating "on" properties of an element's prototype).

While this should work in all browsers, there is some doubt if the above will work in older Firefox. However, this post says otherwise and it seems OK in version 43. You should test versions back as far as you think reasonable.

Community
  • 1
  • 1
RobG
  • 142,382
  • 31
  • 172
  • 209
  • Here's a more complete description of my goal, instead of the very brief one I gave in the question: I need to decide whether an object key is an event type or something else. [Here's the code](https://github.com/borkabrak/attachEvents.js) on github -- the objection in question is the argument to `attachEvents()`. I could implement this differently to get around the problem, but that doesn't satisfy my curiosity about whether this is possible anyway -- I can imagine a case where it might be unavoidable, and it seems like there *should* be a way to do this. :) – Jon Carter Mar 28 '16 at 02:41
  • My apologies for not understanding this at first. This is a good answer. But please see my comment on SLakS' answer for my ignorance about whether it's substantially better. – Jon Carter Mar 31 '16 at 23:13
0

Here's my go-to reference, pretty comprehensive.

Donny West
  • 710
  • 3
  • 6
  • That's what I'm currently using to load the array, myself. But I find this solution imperfect, as described in the question. – Jon Carter Mar 28 '16 at 00:16