Feature testing DOM0 event interface

Discussion in 'Javascript' started by Peter Michaux, Feb 12, 2008.

  1. It seems people make a regular habit of testing for the
    addEventListener and attachEvent methods but they just assume the DOM0-
    type event interface exists like element.onclick.

    At least recent versions of Opera, Safari, IE allow for a feature test
    by all returning true for the following

    javascript:alert(typeof document.documentElement.onclick !=
    'undefined')

    Unfortunately, Firefox returns false for the above.

    Does anyone have a universal feature test for this?

    Thanks,
    Peter
     
    Peter Michaux, Feb 12, 2008
    #1
    1. Advertising

  2. Peter Michaux

    David Mark Guest

    On Feb 12, 12:46 pm, Peter Michaux <> wrote:
    > It seems people make a regular habit of testing for the
    > addEventListener and attachEvent methods but they just assume the DOM0-
    > type event interface exists like element.onclick.


    This assumption won't hurt anything if the page is designed to degrade
    gracefully.

    >
    > At least recent versions of Opera, Safari, IE allow for a feature test
    > by all returning true for the following
    >
    > javascript:alert(typeof document.documentElement.onclick !=
    > 'undefined')
    >
    > Unfortunately, Firefox returns false for the above.
    >
    > Does anyone have a universal feature test for this?
    >


    This isn't ideal as it relies on setAttribute, but it does work for
    Firefox. Alternatively, you could define the onclick attribute in the
    markup.

    var el = getAnElement(), dom0 = true;
    if (typeof el.onclick == 'undefined' &&
    isHostMethod(el, 'setAttribute')) {
    el.setAttribute('onclick', '(function() {})');
    dom0 = (typeof el.onclick == 'function');
    el.setAttribute('onclick', '');
    }

    If a design relies on DOM0 event support, the best solution is to call
    its gateway function like this:

    this.onload = myGateway;

    Is this in regard to the Safari 1.x preventDefault bug on click/
    dblclick? I have thought about that one and I don't think it requires
    a workaround. If, for instance, a user of Safari 1.x clicks a link
    that has a click event listener and preventDefault fails, the browser
    will fire the event and then navigate normally. As long as the page
    is designed to work without script, this should not cause an issue. I
    know some libraries (e.g. YUI) sniff for the older Safari versions and
    fallback to DOM0 for click/dblclick, but I think that is a mistake.
     
    David Mark, Feb 12, 2008
    #2
    1. Advertising

  3. On Feb 12, 12:23 pm, David Mark <> wrote:
    > On Feb 12, 12:46 pm, Peter Michaux <> wrote:
    >
    > > It seems people make a regular habit of testing for the
    > > addEventListener and attachEvent methods but they just assume the DOM0-
    > > type event interface exists like element.onclick.

    >
    > This assumption won't hurt anything if the page is designed to degrade
    > gracefully.


    I have a situation where it will hurt and this is a common situation.
    A page arrives with its HTML for static viewing. I want to manipulate
    the DOM structure and page CSS to create a widget. I think of the
    point at which the DOM and CSS are manipulated as "the point of no
    return". Before I make these manipulations I need to make sure the
    widget will function completely. If the DOM structure and CSS both
    work, but the browser doesn't have correct event handling, then the
    widget will be useless and some content will not be visible to the
    user.


    > > At least recent versions of Opera, Safari, IE allow for a feature test
    > > by all returning true for the following

    >
    > > javascript:alert(typeof document.documentElement.onclick !=
    > > 'undefined')

    >
    > > Unfortunately, Firefox returns false for the above.

    >
    > > Does anyone have a universal feature test for this?

    >
    > This isn't ideal as it relies on setAttribute, but it does work for
    > Firefox. Alternatively, you could define the onclick attribute in the
    > markup.
    >
    > var el = getAnElement(), dom0 = true;
    > if (typeof el.onclick == 'undefined' &&
    > isHostMethod(el, 'setAttribute')) {
    > el.setAttribute('onclick', '(function() {})');
    > dom0 = (typeof el.onclick == 'function');
    > el.setAttribute('onclick', '');
    >
    > }


    There doesn't seem to be anything in the Element.setAttribute spec
    that make me think this is a particularly robust test.

    http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-F68F082


    > If a design relies on DOM0 event support, the best solution is to call
    > its gateway function like this:
    >
    > this.onload = myGateway;


    I agreed that this is a solid solution. What I'm actually trying to
    determine if the above will work. Here is why...

    When a page is built with progressive enhancement in mind, the page
    looks like like the unenhanced version while the whole page loads.
    When window.onload occurs, then the page can be enhanced and made to
    look like the enhanced version. For the user with a browser that will
    support the enhanced version, this is unsightly. For example, a huge
    list of nested ul elements appear on the page for a while while the
    page loads, when window.onload fires, the hander determines that the
    nested ul elements can be converted into a drop-down menu or tree
    menu. When this conversion happens the page appears to "jump" as the
    CSS changes and the page is re-rendered. This is not really acceptable
    as more users will be able to have the enhanced version than the
    unenhanced version.

    So what I want to do is the following...

    When the page is loading, determine if the browser has enough features
    to "get out of trouble". If that is the case then add a CSS file to
    the page with document.write, that will give the page an acceptable
    appearance while the page loads. When window.onload fires, determine
    if the widget can fully function and enable that widget. If the widget
    cannot fully function then execute the "get out of trouble" and revert
    the styling of the HTML to something more pleasing for the unenlivened
    version. It almost allows me to *tentatively* cross the point of no
    return with just one foot so the page looks nicer during load.

    Makes sense?

    > Is this in regard to the Safari 1.x preventDefault bug on click/
    > dblclick?


    Yes my question also impacts this.

    > I have thought about that one and I don't think it requires
    > a workaround.


    You may be right that the workaround is not necessary. I need to think
    about this more.


    > If, for instance, a user of Safari 1.x clicks a link
    > that has a click event listener and preventDefault fails, the browser
    > will fire the event and then navigate normally. As long as the page
    > is designed to work without script, this should not cause an issue.


    But it might cause an issue if the JavaScript does something that
    shouldn't be followed by the normal navigation. I know we aren't
    supposed to use <a> links to add items to a shopping cart but suppose
    someone did. And then suppose they used hijax[1] to make the link add
    the item to the cart with Ajax. If the Ajax is initiated an then the
    link is followed, the item will be added to the cart twice.

    [1] http://domscripting.com/blog/display/41

    I am completely aware this is a crappy example but my gut tells me
    there must be situations where having the JavaScript run followed by
    the normal navigation is bad.

    I suppose the JavaScript could be run after a timeout and that way it
    only runs if the normal navigation didn't work. Messy solution.


    > I know some libraries (e.g. YUI) sniff for the older Safari versions and
    > fallback to DOM0 for click/dblclick, but I think that is a mistake.


    I think the sniff is also a mistake. I use DOM0 listeners for all
    click events. That way I treat all browsers equally and don't need the
    sniff. I think it would be fine to use DOM0 listeners for all event
    handlers. There really isn't a need for addEventListener and
    attachEvent because a wrapper API around DOM0 can do it all anyway. My
    problem is that right now I am not testing that DOM0 will work. This
    is not a large practical problem for me but it is a large problem in
    trying to write a widget properly.

    By the way, this problem is the last detail for an article I am
    writing for my blog about writing progressive enhancement widgets (a
    tabbed pane) for the general web. It uses the isHostMethod etc. If
    anyone is interested in reviewing the article I can post it here for
    debate. I've never seen such an article and I think such an article
    has long been needed.

    Peter
     
    Peter Michaux, Feb 12, 2008
    #3
  4. Peter Michaux

    David Mark Guest

    On Feb 12, 4:15 pm, Peter Michaux <> wrote:
    > On Feb 12, 12:23 pm, David Mark <> wrote:
    >
    > > On Feb 12, 12:46 pm, Peter Michaux <> wrote:

    >
    > > > It seems people make a regular habit of testing for the
    > > > addEventListener and attachEvent methods but they just assume the DOM0-
    > > > type event interface exists like element.onclick.

    >
    > > This assumption won't hurt anything if the page is designed to degrade
    > > gracefully.

    >
    > I have a situation where it will hurt and this is a common situation.
    > A page arrives with its HTML for static viewing. I want to manipulate
    > the DOM structure and page CSS to create a widget. I think of the
    > point at which the DOM and CSS are manipulated as "the point of no
    > return". Before I make these manipulations I need to make sure the
    > widget will function completely. If the DOM structure and CSS both
    > work, but the browser doesn't have correct event handling, then the
    > widget will be useless and some content will not be visible to the
    > user.
    >
    >
    >
    >
    >
    > > > At least recent versions of Opera, Safari, IE allow for a feature test
    > > > by all returning true for the following

    >
    > > > javascript:alert(typeof document.documentElement.onclick !=
    > > > 'undefined')

    >
    > > > Unfortunately, Firefox returns false for the above.

    >
    > > > Does anyone have a universal feature test for this?

    >
    > > This isn't ideal as it relies on setAttribute, but it does work for
    > > Firefox.  Alternatively, you could define the onclick attribute in the
    > > markup.

    >
    > > var el = getAnElement(), dom0 = true;
    > > if (typeof el.onclick == 'undefined' &&
    > >     isHostMethod(el, 'setAttribute')) {
    > >   el.setAttribute('onclick', '(function() {})');
    > >   dom0 = (typeof el.onclick == 'function');
    > >   el.setAttribute('onclick', '');

    >
    > > }

    >
    > There doesn't seem to be anything in the Element.setAttribute spec
    > that make me think this is a particularly robust test.
    >


    How so? It seems quite reasonable to me. Of course, if IE8 fails to
    fix setAttribute and returns undefined for an unset onclick property,
    you will need to use a suitable setAttribute wrapper.

    > http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-...
    >
    > > If a design relies on DOM0 event support, the best solution is to call
    > > its gateway function like this:

    >
    > > this.onload = myGateway;

    >
    > I agreed that this is a solid solution. What I'm actually trying to
    > determine if the above will work. Here is why...
    >
    > When a page is built with progressive enhancement in mind, the page
    > looks like like the unenhanced version while the whole page loads.
    > When window.onload occurs, then the page can be enhanced and made to
    > look like the enhanced version. For the user with a browser that will
    > support the enhanced version, this is unsightly. For example, a huge


    Right.

    > list of nested ul elements appear on the page for a while while the
    > page loads, when window.onload fires, the hander determines that the
    > nested ul elements can be converted into a drop-down menu or tree
    > menu. When this conversion happens the page appears to "jump" as the
    > CSS changes and the page is re-rendered. This is not really acceptable
    > as more users will be able to have the enhanced version than the
    > unenhanced version.


    I see. You want to test before you add a style rule to hide the
    nested lists. Makes sense. Of course, what scripted browser supports
    adding style rules, but not DOM0 events?

    >
    > So what I want to do is the following...
    >
    > When the page is loading, determine if the browser has enough features
    > to "get out of trouble". If that is the case then add a CSS file to
    > the page with document.write, that will give the page an acceptable
    > appearance while the page loads. When window.onload fires, determine


    Right.

    > if the widget can fully function and enable that widget. If the widget
    > cannot fully function then execute the "get out of trouble" and revert
    > the styling of the HTML to something more pleasing for the unenlivened


    Or, in some cases, something that won't completely break the page for
    the odd browser that supports dynamic styles, but not DOM0 events
    (e.g. un-hide the nested lists.)

    > version. It almost allows me to *tentatively* cross the point of no
    > return with just one foot so the page looks nicer during load.
    >
    > Makes sense?


    Yes.

    >
    > > Is this in regard to the Safari 1.x preventDefault bug on click/
    > > dblclick?

    >
    > Yes my question also impacts this.
    >
    > > I have thought about that one and I don't think it requires
    > > a workaround.

    >
    > You may be right that the workaround is not necessary. I need to think
    > about this more.
    >
    > > If, for instance, a user of Safari 1.x clicks a link
    > > that has a click event listener and preventDefault fails, the browser
    > > will fire the event and then navigate normally. As long as the page
    > > is designed to work without script, this should not cause an issue.

    >
    > But it might cause an issue if the JavaScript does something that
    > shouldn't be followed by the normal navigation. I know we aren't
    > supposed to use <a> links to add items to a shopping cart but suppose
    > someone did. And then suppose they used hijax[1] to make the link add
    > the item to the cart with Ajax. If the Ajax is initiated an then the
    > link is followed, the item will be added to the cart twice.


    Yes. But does that old Safari version even support Ajax? If so, you
    already hinted at the solution: use a button.

    >
    > [1]http://domscripting.com/blog/display/41
    >
    > I am completely aware this is a crappy example but my gut tells me
    > there must be situations where having the JavaScript run followed by
    > the normal navigation is bad.


    It's possible. I wonder how many people still use Safari 1.x though.

    >
    > I suppose the JavaScript could be run after a timeout and that way it
    > only runs if the normal navigation didn't work. Messy solution.


    Yes, that would be ugly.

    >
    > > I know some libraries (e.g. YUI) sniff for the older Safari versions and
    > > fallback to DOM0 for click/dblclick, but I think that is a mistake.

    >
    > I think the sniff is also a mistake. I use DOM0 listeners for all
    > click events. That way I treat all browsers equally and don't need the
    > sniff. I think it would be fine to use DOM0 listeners for all event


    I'm not big on using DOM0 listeners to simulate addEventListener/
    attachEvent (unless neither exists.) For one, it slows down event
    handling significantly. And then there are the possibilities of
    collisions with DOM0 listeners defined in the markup or attached by
    other scripts.

    > handlers. There really isn't a need for addEventListener and
    > attachEvent because a wrapper API around DOM0 can do it all anyway. My


    It can do it all, but is considerably slower in doing it. Responding
    to user input is the last place I would want a bottleneck.

    > problem is that right now I am not testing that DOM0 will work. This
    > is not a large practical problem for me but it is a large problem in
    > trying to write a widget properly.


    Large in what way? I can't think of a user agent that would add a
    style rule with script, but not handle DOM0 events.

    >
    > By the way, this problem is the last detail for an article I am
    > writing for my blog about writing progressive enhancement widgets (a
    > tabbed pane) for the general web. It uses the isHostMethod etc.


    Sounds like a useful article. Every time I set out to write a tabbed
    anything, I run into a problem when style is disabled, but scripting
    is enabled. The only solution I have found for this is to make the
    links in the tabs point to bookmarks in the page and to allow the
    default click action to navigate to them. This obviously has an
    unwanted side effect when style and scripting are both enabled (the
    tabs scroll off the page after switching panes.) How did you handle
    this odd case?

    If
    > anyone is interested in reviewing the article I can post it here for
    > debate. I've never seen such an article and I think such an article
    > has long been needed.


    Post it. We've dealt with the issue of turning a list and a series of
    div's into tabbed panes before, but never the issue of missing DOM0
    event support (AFAIK.)
     
    David Mark, Feb 12, 2008
    #4
  5. On Feb 12, 2:43 pm, David Mark <> wrote:
    > On Feb 12, 4:15 pm, Peter Michaux <> wrote:
    >
    > > On Feb 12, 12:23 pm, David Mark <> wrote:

    >
    > > > On Feb 12, 12:46 pm, Peter Michaux <> wrote:

    >
    > > > > It seems people make a regular habit of testing for the
    > > > > addEventListener and attachEvent methods but they just assume the DOM0-
    > > > > type event interface exists like element.onclick.


    [snip]

    > > > > Does anyone have a universal feature test for this?

    >
    > > > This isn't ideal as it relies on setAttribute, but it does work for
    > > > Firefox. Alternatively, you could define the onclick attribute in the
    > > > markup.

    >
    > > > var el = getAnElement(), dom0 = true;
    > > > if (typeof el.onclick == 'undefined' &&
    > > > isHostMethod(el, 'setAttribute')) {
    > > > el.setAttribute('onclick', '(function() {})');
    > > > dom0 = (typeof el.onclick == 'function');
    > > > el.setAttribute('onclick', '');

    >
    > > > }

    >
    > > There doesn't seem to be anything in the Element.setAttribute spec
    > > that make me think this is a particularly robust test.

    >
    > How so? It seems quite reasonable to me. Of course, if IE8 fails to
    > fix setAttribute and returns undefined for an unset onclick property,
    > you will need to use a suitable setAttribute wrapper.
    >
    > >http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-...


    The spec says that if the attribute doesn't exist, it will create it.
    It doesn't say that the fact that an on* attribute can be created
    means it will be used an an event handler.

    [snip]

    > I see. You want to test before you add a style rule to hide the
    > nested lists. Makes sense. Of course, what scripted browser supports
    > adding style rules, but not DOM0 events?


    I've never encountered one but that would be feature inference based
    on two very unrelated features: style and events.

    [snip]

    > > But it might cause an issue if the JavaScript does something that
    > > shouldn't be followed by the normal navigation. I know we aren't
    > > supposed to use <a> links to add items to a shopping cart but suppose
    > > someone did. And then suppose they used hijax[1] to make the link add
    > > the item to the cart with Ajax. If the Ajax is initiated an then the
    > > link is followed, the item will be added to the cart twice.

    >
    > Yes. But does that old Safari version even support Ajax? If so, you
    > already hinted at the solution: use a button.


    I know someone with Safari 1.9 because she has OS X 10.3 and so can't
    upgrade.

    Early point releases of Safari 2 also had this problem so the problem
    was still occurring in a browser versions released only about a year
    or so ago.


    [snip about using DOM0 event instead of newer]

    > It can do it all, but is considerably slower in doing it. Responding
    > to user input is the last place I would want a bottleneck.


    It can't be that much slower. It is only a matter of running one loop
    in the JavaScript rather than in the C/C++/Java of the browser. Each
    individual handler will probably do something that will eclipse the
    time taken to run this loop.

    [snip]

    > > problem is that right now I am not testing that DOM0 will work. This
    > > is not a large practical problem for me but it is a large problem in
    > > trying to write a widget properly.

    >
    > Large in what way?


    I didn't even need the word "large". It isn't a practical problem for
    me at all. Because...

    > I can't think of a user agent that would add a
    > style rule with script, but not handle DOM0 events.


    True but it is unrelated feature inference.

    > > By the way, this problem is the last detail for an article I am
    > > writing for my blog about writing progressive enhancement widgets (a
    > > tabbed pane) for the general web. It uses the isHostMethod etc.

    >
    > Sounds like a useful article. Every time I set out to write a tabbed
    > anything, I run into a problem when style is disabled, but scripting
    > is enabled. The only solution I have found for this is to make the
    > links in the tabs point to bookmarks in the page and to allow the
    > default click action to navigate to them. This obviously has an
    > unwanted side effect when style and scripting are both enabled (the
    > tabs scroll off the page after switching panes.) How did you handle
    > this odd case?


    I didn't need to. I'll post it and you will see why.

    > If
    >
    > > anyone is interested in reviewing the article I can post it here for
    > > debate. I've never seen such an article and I think such an article
    > > has long been needed.

    >
    > Post it. We've dealt with the issue of turning a list and a series of
    > div's into tabbed panes before, but never the issue of missing DOM0
    > event support (AFAIK.)


    I haven't finished writing the article but I can post the code for the
    example later today.

    Thanks,
    Peter
     
    Peter Michaux, Feb 12, 2008
    #5
  6. Peter Michaux

    David Mark Guest

    On Feb 12, 6:16 pm, Peter Michaux <> wrote:
    > On Feb 12, 2:43 pm, David Mark <> wrote:
    >
    > > On Feb 12, 4:15 pm, Peter Michaux <> wrote:

    >
    > > > On Feb 12, 12:23 pm, David Mark <> wrote:

    >
    > > > > On Feb 12, 12:46 pm, Peter Michaux <> wrote:

    >
    > > > > > It seems people make a regular habit of testing for the
    > > > > > addEventListener and attachEvent methods but they just assume the DOM0-
    > > > > > type event interface exists like element.onclick.

    >
    > [snip]
    >
    >
    >
    >
    >
    > > > > > Does anyone have a universal feature test for this?

    >
    > > > > This isn't ideal as it relies on setAttribute, but it does work for
    > > > > Firefox.  Alternatively, you could define the onclick attribute inthe
    > > > > markup.

    >
    > > > > var el = getAnElement(), dom0 = true;
    > > > > if (typeof el.onclick == 'undefined' &&
    > > > >     isHostMethod(el, 'setAttribute')) {
    > > > >   el.setAttribute('onclick', '(function() {})');
    > > > >   dom0 = (typeof el.onclick == 'function');
    > > > >   el.setAttribute('onclick', '');

    >
    > > > > }

    >
    > > > There doesn't seem to be anything in the Element.setAttribute spec
    > > > that make me think this is a particularly robust test.

    >
    > > How so?  It seems quite reasonable to me.  Of course, if IE8 fails to
    > > fix setAttribute and returns undefined for an unset onclick property,
    > > you will need to use a suitable setAttribute wrapper.

    >
    > > >http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-....

    >
    > The spec says that if the attribute doesn't exist, it will create it.
    > It doesn't say that the fact that an on* attribute can be created
    > means it will be used an an event handler.


    The test checks if the property is a function. An implementation that
    does not support DOM0 isn't likely to pass.

    >
    > [snip]
    >
    > > I see.  You want to test before you add a style rule to hide the
    > > nested lists.  Makes sense.  Of course, what scripted browser supports
    > > adding style rules, but not DOM0 events?

    >
    > I've never encountered one but that would be feature inference based
    > on two very unrelated features: style and events.


    No question.

    >
    > [snip]
    >
    > > > But it might cause an issue if the JavaScript does something that
    > > > shouldn't be followed by the normal navigation. I know we aren't
    > > > supposed to use <a> links to add items to a shopping cart but suppose
    > > > someone did. And then suppose they used hijax[1] to make the link add
    > > > the item to the cart with Ajax. If the Ajax is initiated an then the
    > > > link is followed, the item will be added to the cart twice.

    >
    > > Yes.  But does that old Safari version even support Ajax?  If so, you
    > > already hinted at the solution: use a button.

    >
    > I know someone with Safari 1.9 because she has OS X 10.3 and so can't
    > upgrade.
    >
    > Early point releases of Safari 2 also had this problem so the problem
    > was still occurring in a browser versions released only about a year
    > or so ago.


    Do those auto-upgrade?

    >
    > [snip about using DOM0 event instead of newer]
    >
    > > It can do it all, but is considerably slower in doing it.  Responding
    > > to user input is the last place I would want a bottleneck.

    >
    > It can't be that much slower. It is only a matter of running one loop
    > in the JavaScript rather than in the C/C++/Java of the browser. Each
    > individual handler will probably do something that will eclipse the
    > time taken to run this loop.


    You've got to find the events for the element in question and then
    loop through them. The overhead may not be significant when compared
    to the code in the listeners, but then those should also be as light
    as possible. It could cause a palpable slowdown in events like
    mousemove, resize, scroll, etc.

    >
    > [snip]
    >
    > > > problem is that right now I am not testing that DOM0 will work. This
    > > > is not a large practical problem for me but it is a large problem in
    > > > trying to write a widget properly.

    >
    > > Large in what way?

    >
    > I didn't even need the word "large". It isn't a practical problem for
    > me at all. Because...
    >
    > > I can't think of a user agent that would add a
    > > style rule with script, but not handle DOM0 events.

    >
    > True but it is unrelated feature inference.
    >
    > > > By the way, this problem is the last detail for an article I am
    > > > writing for my blog about writing progressive enhancement widgets (a
    > > > tabbed pane) for the general web. It uses the isHostMethod etc.

    >
    > > Sounds like a useful article.  Every time I set out to write a tabbed
    > > anything, I run into a problem when style is disabled, but scripting
    > > is enabled.  The only solution I have found for this is to make the
    > > links in the tabs point to bookmarks in the page and to allow the
    > > default click action to navigate to them.  This obviously has an
    > > unwanted side effect when style and scripting are both enabled (the
    > > tabs scroll off the page after switching panes.)  How did you handle
    > > this odd case?

    >
    > I didn't need to. I'll post it and you will see why.


    I'm interested to see what you came up with.
     
    David Mark, Feb 12, 2008
    #6
  7. On Feb 12, 3:32 pm, David Mark <> wrote:
    > On Feb 12, 6:16 pm, Peter Michaux <> wrote:
    >
    >
    >
    > > On Feb 12, 2:43 pm, David Mark <> wrote:

    >
    > > > On Feb 12, 4:15 pm, Peter Michaux <> wrote:

    >
    > > > > On Feb 12, 12:23 pm, David Mark <> wrote:

    >
    > > > > > On Feb 12, 12:46 pm, Peter Michaux <> wrote:

    >
    > > > > > > It seems people make a regular habit of testing for the
    > > > > > > addEventListener and attachEvent methods but they just assume the DOM0-
    > > > > > > type event interface exists like element.onclick.

    >
    > > [snip]

    >
    > > > > > > Does anyone have a universal feature test for this?

    >
    > > > > > This isn't ideal as it relies on setAttribute, but it does work for
    > > > > > Firefox. Alternatively, you could define the onclick attribute in the
    > > > > > markup.

    >
    > > > > > var el = getAnElement(), dom0 = true;
    > > > > > if (typeof el.onclick == 'undefined' &&
    > > > > > isHostMethod(el, 'setAttribute')) {
    > > > > > el.setAttribute('onclick', '(function() {})');
    > > > > > dom0 = (typeof el.onclick == 'function');
    > > > > > el.setAttribute('onclick', '');

    >
    > > > > > }

    >
    > > > > There doesn't seem to be anything in the Element.setAttribute spec
    > > > > that make me think this is a particularly robust test.

    >
    > > > How so? It seems quite reasonable to me. Of course, if IE8 fails to
    > > > fix setAttribute and returns undefined for an unset onclick property,
    > > > you will need to use a suitable setAttribute wrapper.

    >
    > > > >http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-...

    >
    > > The spec says that if the attribute doesn't exist, it will create it.
    > > It doesn't say that the fact that an on* attribute can be created
    > > means it will be used an an event handler.

    >
    > The test checks if the property is a function. An implementation that
    > does not support DOM0 isn't likely to pass.


    It is an interesting test and thanks for sharing it. I hoped there was
    something a little more straight forward.

    [snip]

    > > > > But it might cause an issue if the JavaScript does something that
    > > > > shouldn't be followed by the normal navigation. I know we aren't
    > > > > supposed to use <a> links to add items to a shopping cart but suppose
    > > > > someone did. And then suppose they used hijax[1] to make the link add
    > > > > the item to the cart with Ajax. If the Ajax is initiated an then the
    > > > > link is followed, the item will be added to the cart twice.

    >
    > > > Yes. But does that old Safari version even support Ajax? If so, you
    > > > already hinted at the solution: use a button.

    >
    > > I know someone with Safari 1.9 because she has OS X 10.3 and so can't
    > > upgrade.

    >
    > > Early point releases of Safari 2 also had this problem so the problem
    > > was still occurring in a browser versions released only about a year
    > > or so ago.

    >
    > Do those auto-upgrade?


    Version 1.9 does not auto-upgrade because version 2 that requires OS X
    10.4.

    Version 2 does auto-upgrade all the way into version 3.


    > > [snip about using DOM0 event instead of newer]

    >
    > > > It can do it all, but is considerably slower in doing it. Responding
    > > > to user input is the last place I would want a bottleneck.

    >
    > > It can't be that much slower. It is only a matter of running one loop
    > > in the JavaScript rather than in the C/C++/Java of the browser. Each
    > > individual handler will probably do something that will eclipse the
    > > time taken to run this loop.

    >
    > You've got to find the events for the element in question and then
    > loop through them.


    There is no need to find them. Here is some pseudo code...

    function addListener(element, type, callback) {
    if (!(element['on'+type])) {
    element['on'+type] = function(e) {
    var callbacks = arguments.callee.callbacks;
    for (var i=0; i<callbacks.length; i++) {
    callbacks(e);
    }
    };
    element['on'+type].callbacks = [];
    }
    element['on'+type].push(callback);
    };

    [snip]

    Peter
     
    Peter Michaux, Feb 13, 2008
    #7
  8. Peter Michaux

    David Mark Guest

    On Feb 12, 7:16 pm, Peter Michaux <> wrote:
    > On Feb 12, 3:32 pm, David Mark <> wrote:
    >
    >
    >
    >
    >
    > > On Feb 12, 6:16 pm, Peter Michaux <> wrote:

    >
    > > > On Feb 12, 2:43 pm, David Mark <> wrote:

    >
    > > > > On Feb 12, 4:15 pm, Peter Michaux <> wrote:

    >
    > > > > > On Feb 12, 12:23 pm, David Mark <> wrote:

    >
    > > > > > > On Feb 12, 12:46 pm, Peter Michaux <> wrote:

    >
    > > > > > > > It seems people make a regular habit of testing for the
    > > > > > > > addEventListener and attachEvent methods but they just assume the DOM0-
    > > > > > > > type event interface exists like element.onclick.

    >
    > > > [snip]

    >
    > > > > > > > Does anyone have a universal feature test for this?

    >
    > > > > > > This isn't ideal as it relies on setAttribute, but it does work for
    > > > > > > Firefox.  Alternatively, you could define the onclick attribute in the
    > > > > > > markup.

    >
    > > > > > > var el = getAnElement(), dom0 = true;
    > > > > > > if (typeof el.onclick == 'undefined' &&
    > > > > > >     isHostMethod(el, 'setAttribute')) {
    > > > > > >   el.setAttribute('onclick', '(function() {})');
    > > > > > >   dom0 = (typeof el.onclick == 'function');
    > > > > > >   el.setAttribute('onclick', '');

    >
    > > > > > > }

    >
    > > > > > There doesn't seem to be anything in the Element.setAttribute spec
    > > > > > that make me think this is a particularly robust test.

    >
    > > > > How so?  It seems quite reasonable to me.  Of course, if IE8 fails to
    > > > > fix setAttribute and returns undefined for an unset onclick property,
    > > > > you will need to use a suitable setAttribute wrapper.

    >
    > > > > >http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-...

    >
    > > > The spec says that if the attribute doesn't exist, it will create it.
    > > > It doesn't say that the fact that an on* attribute can be created
    > > > means it will be used an an event handler.

    >
    > > The test checks if the property is a function.  An implementation that
    > > does not support DOM0 isn't likely to pass.

    >
    > It is an interesting test and thanks for sharing it. I hoped there was
    > something a little more straight forward.
    >
    > [snip]
    >
    >
    >
    >
    >
    > > > > > But it might cause an issue if the JavaScript does something that
    > > > > > shouldn't be followed by the normal navigation. I know we aren't
    > > > > > supposed to use <a> links to add items to a shopping cart but suppose
    > > > > > someone did. And then suppose they used hijax[1] to make the link add
    > > > > > the item to the cart with Ajax. If the Ajax is initiated an then the
    > > > > > link is followed, the item will be added to the cart twice.

    >
    > > > > Yes.  But does that old Safari version even support Ajax?  If so, you
    > > > > already hinted at the solution: use a button.

    >
    > > > I know someone with Safari 1.9 because she has OS X 10.3 and so can't
    > > > upgrade.

    >
    > > > Early point releases of Safari 2 also had this problem so the problem
    > > > was still occurring in a browser versions released only about a year
    > > > or so ago.

    >
    > > Do those auto-upgrade?

    >
    > Version 1.9 does not auto-upgrade because version 2 that requires OS X
    > 10.4.
    >
    > Version 2 does auto-upgrade all the way into version 3.


    Then it is pretty much a Safari 1.x issue. Until OS X 10.3 dies out,
    the issue will have to be considered on a case by case basis (I don't
    see a general solution that is practical, unless you want to use DOM0
    exclusively.)

    >
    > > > [snip about using DOM0 event instead of newer]

    >
    > > > > It can do it all, but is considerably slower in doing it.  Responding
    > > > > to user input is the last place I would want a bottleneck.

    >
    > > > It can't be that much slower. It is only a matter of running one loop
    > > > in the JavaScript rather than in the C/C++/Java of the browser. Each
    > > > individual handler will probably do something that will eclipse the
    > > > time taken to run this loop.

    >
    > > You've got to find the events for the element in question and then
    > > loop through them.

    >
    > There is no need to find them. Here is some pseudo code...
    >
    > function addListener(element, type, callback) {
    >   if (!(element['on'+type])) {
    >       element['on'+type] = function(e) {
    >         var callbacks = arguments.callee.callbacks;
    >         for (var i=0; i<callbacks.length; i++) {
    >             callbacks(e);
    >         }
    >       };
    >       element['on'+type].callbacks = [];
    >   }
    >   element['on'+type].push(callback);
    >
    > };


    That's not too bad, but clearly more is needed to emulate
    addEventListener (e.g. preserve the "this" reference, handle callbacks
    that return false, etc.) I recently added similar code to my
    library. Rather than looping, I "chained" the (normalized) listeners
    together. The biggest issue that came up was how to allow for
    alternate contexts (i.e. setting "this" to something other than the
    element.) I finally came up with a normalization/storage scheme that
    works for attachEvent and DOM0 without leaking memory in IE. Thinking
    about it now, starting off with something like the above may have led
    to a simpler solution, though I think what I came up with will be
    faster.

    We should revisit this when the CWR addEventListener wrapper comes up
    for discussion.
     
    David Mark, Feb 13, 2008
    #8
  9. On Feb 12, 12:23 pm, David Mark <> wrote:
    > On Feb 12, 12:46 pm, Peter Michaux <> wrote:


    > This isn't ideal as it relies on setAttribute, but it does work for
    > Firefox. Alternatively, you could define the onclick attribute in the
    > markup.
    >
    > var el = getAnElement(), dom0 = true;
    > if (typeof el.onclick == 'undefined' &&
    > isHostMethod(el, 'setAttribute')) {
    > el.setAttribute('onclick', '(function() {})');
    > dom0 = (typeof el.onclick == 'function');
    > el.setAttribute('onclick', '');
    >
    > }



    The setAttribute spec specifically states that the second argument is
    not parsed and is treated like a string literal

    <URL: http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-F68F082>

    I don't like to use a test that will break if a browser becomes _more_
    standards compliant. If Firefox starts to follow the standard the
    above test will stop working.

    ---------

    Here is a test that checks inline handlers are supported. Not related
    to my initial question exactly. If they are not then I imagine that,
    at best, the onclick attribute of the firstChild would be a string.

    var el = document.createElement('div');
    el.innerHTML = '<span onclick="alert(\'hi\');">hi</span>';
    typeof el.firstChild.onclick;


    It works in IE5+ and recent FF, S and O.

    Peter
     
    Peter Michaux, Feb 16, 2008
    #9
  10. Peter Michaux

    David Mark Guest

    On Feb 16, 1:26 pm, Peter Michaux <> wrote:
    > On Feb 12, 12:23 pm, David Mark <> wrote:
    >
    > > On Feb 12, 12:46 pm, Peter Michaux <> wrote:
    > > This isn't ideal as it relies on setAttribute, but it does work for
    > > Firefox.  Alternatively, you could define the onclick attribute in the
    > > markup.

    >
    > > var el = getAnElement(), dom0 = true;
    > > if (typeof el.onclick == 'undefined' &&
    > >     isHostMethod(el, 'setAttribute')) {
    > >   el.setAttribute('onclick', '(function() {})');
    > >   dom0 = (typeof el.onclick == 'function');
    > >   el.setAttribute('onclick', '');

    >
    > > }

    >
    > The setAttribute spec specifically states that the second argument is
    > not parsed and is treated like a string literal


    Absolutely.

    >
    > <URL:http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-....>
    >
    > I don't like to use a test that will break if a browser becomes _more_
    > standards compliant. If Firefox starts to follow the standard the
    > above test will stop working.


    I don't follow you there. If you add an onclick attribute, the DOM
    should return a function when the onclick property is evaluated
    (assuming it supports the DOM0 event model.)

    >
    > ---------
    >
    > Here is a test that checks inline handlers are supported. Not related
    > to my initial question exactly. If they are not then I imagine that,
    > at best, the onclick attribute of the firstChild would be a string.
    >
    > var el = document.createElement('div');
    > el.innerHTML = '<span onclick="alert(\'hi\');">hi</span>';
    > typeof el.firstChild.onclick;


    That's roughly the same thing, but it uses the non-standard innerHTML
    property.
     
    David Mark, Feb 16, 2008
    #10
  11. On Feb 16, 3:16 pm, David Mark <> wrote:
    > On Feb 16, 1:26 pm, Peter Michaux <> wrote:
    >
    >
    >
    > > On Feb 12, 12:23 pm, David Mark <> wrote:

    >
    > > > On Feb 12, 12:46 pm, Peter Michaux <> wrote:
    > > > This isn't ideal as it relies on setAttribute, but it does work for
    > > > Firefox. Alternatively, you could define the onclick attribute in the
    > > > markup.

    >
    > > > var el = getAnElement(), dom0 = true;
    > > > if (typeof el.onclick == 'undefined' &&
    > > > isHostMethod(el, 'setAttribute')) {
    > > > el.setAttribute('onclick', '(function() {})');
    > > > dom0 = (typeof el.onclick == 'function');
    > > > el.setAttribute('onclick', '');

    >
    > > > }

    >
    > > The setAttribute spec specifically states that the second argument is
    > > not parsed and is treated like a string literal

    >
    > Absolutely.
    >
    >
    >
    > > <URL:http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-F68F082>

    >
    > > I don't like to use a test that will break if a browser becomes _more_
    > > standards compliant. If Firefox starts to follow the standard the
    > > above test will stop working.

    >
    > I don't follow you there. If you add an onclick attribute, the DOM
    > should return a function when the onclick property is evaluated
    > (assuming it supports the DOM0 event model.)


    setAttribute takes two string arguments. The second string argument is
    not supposed to be parsed in anyway. So if the first string argument
    is "onclick" and the second string argument is '(function() {})' then
    the value of the element's onclick attribute should be a string
    '(function() {})'. That is, the second string argument should not have
    been converted to a function. That is how I read the section of spec
    that I linked. The key bit being "This value is a simple string".

    I think I'm interpreting the spec correctly but even if my
    interpretation is wrong, the spec does not say anything along the
    lines of "if the string can be evaluated as JavaScript and the
    attribute name starts with 'on' then it is converted to a javascript
    function." I would want to see something like that before I depended
    on that behavior.


    > > ---------

    >
    > > Here is a test that checks inline handlers are supported. Not related
    > > to my initial question exactly. If they are not then I imagine that,
    > > at best, the onclick attribute of the firstChild would be a string.

    >
    > > var el = document.createElement('div');
    > > el.innerHTML = '<span onclick="alert(\'hi\');">hi</span>';
    > > typeof el.firstChild.onclick;

    >
    > That's roughly the same thing, but it uses the non-standard innerHTML
    > property.


    I don't think it is the same thing because the onclick attribute in
    HTML is supposed to contain script. You can see in the following table
    that the type of the value of an on* attribute is %script

    <URL: http://www.w3.org/TR/html401/index/attributes.html>

    Peter
     
    Peter Michaux, Feb 17, 2008
    #11
  12. Peter Michaux

    David Mark Guest

    On Feb 16, 7:17 pm, Peter Michaux <> wrote:
    > On Feb 16, 3:16 pm, David Mark <> wrote:
    >
    >
    >
    >
    >
    > > On Feb 16, 1:26 pm, Peter Michaux <> wrote:

    >
    > > > On Feb 12, 12:23 pm, David Mark <> wrote:

    >
    > > > > On Feb 12, 12:46 pm, Peter Michaux <> wrote:
    > > > > This isn't ideal as it relies on setAttribute, but it does work for
    > > > > Firefox.  Alternatively, you could define the onclick attribute inthe
    > > > > markup.

    >
    > > > > var el = getAnElement(), dom0 = true;
    > > > > if (typeof el.onclick == 'undefined' &&
    > > > >     isHostMethod(el, 'setAttribute')) {
    > > > >   el.setAttribute('onclick', '(function() {})');
    > > > >   dom0 = (typeof el.onclick == 'function');
    > > > >   el.setAttribute('onclick', '');

    >
    > > > > }

    >
    > > > The setAttribute spec specifically states that the second argument is
    > > > not parsed and is treated like a string literal

    >
    > > Absolutely.

    >
    > > > <URL:http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-...>

    >
    > > > I don't like to use a test that will break if a browser becomes _more_
    > > > standards compliant. If Firefox starts to follow the standard the
    > > > above test will stop working.

    >
    > > I don't follow you there.  If you add an onclick attribute, the DOM
    > > should return a function when the onclick property is evaluated
    > > (assuming it supports the DOM0 event model.)

    >
    > setAttribute takes two string arguments. The second string argument is
    > not supposed to be parsed in anyway. So if the first string argument
    > is "onclick" and the second string argument is '(function() {})' then
    > the value of the element's onclick attribute should be a string
    > '(function() {})'. That is, the second string argument should

    not have

    Certainly the attribute value will be a string.

    > been converted to a function. That is how I read the section of spec


    It isn't converted to a function. The DOM simply interprets it as a
    function (in implementations that support DOM0 events.)

    > that I linked. The key bit being "This value is a simple string".


    If you set a disabled attribute to the string "disabled", the DOM will
    interpret that the element is disabled and will return a boolean
    (true) for the disabled property. AFAIK, IE is the only browser that
    mixes up the document tree with the DOM (which requires a previously
    discussed workaround to make it behave properly.)

    >
    > I think I'm interpreting the spec correctly but even if my
    > interpretation is wrong, the spec does not say anything along the
    > lines of "if the string can be evaluated as JavaScript and the
    > attribute name starts with 'on' then it is converted to a javascript
    > function." I would want to see something like that before I depended
    > on that behavior.
    >
    > > > ---------

    >
    > > > Here is a test that checks inline handlers are supported. Not related
    > > > to my initial question exactly. If they are not then I imagine that,
    > > > at best, the onclick attribute of the firstChild would be a string.

    >
    > > > var el = document.createElement('div');
    > > > el.innerHTML = '<span onclick="alert(\'hi\');">hi</span>';
    > > > typeof el.firstChild.onclick;

    >
    > > That's roughly the same thing, but it uses the non-standard innerHTML
    > > property.

    >
    > I don't think it is the same thing because the onclick attribute in
    > HTML is supposed to contain script. You can see in the following table


    Both versions use DOM manipulation to mutate the underlying document
    (or fragment in your case.) AFAIK, the DOM will reflect the changes
    to the document the same for each. The difference is that yours uses
    innerHTML, which has no standard specification. The only possible
    benefit I can see to using innerHTML for this is that it will work in
    IE without a setAttribute workaround.
     
    David Mark, Feb 17, 2008
    #12
  13. On Feb 16, 4:34 pm, David Mark <> wrote:
    > On Feb 16, 7:17 pm, Peter Michaux <> wrote:
    >
    > > On Feb 16, 3:16 pm, David Mark <> wrote:

    >
    > > > On Feb 16, 1:26 pm, Peter Michaux <> wrote:

    >
    > > > > On Feb 12, 12:23 pm, David Mark <> wrote:

    >
    > > > > > On Feb 12, 12:46 pm, Peter Michaux <> wrote:
    > > > > > This isn't ideal as it relies on setAttribute, but it does work for
    > > > > > Firefox. Alternatively, you could define the onclick attribute in the
    > > > > > markup.

    >
    > > > > > var el = getAnElement(), dom0 = true;
    > > > > > if (typeof el.onclick == 'undefined' &&
    > > > > > isHostMethod(el, 'setAttribute')) {
    > > > > > el.setAttribute('onclick', '(function() {})');
    > > > > > dom0 = (typeof el.onclick == 'function');
    > > > > > el.setAttribute('onclick', '');

    >
    > > > > > }

    >
    > > > > The setAttribute spec specifically states that the second argument is
    > > > > not parsed and is treated like a string literal

    >
    > > > Absolutely.

    >
    > > > > <URL:http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-...>

    >
    > > > > I don't like to use a test that will break if a browser becomes _more_
    > > > > standards compliant. If Firefox starts to follow the standard the
    > > > > above test will stop working.

    >
    > > > I don't follow you there. If you add an onclick attribute, the DOM
    > > > should return a function when the onclick property is evaluated
    > > > (assuming it supports the DOM0 event model.)

    >
    > > setAttribute takes two string arguments. The second string argument is
    > > not supposed to be parsed in anyway. So if the first string argument
    > > is "onclick" and the second string argument is '(function() {})' then
    > > the value of the element's onclick attribute should be a string
    > > '(function() {})'. That is, the second string argument should

    >
    > not have
    >
    > Certainly the attribute value will be a string.
    >
    > > been converted to a function. That is how I read the section of spec

    >
    > It isn't converted to a function. The DOM simply interprets it as a
    > function (in implementations that support DOM0 events.)



    You are right and this is not completely intuitive to me (obviously
    since I was wrong).

    I did a little firebug console session

    >>> var el = document.createElement('div');
    >>> el.setAttribute('onclick', "(function(){})");


    >>> typeof el.getAttribute('onclick')

    "string"

    >>> el.getAttribute('onclick');

    "(function(){})"

    >>> typeof el.onclick

    "function"

    >>> el.onclick

    onclick(event)


    And then with an error in the string

    >>> var el = document.createElement('div');
    >>> el.setAttribute('onclick', 'foobar*#$)');


    >>> typeof el.getAttribute('onclick');

    "string"

    >>> el.getAttribute('onclick');

    "foobar*#$)"

    >>> el.onclick

    illegal character
    foobar*#$)

    >>> typeof el.onclick

    illegal character
    foobar*#$)


    It is interesting that the error comes only when trying to access the
    el.onclick attribute directly. The JavaScript engine does the
    conversion at that time which seems like a good idea.


    > > that I linked. The key bit being "This value is a simple string".

    >
    > If you set a disabled attribute to the string "disabled", the DOM will
    > interpret that the element is disabled and will return a boolean
    > (true) for the disabled property. AFAIK, IE is the only browser that
    > mixes up the document tree with the DOM (which requires a previously
    > discussed workaround to make it behave properly.)


    I'll think about this some more for the original problem.

    Thank you,
    Peter
     
    Peter Michaux, Feb 17, 2008
    #13
  14. On Feb 12, 12:23 pm, David Mark <> wrote:

    [snip]

    > Is this in regard to the Safari 1.x preventDefault bug on click/
    > dblclick? I have thought about that one and I don't think it requires
    > a workaround. If, for instance, a user of Safari 1.x clicks a link
    > that has a click event listener and preventDefault fails, the browser
    > will fire the event and then navigate normally. As long as the page
    > is designed to work without script, this should not cause an issue. I
    > know some libraries (e.g. YUI) sniff for the older Safari versions and
    > fallback to DOM0 for click/dblclick, but I think that is a mistake.


    If a workaround for Safari is required then I think all browsers
    should use it and it should be the DOM0 style of work around.

    However, I did think up a test for the Safari problem. I don't
    actually have a broken Safari around but I think the following idea
    should work. This is just the idea and needs its own feature testing
    before it runs. This is an onerous test for the browser to run and
    cannot run until the DOM is ready.


    var iframe = document.createElement('iframe');
    document.body.appendChild(iframe);

    // get the iframe as a window object
    var iframe = window.frames[window.frames.length-1];
    var d = iframe.document;
    d.open();
    d.write('<html><head><title>test</title></head>' +
    '<body><h1>hi</h1><a id="fooLink" href="#foo">' +
    'click me</a></body></head>');
    d.close();

    var link = d.getElementById('fooLink');
    // comment out the next line to see the test fail
    link.addEventListener('click', function(e) {e.preventDefault()});

    var e = d.createEvent('MouseEvents');
    e.initMouseEvent('click', true, true, iframe, 1, 0, 0, 0, 0,
    false, false, false, false, false, null);
    link.dispatchEvent(e);

    setTimeout(function() {
    if (/foo/.test(iframe.location)) {
    alert('failed');
    }
    else {
    alert('passed');
    }
    }, 100);



    Peter
     
    Peter Michaux, Feb 17, 2008
    #14
  15. Safari preventDefault solved?

    On Feb 12, 12:23 pm, David Mark <> wrote:

    > Is this in regard to the Safari 1.x preventDefault bug on click/
    > dblclick? I have thought about that one and I don't think it requires
    > a workaround.



    I think the workaround is tiny and doesn't require using DOM0
    listeners how it is done in YUI. They basically have two entire Event
    libraries in one.

    Below is the idea for click events. I suppose a user cannot cancel the
    bubble for this to work. I just thought this up. Does it have any
    merit?


    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/strict.dtd">

    <html>
    <head>

    <title>safari click test</title>

    <script type="text/javascript">

    var prevented = false;

    var preventDef = function(e) {
    if (e.preventDefault) {
    prevented = true;
    e.preventDefault();
    }
    else {
    e.returnValue = false;
    }
    };

    var check = function() {
    var result = !prevented;
    prevented = false;
    return result;
    };

    // use only one DOM0 handler
    document.documentElement.onclick = check;

    var handleClick = function(e) {
    preventDef(e);
    };

    window.onload = function() {
    document.getElementById('foo'
    ).addEventListener('click',
    handleClick, false);
    };

    </script>


    </head>
    <body onclick="check(event);">

    <p><a id="foo" href="#foo">click</a></p>

    </body>
    </html>
     
    Peter Michaux, Feb 17, 2008
    #15
  16. Peter Michaux

    David Mark Guest

    On Feb 17, 1:28 am, Peter Michaux <> wrote:
    > On Feb 12, 12:23 pm, David Mark <> wrote:
    >
    > [snip]
    >
    > > Is this in regard to the Safari 1.x preventDefault bug on click/
    > > dblclick?  I have thought about that one and I don't think it requires
    > > a workaround.  If, for instance, a user of Safari 1.x clicks a link
    > > that has a click event listener and preventDefault fails, the browser
    > > will fire the event and then navigate normally.  As long as the page
    > > is designed to work without script, this should not cause an issue.  I
    > > know some libraries (e.g. YUI) sniff for the older Safari versions and
    > > fallback to DOM0 for click/dblclick, but I think that is a mistake.

    >
    > If a workaround for Safari is required then I think all browsers
    > should use it and it should be the DOM0 style of work around.
    >
    > However, I did think up a test for the Safari problem. I don't
    > actually have a broken Safari around but I think the following idea
    > should work. This is just the idea and needs its own feature testing
    > before it runs. This is an onerous test for the browser to run and
    > cannot run until the DOM is ready.
    >
    > var iframe = document.createElement('iframe');
    > document.body.appendChild(iframe);
    >
    > // get the iframe as a window object
    > var iframe = window.frames[window.frames.length-1];
    > var d = iframe.document;
    > d.open();
    > d.write('<html><head><title>test</title></head>' +
    >                    '<body><h1>hi</h1><a id="fooLink"href="#foo">' +
    >                    'click me</a></body></head>');
    > d.close();
    >
    > var link = d.getElementById('fooLink');
    > // comment out the next line to see the test fail
    > link.addEventListener('click', function(e) {e.preventDefault()});
    >
    > var e = d.createEvent('MouseEvents');
    > e.initMouseEvent('click', true, true, iframe, 1, 0, 0, 0, 0,
    >                  false, false, false, false, false, null);
    > link.dispatchEvent(e);
    >
    > setTimeout(function() {
    >   if (/foo/.test(iframe.location)) {
    >     alert('failed');
    >  }
    >  else {
    >     alert('passed');
    >   }
    >
    > }, 100);


    The timeout bothers me and are you sure the Safari versions in
    question support initMouseEvent?

    All in all, I think this one to design out of the system (i.e. don't
    rely on preventDefault working for click events.) Better still, try
    to avoid using links as buttons. That reminds me, I really need to
    dig up an old property sheet I wrote that used (dynamically created)
    buttons for tabs. It didn't require a lot of CSS, looked just like a
    strip of tabs and worked well in every browser I tested (NS6.2-
    present, Windows Safari, Opera 9, FireFox 2, IE5-present.) Let me
    know when you get to the point of styling the tabs for your example
    widget...
     
    David Mark, Feb 17, 2008
    #16
  17. Peter Michaux

    David Mark Guest

    Re: Safari preventDefault solved?

    On Feb 17, 1:54 am, Peter Michaux <> wrote:
    > On Feb 12, 12:23 pm, David Mark <> wrote:
    >
    > > Is this in regard to the Safari 1.x preventDefault bug on click/
    > > dblclick?  I have thought about that one and I don't think it requires
    > > a workaround.

    >
    > I think the workaround is tiny and doesn't require using DOM0
    > listeners how it is done in YUI. They basically have two entire Event
    > libraries in one.


    Yes, I made DOM0 support an optional module for this reason. It
    strikes me that some applications may need to know if addEventListener/
    attachEvent are actually supported or not (without resorting to
    detecting the individual methods.) So if DOM0 support is excluded,
    attachListener (and the others) are created only if the DOM2 event
    model is available. The exception is attachDocumentReadyListener,
    which always uses a DOM0 load listener as a fallback (too many
    unrelated features would be short-circuited in DOM0 browsers without
    it.)

    >
    > Below is the idea for click events. I suppose a user cannot cancel the
    > bubble for this to work. I just thought this up. Does it have any
    > merit?


    You lost me on the "user cannot cancel the bubble" point.

    >
    > <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
    >   "http://www.w3.org/TR/html4/strict.dtd">
    >
    > <html>
    > <head>
    >
    >   <title>safari click test</title>
    >
    >   <script type="text/javascript">
    >
    >     var prevented = false;
    >
    >     var preventDef = function(e) {
    >       if (e.preventDefault) {


    You want to check if e exists first.

    >         prevented = true;
    >         e.preventDefault();
    >       }
    >       else {
    >         e.returnValue = false;
    >       }
    >     };
    >
    >     var check = function() {
    >       var result = !prevented;
    >       prevented = false;
    >       return result;
    >     };
    >
    >     // use only one DOM0 handler
    >     document.documentElement.onclick = check;
    >
    >     var handleClick = function(e) {
    >       preventDef(e);
    >     };
    >
    >     window.onload = function() {
    >       document.getElementById('foo'
    >        ).addEventListener('click',
    >                    handleClick, false);
    >     };
    >
    >   </script>
    >
    > </head>
    > <body onclick="check(event);">
    >
    >   <p><a id="foo" href="#foo">click</a></p>
    >
    > </body>
    > </html>


    It seems you are mixing up event bubbling with default actions. You
    could test stopPropagation with this, but that method isn't broken in
    any browser that I know of.
     
    David Mark, Feb 17, 2008
    #17
  18. On Feb 16, 10:57 pm, David Mark <> wrote:
    > On Feb 17, 1:28 am, Peter Michaux <> wrote:
    >
    >
    >
    > > On Feb 12, 12:23 pm, David Mark <> wrote:

    >
    > > [snip]

    >
    > > > Is this in regard to the Safari 1.x preventDefault bug on click/
    > > > dblclick? I have thought about that one and I don't think it requires
    > > > a workaround. If, for instance, a user of Safari 1.x clicks a link
    > > > that has a click event listener and preventDefault fails, the browser
    > > > will fire the event and then navigate normally. As long as the page
    > > > is designed to work without script, this should not cause an issue. I
    > > > know some libraries (e.g. YUI) sniff for the older Safari versions and
    > > > fallback to DOM0 for click/dblclick, but I think that is a mistake.

    >
    > > If a workaround for Safari is required then I think all browsers
    > > should use it and it should be the DOM0 style of work around.

    >
    > > However, I did think up a test for the Safari problem. I don't
    > > actually have a broken Safari around but I think the following idea
    > > should work. This is just the idea and needs its own feature testing
    > > before it runs. This is an onerous test for the browser to run and
    > > cannot run until the DOM is ready.

    >
    > > var iframe = document.createElement('iframe');
    > > document.body.appendChild(iframe);

    >
    > > // get the iframe as a window object
    > > var iframe = window.frames[window.frames.length-1];
    > > var d = iframe.document;
    > > d.open();
    > > d.write('<html><head><title>test</title></head>' +
    > > '<body><h1>hi</h1><a id="fooLink" href="#foo">' +
    > > 'click me</a></body></head>');
    > > d.close();

    >
    > > var link = d.getElementById('fooLink');
    > > // comment out the next line to see the test fail
    > > link.addEventListener('click', function(e) {e.preventDefault()});

    >
    > > var e = d.createEvent('MouseEvents');
    > > e.initMouseEvent('click', true, true, iframe, 1, 0, 0, 0, 0,
    > > false, false, false, false, false, null);
    > > link.dispatchEvent(e);

    >
    > > setTimeout(function() {
    > > if (/foo/.test(iframe.location)) {
    > > alert('failed');
    > > }
    > > else {
    > > alert('passed');
    > > }

    >
    > > }, 100);

    >
    > The timeout bothers me


    It bothers me a lot. The whole thing is awful but it is in the group
    archives and if someone wants to make a test this may help them start.

    > and are you sure the Safari versions in
    > question support initMouseEvent?


    I'm not sure.

    > All in all, I think this one to design out of the system (i.e. don't
    > rely on preventDefault working for click events.) Better still, try
    > to avoid using links as buttons. That reminds me, I really need to
    > dig up an old property sheet I wrote that used (dynamically created)
    > buttons for tabs. It didn't require a lot of CSS, looked just like a
    > strip of tabs and worked well in every browser I tested (NS6.2-
    > present, Windows Safari, Opera 9, FireFox 2, IE5-present.) Let me
    > know when you get to the point of styling the tabs for your example
    > widget...


    I suppose for marketing purposes the tabbed pane should look pretty.
    Then people will think the JavaScript is better :-S

    Peter
     
    Peter Michaux, Feb 17, 2008
    #18
  19. Peter Michaux

    David Mark Guest

    On Feb 17, 2:11 am, Peter Michaux <> wrote:
    > On Feb 16, 10:57 pm, David Mark <> wrote:
    >
    >
    >
    >
    >
    > > On Feb 17, 1:28 am, Peter Michaux <> wrote:

    >
    > > > On Feb 12, 12:23 pm, David Mark <> wrote:

    >
    > > > [snip]

    >
    > > > > Is this in regard to the Safari 1.x preventDefault bug on click/
    > > > > dblclick?  I have thought about that one and I don't think it requires
    > > > > a workaround.  If, for instance, a user of Safari 1.x clicks a link
    > > > > that has a click event listener and preventDefault fails, the browser
    > > > > will fire the event and then navigate normally.  As long as the page
    > > > > is designed to work without script, this should not cause an issue.  I
    > > > > know some libraries (e.g. YUI) sniff for the older Safari versions and
    > > > > fallback to DOM0 for click/dblclick, but I think that is a mistake.

    >
    > > > If a workaround for Safari is required then I think all browsers
    > > > should use it and it should be the DOM0 style of work around.

    >
    > > > However, I did think up a test for the Safari problem. I don't
    > > > actually have a broken Safari around but I think the following idea
    > > > should work. This is just the idea and needs its own feature testing
    > > > before it runs. This is an onerous test for the browser to run and
    > > > cannot run until the DOM is ready.

    >
    > > > var iframe = document.createElement('iframe');
    > > > document.body.appendChild(iframe);

    >
    > > > // get the iframe as a window object
    > > > var iframe = window.frames[window.frames.length-1];
    > > > var d = iframe.document;
    > > > d.open();
    > > > d.write('<html><head><title>test</title></head>' +
    > > >                    '<body><h1>hi</h1><a id="fooLink" href="#foo">' +
    > > >                    'click me</a></body></head>');
    > > > d.close();

    >
    > > > var link = d.getElementById('fooLink');
    > > > // comment out the next line to see the test fail
    > > > link.addEventListener('click', function(e) {e.preventDefault()});

    >
    > > > var e = d.createEvent('MouseEvents');
    > > > e.initMouseEvent('click', true, true, iframe, 1, 0, 0, 0, 0,
    > > >                  false, false, false, false, false, null);
    > > > link.dispatchEvent(e);

    >
    > > > setTimeout(function() {
    > > >   if (/foo/.test(iframe.location)) {
    > > >     alert('failed');
    > > >  }
    > > >  else {
    > > >     alert('passed');
    > > >   }

    >
    > > > }, 100);

    >
    > > The timeout bothers me

    >
    > It bothers me a lot. The whole thing is awful but it is in the group
    > archives and if someone wants to make a test this may help them start.
    >
    > > and are you sure the Safari versions in
    > > question support initMouseEvent?

    >
    > I'm not sure.
    >
    > > All in all, I think this one to design out of the system (i.e. don't
    > > rely on preventDefault working for click events.)  Better still, try
    > > to avoid using links as buttons.  That reminds me, I really need to
    > > dig up an old property sheet I wrote that used (dynamically created)
    > > buttons for tabs.  It didn't require a lot of CSS, looked just like a
    > > strip of tabs and worked well in every browser I tested (NS6.2-
    > > present, Windows Safari, Opera 9, FireFox 2, IE5-present.)  Let me
    > > know when you get to the point of styling the tabs for your example
    > > widget...

    >
    > I suppose for marketing purposes the tabbed pane should look pretty.
    > Then people will think the JavaScript is better :-S
    >


    LOL. But seriously, this was as "pretty" as a strip of tabs can be.
    IIRC, my aim at the time was to make it look like a Windows property
    sheet.
     
    David Mark, Feb 17, 2008
    #19
  20. Re: Safari preventDefault solved?

    On Feb 16, 11:10 pm, David Mark <> wrote:
    > On Feb 17, 1:54 am, Peter Michaux <> wrote:
    >
    > > On Feb 12, 12:23 pm, David Mark <> wrote:

    >
    > > > Is this in regard to the Safari 1.x preventDefault bug on click/
    > > > dblclick? I have thought about that one and I don't think it requires
    > > > a workaround.

    >
    > > I think the workaround is tiny


    [snip]

    > > Below is the idea for click events. I suppose a user cannot cancel the
    > > bubble for this to work. I just thought this up. Does it have any
    > > merit?

    >
    > You lost me on the "user cannot cancel the bubble" point.


    The function called "check" needs to run as a DOM0 event handler and
    return false to actually make the prevent default happen in the broken
    Safari browsers.

    I think there could be workarounds so that cancel bubble would still
    be allowed.


    > > <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
    > > "http://www.w3.org/TR/html4/strict.dtd">

    >
    > > <html>
    > > <head>

    >
    > > <title>safari click test</title>

    >
    > > <script type="text/javascript">

    >
    > > var prevented = false;

    >
    > > var preventDef = function(e) {
    > > if (e.preventDefault) {

    >
    > You want to check if e exists first.
    >
    >
    >
    > > prevented = true;
    > > e.preventDefault();
    > > }
    > > else {
    > > e.returnValue = false;
    > > }
    > > };

    >
    > > var check = function() {
    > > var result = !prevented;
    > > prevented = false;
    > > return result;
    > > };

    >
    > > // use only one DOM0 handler
    > > document.documentElement.onclick = check;

    >
    > > var handleClick = function(e) {
    > > preventDef(e);
    > > };

    >
    > > window.onload = function() {
    > > document.getElementById('foo'
    > > ).addEventListener('click',
    > > handleClick, false);
    > > };

    >
    > > </script>

    >
    > > </head>
    > > <body onclick="check(event);">

    >
    > > <p><a id="foo" href="#foo">click</a></p>

    >
    > > </body>
    > > </html>

    >
    > It seems you are mixing up event bubbling with default actions.


    In a broken Safari browser, at least one DOM0 handler for the event
    needs to return false to prevent the default behavior. The normal
    solution is to use legacy handlers for click and dblclick in so the
    actual handler that wants to prevent default will return false.
    However why not just let the event bubble up the dom a bit and then
    have the document.documentElement.onclick handler be the one to return
    false. I think the above code might be good.

    > You
    > could test stopPropagation with this, but that method isn't broken in
    > any browser that I know of.


    I don't follow. The above isn't a test. It is the workaround.

    Peter
     
    Peter Michaux, Feb 17, 2008
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Brian van den Broek
    Replies:
    3
    Views:
    862
    Jeremy Bowers
    Apr 3, 2005
  2. Brian van den Broek
    Replies:
    2
    Views:
    398
    Brian van den Broek
    Apr 5, 2005
  3. Chris

    Testing and Load Testing

    Chris, Mar 4, 2007, in forum: ASP .Net
    Replies:
    2
    Views:
    336
  4. Peter Michaux

    typeof for feature testing host methods

    Peter Michaux, Dec 15, 2007, in forum: Javascript
    Replies:
    61
    Views:
    539
    Peter Michaux
    Dec 21, 2007
  5. David Mark

    Mousewheel event does not support DOM0 in FF

    David Mark, Jun 2, 2010, in forum: Javascript
    Replies:
    9
    Views:
    155
    David Mark
    Jun 4, 2010
Loading...

Share This Page