PDA

View Full Version : [FIXED-445][3.1] Firefox/Document mousedown event bug



kavih7
17 Jan 2010, 8:58 PM
Ext version tested:

Ext 3.1.0


css used:

only default ext-all.css


Browser versions tested against:

FF3.5.7 (firebug 1.4.5 installed)


Operating System:

Windows Vista
Ubuntu 9.10 (karmic)


Description:

When a listener is attached to the DOM document for a mousedown event (from Element.on() or whatever), internally the EventManager adds a listener to the Ext.EventManager.stoppedMouseDownEvent property. When Element.un() or whatever tries to remove the listener later, it does not succeed with removing the listener from the stoppedMouseDownEvent property. If the element(s) originally associated with the event handler is no longer in the DOM (Ext.Window closes or something), any future mousedown events will trigger the handler and can cause bugs when trying to access that no longer present element(s).


Test Case:
See this URL : http://www.kavih.com/misc/ext/md_bug


Steps to reproduce the problem:

Open the URL from above
Open firebug console to watch the JS error be reported
Make sure to click inside the spinner to give it focus (this adds a mousedown event listener to the DOM document)
Click the cancel button for the window that first shows (this blurs the spinner, causing an attempt to remove the DOM document mousedown event listener)
Click the "click me" link
Drag the window that shows and watch the error appear in the firebug console (the handler from step 3 above runs)


The result that was expected:

No error


The result that occurs instead:

An error occurs for most mousedown events


Screenshot or Video:

N/A (Just see it at the URL/directions provided above).


Debugging already done:

Found that the Ext.EventManager.removeListener method will return before removing a mousedown listener from the Ext.EventManager.stoppedMouseDownEvent property for DOM document listeners.


Possible fix:

The code in red added to the Ext.EventManager.removeListener method will remove the listener appropriately before returning from the method. However, I have not tested this for efficiency or refactoring purposes. You'll notice the code added is just the code from the bottom of the method (which normally doesn't get reached).



removeListener : function(el, eventName, fn, scope){
el = Ext.getDom(el);
var id = getId(el),
f = el && (Ext.elCache[id].events)[eventName] || [],
wrap, i, l, k, wf;

for (i = 0, len = f.length; i < len; i++) {
if (Ext.isArray(f[i]) && f[i][0] == fn && (!scope || f[i][2] == scope)) {
if(fn.task) {
fn.task.cancel();
delete fn.task;
}
k = fn.tasks && fn.tasks.length;
if(k) {
while(k--) {
fn.tasks[k].cancel();
}
delete fn.tasks;
}
wf = wrap = f[i][1];
if (E.extAdapter) {
wf = f[i][3];
}
E.un(el, eventName, wf);
f.splice(i,1);
if (f.length === 0) {
delete Ext.elCache[id].events[eventName];
}
if(eventName == "mousedown" && el == DOC && wrap){
Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
}
for (k in Ext.elCache[id].events) {
return false;
}
Ext.elCache[id].events = {};
return false;
}
}


if(eventName == "mousewheel" && el.addEventListener && wrap){
el.removeEventListener("DOMMouseScroll", wrap, false);
}

if(eventName == "mousedown" && el == DOC && wrap){
Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
}
}

MartiCode
18 Jan 2010, 1:29 AM
That problem can be easily checked: every time a tooltip is shown and disappear, the mousedown event isn't removed and Ext.EventManager.stoppedMouseDownEvent.listeners is growing by 1 element.

Condor
18 Jan 2010, 1:45 AM
Shouldn't that be:

removeListener : function(el, eventName, fn, scope){
el = Ext.getDom(el);
var id = getId(el),
f = el && (Ext.elCache[id].events)[eventName] || [],
wrap, i, l, k, wf, len, fnc;
for (i = 0, len = f.length; i < len; i++) {
if (Ext.isArray(fnc = f[i]) && fnc[0] == fn && (!scope || fnc[2] == scope)) {
if(fnc[4]) {
fnc[4].cancel();
}
k = fn.tasks && fn.tasks.length;
if(k) {
while(k--) {
fn.tasks[k].cancel();
}
delete fn.tasks;
}
wf = wrap = fnc[1];
if (E.extAdapter) {
wf = fnc[3];
}
E.un(el, eventName, wf);
f.splice(i,1);
if (f.length === 0) {
delete Ext.elCache[id].events[eventName];
}
if(eventName == "mousewheel" && el.addEventListener && wrap){
el.removeEventListener("DOMMouseScroll", wrap, false);
}
if(eventName == "mousedown" && el == DOC && wrap){
Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
}
for (k in Ext.elCache[id].events) {
return false;
}
Ext.elCache[id].events = {};
return false;
}
}
/*if(eventName == "mousewheel" && el.addEventListener && wrap){
el.removeEventListener("DOMMouseScroll", wrap, false);
}
if(eventName == "mousedown" && el == DOC && wrap){
Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
}*/
},

Jamie Avins
27 Jan 2010, 1:28 PM
Fixed in svn-core 135.