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);
}
}
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);
}
}