Fwd: [whatwg] Exposing EventTarget to JavaScript

Forwarded from whatwg upon Ian's request.

Forwarded conversation
Subject: Exposing EventTarget to JavaScript
------------------------

From: *Erik Arvidsson* <erik.arvidsson@gmail.com>
Date: Fri, Apr 24, 2009 at 10:00
To: whatwg <whatwg@lists.whatwg.org>


Almost all JavaScript libraries and web apps of moderate size end up
reimplementing events for their UI toolkits or for messaging between
different parts of their application. To help out with this scenario
it would be good if an implementation of the EventTarget interface
could be exposed to JavaScript. This would mean that JavaScript can
instantiate and extend event targets and dispatch events to these
objects would work just like it does for DOM elements today.

For example:

var et = new EventTarget;
...
et.addEventListener('foo', fun, false);
...
et.dispatchEvent(eventObject);

would call the handler fun.

The example above actually works today if you replace "new
EventTarget" with "document.createElement('div')".

The next and more important step is to allow a JavaScript "class" to
extend an EventTarget. For example:

function MyClass() {
 EventTarget.call(this);
 ...
}
MyClass.prototype = new EventTarget; // *[1]

Then addEventListener and dispatchEvent should work as expected on
MyClass objects.

One more thing needs to be mentioned and that is how event propagation
should work in scenario. If the object has a "parentNode" property
then the event dispatching mechanism will do the right thing.

var o1 = new MyClass;
var o2 = new MyClass;
o1.parentNode = o2;
o2.addEvengListener('foo', fun, true); // capture
o1.dispatchEvent(e);

In this case fun will be called because the event propagated up to o2.

There is one more thing that needs to be done to make this work
without a hitch and that is to allow "new Event('foo')" to work.
Without that we would still have to do "var $tmp =
document.createEvent('Event'); $tmp.initEvent('foo')" which of course
is very verbose and requires a document.

I see this as a small step to make JS and DOM work better together and
I hope that "this is the beginning of a beautiful friendship".

*[1] This can be optimized using js tricks in ES3 and using
Object.create in ES5 so that no EventTarget needs to be instantiated.

--
erik

----------
From: *Kristof Zelechovski* <giecrilj@stegny.2a.pl>
Date: Fri, Apr 24, 2009 at 10:17
To: Erik Arvidsson <erik.arvidsson@gmail.com>, whatwg <
whatwg@lists.whatwg.org>


As a reminder, the syntax {new Option()} (Netscape DOM) is deprecated to the
syntax {document.createElement("OPTION")} (W3C DOM).  The requested syntax
{new Event()} would be inconsistent with that design decision.  OTOH, the
syntax {new XMLHTTPRequest()} has already been adopted, perhaps because
{document.createXMLHTTPRequest()} would be too specific?
A bit confused,
Chris



----------
From: *Alex Russell* <slightlyoff@google.com>
Date: Fri, Apr 24, 2009 at 10:29
To: Erik Arvidsson <erik.arvidsson@gmail.com>
Cc: whatwg <whatwg@lists.whatwg.org>


As we discussed off-list, I absolutely support this, but with shorter
names. The DOM names for these interfaces are dumb. Idiomatic JS
prefers short over long, so the above example should be able to be
written as:

var et = new EventTarget();
et.listen("foo", fun); // default phase to "false"
et.dispatch(evtObj);

Similarly, the DOM interface should be modified to allow these aliases
for the existing names.

Regards

----------
From: *Giovanni Campagna* <scampa.giovanni@gmail.com>
Date: Fri, Apr 24, 2009 at 10:30
To: Erik Arvidsson <erik.arvidsson@gmail.com>
Cc: whatwg <whatwg@lists.whatwg.org>


2009/4/24 Erik Arvidsson <erik.arvidsson@gmail.com>:
This should not work. This is because the DOM event system (used for
elements) is different from the scripting event system (used for
windows, xmlhttprequest, workers, etc.). The former requires a
document through which the event flows (capture - target - bubble
phases). No document => no event.
This is a matter of host language, not of DOM. In Java, you just do
public class MyClass implements EventTarget {
}

and the same in ES6 (ES-Harmony)
Why do you need an EventTarget?
In most cases you can emulate the same behavior with a Javascript
library, without more work on the UA.
Giovanni

----------
From: *Alex Russell* <slightlyoff@google.com>
Date: Fri, Apr 24, 2009 at 10:33
To: Giovanni Campagna <scampa.giovanni@gmail.com>
Cc: Erik Arvidsson <erik.arvidsson@gmail.com>, whatwg <
whatwg@lists.whatwg.org>


This is a bug, not a design constraint.

