W3C home > Mailing lists > Public > public-webapi@w3.org > March 2006

Re: ACTION-70: Define the scope chain of onFoo events reference issue-1

From: Maciej Stachowiak <mjs@apple.com>
Date: Tue, 14 Mar 2006 02:46:16 -0800
Message-Id: <4E6DDF94-E1CC-47F2-B27C-7A4A63B827A5@apple.com>
Cc: "\"Web APIs WG (public)\"" <public-webapi@w3.org>
To: Sergey Ilinsky <sergey@backbase.com>


On Mar 14, 2006, at 1:01 AM, Sergey Ilinsky wrote:

> Hello everyone,
>
> To the discussion kept here I'd like to add several important  
> issues that have not been yet taken into consideration.
>
> 1) Event listeners can not (and I also believe should not) be  
> capable of changing by modification of element attributes

With the following test case, Safari, Firefox and Opera respect the  
DOM change and reflect it with a changed event handler:


<div id="a" onclick="alert('original')" style="width: 200; height:  
200; background-color: red;"></div>
<br>
<br>
<div id="b" onclick="document.getElementById('a').setAttribute 
('onclick', 'alert(\'new\')');">
   click here to change above listener
</div>


>  2) Since element can have any amount of listeners of the same  
> event type attached, the construction
>    element.on<handler> = fHandler;
>    becomes ambigous (what is being reassigned by this call - a  
> collection or the last one listener added or something else?).
>    This is to be defined.

<element onsomeevent=""> and element.onsomeevent = fHandler refer to  
a single, unique listner per element. There is exactly one such "html  
event listener" per event per element, but there can be any number of  
addEventListener-added listeners at the same time.

>  3) The current order of handlers execution is different in  
> different browsers
>    (take onload event that is first handled on window and then on  
> body in IE, while fired first on body and then on window in Mozilla)

The load event does not fire on the body at all in Mozilla, as far as  
I know. The following test case shows only "window". Same in the  
latest builds of Safari. Opera fires body, then window, then  
document, which seems weird. IE doesn't have addEventListener so this  
test case won't work.

