Skip to main content

Bug Tracker

Side navigation

#7278 closed bug (cantfix)

Opened October 22, 2010 03:59AM UTC

Closed April 01, 2011 12:29AM UTC

Last modified March 14, 2012 02:33AM UTC

Error preventing delayed special events in IE

Reported by: scottgonzalez Owned by:
Priority: high Milestone:
Component: event Version: 1.4.3
Keywords: special events Cc:
Blocked by: Blocking:
Description

We ran into a problem using the hoverintent special event with accordions in jQuery UI. I've narrowed down the problem to calling event.preventDefault() when the special event is triggered through a timeout from a native event. For some reason IE won't let you set event.returnValue inside event.preventDefault().

The only solution I've been able to find is wrapping the e.returnValue = false in a try/catch inside jQuery.Event.prototype.preventDefault().

full demo: http://jqueryui.com/demos/accordion/hoverintent.html

reduced test case: http://jsfiddle.net/GSD84/1/

Attachments (0)
Change History (11)

Changed October 22, 2010 04:00AM UTC by scottgonzalez comment:1

description: We ran into a problem using the hoverintent special event with accordions in jQuery UI. I've narrowed down the problem to calling event.preventDefault() when the special event is triggered through a timeout from a native event. For some reason IE won't let you set event.returnValue inside event.preventDefault(). \ \ The only solution I've been able to find is wrapping the `e.returnValue = false` in a try/catch inside jQuery.Event.prototype.preventDefault(). \ \ full demo: http://jqueryui.com/demos/accordion/hoverintent.html \ reduced test case: http://jsfiddle.net/GSD84/1/We ran into a problem using the hoverintent special event with accordions in jQuery UI. I've narrowed down the problem to calling event.preventDefault() when the special event is triggered through a timeout from a native event. For some reason IE won't let you set event.returnValue inside event.preventDefault(). \ \ The only solution I've been able to find is wrapping the `e.returnValue = false` in a try/catch inside jQuery.Event.prototype.preventDefault(). \ \ full demo: http://jqueryui.com/demos/accordion/hoverintent.html[[BR]] \ reduced test case: http://jsfiddle.net/GSD84/1/

Changed October 22, 2010 04:00AM UTC by scottgonzalez comment:2

component: unfiledevent
description: We ran into a problem using the hoverintent special event with accordions in jQuery UI. I've narrowed down the problem to calling event.preventDefault() when the special event is triggered through a timeout from a native event. For some reason IE won't let you set event.returnValue inside event.preventDefault(). \ \ The only solution I've been able to find is wrapping the `e.returnValue = false` in a try/catch inside jQuery.Event.prototype.preventDefault(). \ \ full demo: http://jqueryui.com/demos/accordion/hoverintent.html[[BR]] \ reduced test case: http://jsfiddle.net/GSD84/1/We ran into a problem using the hoverintent special event with accordions in jQuery UI. I've narrowed down the problem to calling event.preventDefault() when the special event is triggered through a timeout from a native event. For some reason IE won't let you set event.returnValue inside event.preventDefault(). \ \ The only solution I've been able to find is wrapping the `e.returnValue = false` in a try/catch inside jQuery.Event.prototype.preventDefault(). \ \ full demo: http://jqueryui.com/demos/accordion/hoverintent.html [[BR]] \ reduced test case: http://jsfiddle.net/GSD84/1/

Changed October 23, 2010 09:25PM UTC by SlexAxton comment:3

keywords: → special events
priority: undecidedhigh
status: newopen

Changed December 02, 2010 05:59PM UTC by ravasthi@mac.com comment:4

I'm not sure if this will be at all helpful, but in my own experience with this issue, it's not just e.returnValue but ''all'' members of the event object that are inaccessible, including e.cancelBubble from event.stopPropagation().

In my case, I'm using the jQuery Tools tooltip plugin with a delay. When handling a custom event that fires just before the tooltip is shown, I do a test that would allow me to prevent the appearance of the tooltip by returning false from the handler. When I do that, and consequently jQuery.handle() calls event.preventDefault() and event.stopPropagation(), both of them have trouble accessing the original event object.

I used the IE script debugger, and at that point in time, every property of the event object is marked as Member not found.

Changed April 01, 2011 12:29AM UTC by dmethvin comment:5

resolution: → cantfix
status: openclosed

I think the problem is that in IE the global event object only exists during the time the event is being delivered. That is some special IE host object and not a standard Javascript object that can be held in a closure. When the code is called in a timeout the event delivery is done so event object has dissolved and is no longer accessible.

See the comments here:

http://msdn.microsoft.com/en-us/library/ms535863%28v=vs.85%29.aspx

As a workaround you could try newEvent = document.createEventObject(event) or perhaps newEvent = $.extend({}, event) if you need an honest JS object. In any case I think this is a limitation of IE that we can't circumvent so you'll need to fake something up.

Changed January 31, 2012 02:05PM UTC by scottgonzalez comment:6

Could we potentially set a flag that causes preventDefault() and other methods that we normalize to not bubble to the original event if the're called asynchronously?

Changed January 31, 2012 04:01PM UTC by dmethvin comment:7

Since we're feature-detecting the presence of the preventDefault method, it should be okay to do this in your handle hook:

http://jsfiddle.net/GSD84/11/

You could copy over any properties you need of course. To prevent clobbering subsequent attached handlers you'll need to restore event.type and event.originalEvent before returning though, which means you also need to make a copy of the event that setTimeout can use when it fires.

There's no way to handle this generically in core without knowing you intend to hold onto the event object past the normal delivery of the event. Are there are lots of cases like this, or is hoverIntent the main usage?

Changed January 31, 2012 04:24PM UTC by scottgonzalez comment:8

I'm sure there are other use cases. Off the top of my head, the only other event I can think of is taphold. jQuery Mobile implemented taphold, but they don't pass any of the original event information along. If they did, it would have to come from an event that is already gone, such as mousedown or touchstart. I'll try to put together a patch with the generic solution I was thinking of, though it may not be worth landing even if I can implement it.

Changed January 31, 2012 06:34PM UTC by scottgonzalez comment:9

Ok, so we can't implement the fix I was thinking of, but wrapping event.returnValue = false; in a try/catch fixes the problem. This seems really painful for developers to work around inside their own special events, especially when supporting multiple versions of jQuery.

Changed January 31, 2012 06:54PM UTC by dmethvin comment:10

It's going to crash on any direct/indirect use of the now-defunct originalEvent inside the user's handler, not just that one. Technically the code isn't doing what it intended on any platform, since a delayed .preventDefault() or .stopPropagation() won't have any effect. By making the handler async it's become impossible to manipulate the event state since the event is technically over. It's just a question of whether that happens silently or with an error.

If you don't need originalEvent in the timeout can you try setting it to an empty Javascript object instead of leaving the global IE event object in the closure? That seemed to work in the fiddle I posted. Something like that should apply to all versions of jQuery so you have backcompat, which the try/catch won't do.

Changed January 31, 2012 07:08PM UTC by scottgonzalez comment:11

I suppose that's fine. You win this round :-)