JavaScript should be extended to support event dispatch (as Erik
outlines) and it should be done in such a way as to cast the DOM event
system as an implementation of that dispatch mechanism. Suggesting
that JS and DOM shouldn't be more tightly integrated because they
havent' been more tightly integrated in the past isn't a legit
argument.
It's safe to fully ignore Java.

Regards

----------
From: *Ojan Vafai* <ojan@chromium.org>
Date: Fri, Apr 24, 2009 at 10:55
To: Erik Arvidsson <erik.arvidsson@gmail.com>, Alex Russell <
slightlyoff@google.com>


I think we should wait for another day's worth of feedback and then try to
get WebKit teams' thoughts on this. If they agree that this is a good idea,
we can just add it to WebKit-based browsers and thats the end of the
discussion really.
Alex, while I agree that the naming is unfortunate, I'm of the opinion that
we're stuck with it for now. The benefits of changing the name just don't
seem that substantial to me compared to the confusion of adding another API
that does the same thing.

Ojan

----------
From: *Giovanni Campagna* <scampa.giovanni@gmail.com>
Date: Fri, Apr 24, 2009 at 10:58
To: Alex Russell <slightlyoff@google.com>
Cc: Erik Arvidsson <erik.arvidsson@gmail.com>, whatwg <
whatwg@lists.whatwg.org>


2009/4/24 Alex Russell <slightlyoff@google.com>:
DOM = Document Object Model = a set of APIs for representing and
manipulating documents

If you need pure scripting interfaces, you can write your own library,
without reusing EventTarget, that has been used outside its scope with
debatable results. (what does event.stopPropagation() do for
XMLHttpRequest events?)
Why?
Moreover, is it safe to fully ignore Python or Perl? This is not the
opinion of the SVGWG, in SVGTiny12.
And Java bindings are provided by WebIDL and all DOM specifications.

----------
From: *Aaron Boodman* <aa@google.com>
Date: Fri, Apr 24, 2009 at 11:29
To: Erik Arvidsson <erik.arvidsson@gmail.com>
Cc: whatwg <whatwg@lists.whatwg.org>


I like the basic idea, but I think drawing too much inspiration from
DOM events is a bad idea. What does it mean to "capture" a pure JS
event? Further, the DOM event model has problems. It would be nice if
events were first-class, not strings. It would be more idiomatic JS, I
would argue, to do someObject.onClick.add(<handler>).

- a

----------
From: *Boris Zbarsky* <bzbarsky@mit.edu>
Date: Fri, Apr 24, 2009 at 11:46
To: Erik Arvidsson <erik.arvidsson@gmail.com>
Cc: whatwg <whatwg@lists.whatwg.org>


Why do you want the eventTarget interface as opposed to a sane callback
function registration setup? So this already works, no? What, precisely, is
the use case for this in general?  In the DOM, propagating events to parents
makes sense (esp. because parents are unique).  What would be the use case
in a general object graph? Possibly for good reasons?  In some
implementations the document is in fact baked into the event for various
security purposes. It's not really clear to me what the benefits of using
the (rather suboptimal, from the JS point of view) DOM EventTarget API for
generic JS callback dispatch are.

-Boris


----------
From: *Ian Hickson* <ian@hixie.ch>
Date: Fri, Apr 24, 2009 at 12:44
To: Erik Arvidsson <erik.arvidsson@gmail.com>, Kristof Zelechovski <
giecrilj@stegny.2a.pl>, Alex Russell <slightlyoff@google.com>, Giovanni
Campagna <scampa.giovanni@gmail.com>, Aaron Boodman <aa@google.com>, Boris
Zbarsky <bzbarsky@mit.edu>
Cc: whatwg <whatwg@lists.whatwg.org>


> different parts of their application. To help out with this scenario it
This seems like a reasonable idea, but would be more appropriately made
available in the DOM3 Events specification, being developed in the W3C
public-webapps working group.
This isn't correct; new Option() is perfectly valid and not deprecated.
> var et = new EventTarget();
I encourage you to bring this up on the public-webapps list.
This does not appear to be accurate either, though DOM3 Events maybe needs
to be made clearer on the topic.

--
Ian Hickson               U+1047E                )\._.,--....,'``.    fL
http://ln.hixie.ch/       U+263A                /,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'

----------
From: *Erik Arvidsson* <erik.arvidsson@gmail.com>
Date: Fri, Apr 24, 2009 at 12:47
To: Boris Zbarsky <bzbarsky@mit.edu>
Cc: whatwg <whatwg@lists.whatwg.org>


One of the benefits is a consistent API.

I do agree that the EventTarget API is suboptimal and so are most of
the DOM APIs but it is what we got and we need tie the lose ends and
make ends meet.