<html>
<body>
<script>
window.addEventListener("load", function() { alert('window'); }, false);
document.addEventListener("load", function() { alert('document'); },  
false);
document.documentElement.addEventListener("load", function() { alert 
('html element'); }, false);
document.body.addEventListener("load", function() { alert('body  
element'); }, false);
</script>
</body>
</html>


>  4) The scope of execution is currently very chaotic and very  
> dependent on event types
>    For example when handling onload/onunload event handlers, "this"  
> object in IE points to window, while handlers for other event types
>    properly get their scope of element objects.

I don't think it is chaotic in other browsers. But most browsers do  
treat the onload property of <body> as creating a load event listener  
on the window, not the body. So the "this" object binding isn't  
arbitrary, it just reflects the true target of the event.

But I think specifying events on the window object is probably out of  
scope for DOM Level 3 Events.


>     I think the scope should never be dependent on the type of  
> event and in any case get the scope of DOMElement Node to which the  
> listener was added.

I'm assuming you mean this only for onfoo attribute-based event  
listeners. This wouldn't be compatible with what browsers currently  
do. But I think the html <body> and <html> elements might be the only  
special cases. Perhaps also <frameset>.

Regards,
Maciej



>
>
> Sergey Ilinsky,
> Core Architect,
> BackBase B.V.
>
> --- Jonas Sicking <jonas@sicking.cc> wrote:
> >
> > Maciej Stachowiak wrote:
> > > Hi everyone,
> > >
> > > This action item was assigned to me while I wasn't
> > present, so I'm not
> > > sure what it means. I could imagine the following
> > possible things
> > > intended to be covered:
> > >
> > > 1) Define scope chain for event listeners attached
> > via HTML event
> > > attributes, e.g. <img
> > onclick="handleClick(event)">.
> > > 2) Define `this' binding behavior for #1.
> > > 3) Define scope chain for events attached via HTML
> > DOM properties, e.g.
> > > myImage.onclick = handleClick
> > > 4) Define `this' binding behavior for #3.
> > > 5) Define scope chain for events attached via
> > addEventListener().
> > > 6) Define `this' binding for #5 (already done).
> > > 7) Define scope chain for event listeners attached
> > via SVG 1.1 event
> > > attributes, e.g. <image
> > onclick="handleClick(event)">.
> > > 8) Define `this' binding behavior for #1.
> > >
> > > I do not feel like I have the relevant expertise
> > to answer 7 and 8, but
> > > I can try to do some research if it is desirable
> > to define those.
> >
> > Ideally I would hope that we can define 7 and 8 to
> > be as similar to 1
> > and 2 as possible, to reduce author confusion and
> > make CDF more sane.
> >
> > > Here's brief outlines of the behavior I would
> > propose. I have not tested
> > > thoroughly or written any of this up in formal
> > language, so please let
> > > me know which ones need testing and formal
> > language.
> > >
> > > 1) The attribute text is coverted to a function as
> > if it were the result
> > > of the following expression evaluated in global
> > scope, where ELT is the
> > > DOM object representing the element:
> > >
> > > (function() { with(ELT) { return function(event) {
> >  ....contents of
> > > attribute here... } } })()
> >
> > There is need for additional code in here to deal
> > with the return value,
> > i.e. that returning false should call
> > .preventDefault. Other then that I
> > agree with this.
> >
> > However we should probably also define the scope
> > chain for elements.
> > This should clearly ideally have lived in another
> > spec, but I guess
> > we're stuck with having it in events for now?
> >
> > > The behavior is then as if resulting function F
> > were added with
> > > addEventListener(event, F, false).
> > >
> > > The upshot of this is that a function is made with
> > ELT at the head of
> > > its [[Scope]] internal property, and "event" is
> > bound to the event in
> > > the function body.
> > >
> > > I think describing this in terms of the language
> > beats trying to write
> > > prose about the [[Scope]] property though.
> > >
> > > Also this is subtly incompatible with Win IE,
> > since I believe it has
> > > only window.event, not an actual event parameter
> > to attribute handlers.
> >
> > As far as events go I think compatibility with IE is
> > a lost cause. So
> > i'm not too worried here.
> >
> > > Also, some event listener properties on the <body>
> > element actually
> > > create event listeners on the window object, not
> > the body, and so do not
> > > include the body in their scope chain.
> >
> > I just verified this in mozilla. Adding on*
> > attributes to the <body> or
> > the <html> tag will make both |this| and the scope
> > chain start on the
> > window object.
> >
> > > 2) See above - no special considerations for
> > "this" beyond the effect of
> > > addEventListener of a function.
> > >
> > > 3) Event handler DOM properties have a function
> > value. Getting the
> > > property retrieves any event listener function
> > previously set using the
> > > property or corresponding markup attribute.
> > Setting the property removes
> > > any previous event listener set via that property
> > or the corresponding
> > > attribute, and adds the newly set function as if
> > with addEventListener.
> > > There is no change made to the scope chain of a
> > function set this way.
> >
> > You mean that if you call
> > element.onclick = handler;
> >
> > then the scope chain of |handler| is determined by
> > what scope chain the
> > function had when it was created, right. Saying "no
> > change" could be
> > interpreted as if its the same as when the handler
> > is defined inside the
> > attribute.
> >
> > > The slightly odd implication of this is that you
> > can retrieve an event
> > > listener created via attribute and attach it to
> > another element, and its
> > > scope chain continues to include the original
> > element, not the new element.
> > >
> > > 4) See above - no special considerations for
> > "this" beyond the effect of
> > > addEventListener of a function.
> >
> > I think we should explicitly say that |this| will
> > get the same binding
> > as when a function is provided to addEventListener.
> >
> > > 5) addEventListener does not alter any function
> > parameters passed to it.
> > > In particular it does not alter the scope chain.
> > >
> > > 6) I already came up with language for this. In
> > brief my proposal was to
> > > define this as equivalent to adding an
> > EventListener created by the
> > > expression { handleEvent: function(event) {
> > > F.applyTo(event.currentTarget, [event]); } } where
> > F is the function.
> >
> > I would prefer if we used "call" rather then "apply"
> > to make it clear
> > that only one parameter is passed. It would also
> > make it cheaper for
> > someone implementing this literally.
> >
> > > The upshot of this is that the event's current
> > target will be the "this"
> > > object for any function event listener. But if you
> > add an object with a
> > > handleEvent method, then its handleEvent method is
> > invoked as normal,
> > > with the EventListener as the "this" object. Here
> > again I think it is
> > > better to explain the behavior in terms of
> > ECMAScript expressions than
> > > to try to explain in terms of ECMA-262
> > spec-internal concepts. It is
> > > more obvious how to test this way, and is more
> > likely to be compatible
> > > with future revisions of ECMA-262.
> >
> > Sounds good to me.
> >
> > / Jonas
> >
> >
>
Received on Tuesday, 14 March 2006 10:46:38 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Tuesday, 8 January 2008 14:18:53 GMT