--
erik

----------
From: *Ojan Vafai* <ojan@chromium.org>
Date: Fri, Apr 24, 2009 at 12:47
To: Erik Arvidsson <erik.arvidsson@gmail.com>, Alex Russell <
slightlyoff@google.com>


OK. Forget what I said, we should do what Hixie said.

----------
From: *Maciej Stachowiak* <mjs@apple.com>
Date: Fri, Apr 24, 2009 at 13:29
To: Aaron Boodman <aa@google.com>
Cc: Erik Arvidsson <erik.arvidsson@gmail.com>, whatwg <
whatwg@lists.whatwg.org>


There's really two aspects to the DOM event model. One is the basic
addEventListner / dispatchEvent mechanism, which allows objects to have
event listeners attached. The other is the bubble/capture event flow in the
DOM tree. It can make sense for an object to be an EventTarget without
participating in bubble/capture, because it is not part of the DOM document
tree. An example of this is XMLHttpRequest. It's a bit late in the game to
change the DOM itself to work that way. And having some other event
mechanism that works like this, while DOM events continue to work as they
do, would be confusing I think. One advantage to string event names is that
users of the DOM can invent custom event names at will. In addition, it is
possible to register for events that are not supported without having to do
feature testing. There are certainly downsides to the design but it is not
without precedent.

Regards,
Maciej


----------
From: *Alex Russell* <slightlyoff@google.com>
Date: Fri, Apr 24, 2009 at 14:06
To: Giovanni Campagna <scampa.giovanni@gmail.com>
Cc: Erik Arvidsson <erik.arvidsson@gmail.com>, whatwg <
whatwg@lists.whatwg.org>


On Fri, Apr 24, 2009 at 10:58 AM, Giovanni Campagna
That strong distinction between a theoretical OM for some abstract DOM
vs. the actual real-world use cases of "JavaScript is the primary
consumer" has allowed DOM APIs to be mangled beyond usability for far
too long.
If those events are dispatching down a chain of listeners on some
event, it stops that chain dispatch. The idea that somehow calling a
function in JS and firing an event in the DOM are totally different
thigns that deserve totally different listener APIs is an artifact of
a time when we had much less experience about how these things are
used in the real world. Dispatch is dispatch. Function calls are
events. Treating them differently because they happened to originate
from one part of the platform and not the other is crazy.
For the purpose of designing DOM APIs for the real world, absolutely.
They are not the "design center". Python has already left the building
(see lxml and the ElementTree API for details on why sane people
abandoned W3C DOM wholesale).
This is a historical artifact which doesn't need to blight the design
of DOM in it's primary use-case. If anything, we should be expressing
Java bindings as a special case, not as the common-case.

Regards

----------
From: *Alex Russell* <slightlyoff@google.com>
Date: Fri, Apr 24, 2009 at 14:09
To: Maciej Stachowiak <mjs@apple.com>
Cc: Aaron Boodman <aa@google.com>, whatwg <whatwg@lists.whatwg.org>, Erik
Arvidsson <erik.arvidsson@gmail.com>


Something missing from this (and from Erik's original mail) is the
ability to enumerate listeners. A facility for this should probably be
added.
Even in the XHR case, adding more than one listener is currently a
pain. Part of the goal here would be to make event dispatch across
lists of listeners as natural in JS as it is in DOM.

Regards

----------
From: *Aaron Boodman* <aa@google.com>
Date: Fri, Apr 24, 2009 at 14:16
To: Alex Russell <slightlyoff@google.com>
Cc: Maciej Stachowiak <mjs@apple.com>, whatwg <whatwg@lists.whatwg.org>,
Erik Arvidsson <erik.arvidsson@gmail.com>


Nit: I believe this has been fixed in XHR (it now supports
addEventListener, if that's what you were referring to).

- a

----------
From: *Alex Russell* <slightlyoff@google.com>
Date: Fri, Apr 24, 2009 at 14:18
To: Aaron Boodman <aa@google.com>
Cc: Maciej Stachowiak <mjs@apple.com>, whatwg <whatwg@lists.whatwg.org>,
Erik Arvidsson <erik.arvidsson@gmail.com>


Ahh, yeah, thanks for the clarification. I wasn't aware of that change.

Regards

----------
From: *Ian Hickson* <ian@hixie.ch>
Date: Fri, Apr 24, 2009 at 14:28
To: Maciej Stachowiak <mjs@apple.com>, Alex Russell <slightlyoff@google.com>,
Aaron Boodman <aa@google.com>
Cc: Erik Arvidsson <erik.arvidsson@gmail.com>



I recommend discussing this on the public-webapps list -- the editor of
the DOM3 Events spec doesn't read the WHATWG list as far as I'm aware.

----------
From: *Alex Russell* <slightlyoff@google.com>
Date: Fri, Apr 24, 2009 at 14:41
To: Boris Zbarsky <bzbarsky@mit.edu>
Cc: Erik Arvidsson <erik.arvidsson@gmail.com>, whatwg <
whatwg@lists.whatwg.org>


Most of the JS object graphs that you'll see in the wild either
represent data hierarchies (wherein updates might trigger a UI change)
or wrapped sets of DOM nodes as a way to make up for the fact that you
can't freaking subclass Element from JS. In the latter case, it's
natural to need it to keep up the facade. In the former, it's a
performance convenience.
I think individual call sites overriding their dispatch is sane, but
hopefully uncommon.
I don't think the proposal would be to use it as-is. Clearly it needs
beefing up to serve as a good aspect system for JS, but it's the right
starting place. Treating function calls as message sends or events to
be dispatched gives you a nice way of building after-advice into JS
objects, and with a little bit of massaging, could also give you
before and around advice. There's some friction between the Event
object and the "arguments" object, but not so much that it would be
insurrmountable to recast DOM event dispatch as sub-case of regular JS
function calling. JS libraries provide ways to try to unify these
interfaces (at huge expense), so moving it into the language makes the
most sense.

Regards

----------
From: *Boris Zbarsky* <bzbarsky@mit.edu>
Date: Fri, Apr 24, 2009 at 14:42
To: Alex Russell <slightlyoff@google.com>
Cc: whatwg <whatwg@lists.whatwg.org>


This has been brought up before.

1)  There are some serious security concerns here.
2)  It's not clear what the enumeration should actually return.
   EventListener objects?  JS Function objects?  Something else?
   Last I checked people couldn't even agree on this (both have
   pros and cons).

And other than a debugger, I have yet to see a usecase for this.  Do you
have a specific one in mind? How so, exactly? The only natural thing in DOM
is the event flow from target to root. That concept doesn't make much sense
in the absence of a linear data structure (the list of ancestors, here).

Is your real use case just to call a bunch of listeners in a defined order?

-Boris

----------
From: *Boris Zbarsky* <bzbarsky@mit.edu>
Date: Fri, Apr 24, 2009 at 14:43
To: Erik Arvidsson <erik.arvidsson@gmail.com>, whatwg <whatwg@whatwg.org>


OK, true.  But if the API is a bad fit, this might not be enough to want to
use it. Why is the right approach to this to add addEventListener and its
baggage to everything instead of adding a sane API to everything?

-Boris

----------
From: *Boris Zbarsky* <bzbarsky@mit.edu>
Date: Fri, Apr 24, 2009 at 14:46
To: Alex Russell <slightlyoff@google.com>
Cc: Erik Arvidsson <erik.arvidsson@gmail.com>, whatwg <
whatwg@lists.whatwg.org>


Agreed for the latter case (though at that point whatever is doing the
wrapping can also handle forwarding the listener sets to the real DOM
nodes).

I'm not sure what the performance issue with the former case is.  Can you
elaborate? I'm not sure how that relates to what I said... OK.

-Boris

----------
From: *Alex Russell* <slightlyoff@google.com>
Date: Fri, Apr 24, 2009 at 14:52
To: Boris Zbarsky <bzbarsky@mit.edu>
Cc: whatwg <whatwg@lists.whatwg.org>


Array of function objects. That would let you do useful things with it
like unshifting onto the front or slicing to remove some set of
listeners.
Aaron's note about addEventListener solves it, but in the common case
where a JS system wants to have multiple callbacks, they either wind
up carrying around their own event listener system (e.g.,
dojo.connect()) or a Deferred pattern to wrap functions which only
support direct dispatch from a single call site.
I think what I'd like to see is a way for this interface to allow
arbitrary JS object to specify what their "ancestor" is. That way
hierarchical JS objects can dispatch "up".
Consider some API that defines an "event":

thinger = {
   happened: function(){
       // processes some state here
   }
};

Today, JS toolkits provide various ways of listening for something
invoking this. In Dojo, I'd say:

dojo.connect(thinger, "happened", function(){ ... });

Other systems have similar conveniences, but in general they all exist
to keep developers from needing to do:

(function() {
  var old_happened = thinger.happened;
  thinger.happened = function() {
      // ...
      return old_happened.apply(this, arguments);
  };
})();

This method of building "callbacks" on existing APIs is not, to use
your word, "sane".

Regards




-- 
erik

Received on Friday, 24 April 2009 21:55:26 UTC