I've been banging my head against the wall again with FireFart (as Peter Bromberg lovingly calls FireFox) DOM programming.
What I'm doing is simple enough – I dynamically load up a <div> tag with HTML via innerHTML property and then need to draw a related control with the same dimensions.
var Panel = $(Context.ControlId);
Panel.innerHTML = Result;
// incorrect in FireFox, correct in IE
var Height = Panel.offsetHeight;
ShowShadow(Panel.id);
where ShowShadow is a function that creates a shadow dynamically for the control. Obviously ShowShadow is critically in need of the proper bounds for the target control and this is where the problem comes in. If you look at the value of Height at the point above it will be the correct height of the newly updated element with the new content in Internet Explorer, and have some stale value from a previous setting in FireFox.
Normally the .offsetHeight property should do the trick but FireFox is not behaving. The value returned with .offsetHeight is rarely consistent depending on the style height setting, but even when no style setting is made at all the .offsetHeight is not correct.
Interestingly enough the width works just fine – it's retrieved without any issues. It's only the height that has issues.
I've fought this particular problem for some time off and on. I get it to work, then I add a little code here or there in the framework code and it breaks again in FireFox. Just to be sure I'm not completely off my nut I looked at ATLAS and what it's doing to get control coordinates which is pretty much the same I use:
function GetControlLocation(element)
{
var offsetX = 0;
var offsetY = 0;
var parent;
for (parent = element; parent; parent = parent.offsetParent) {
if (parent.offsetLeft) {
offsetX += parent.offsetLeft;
}
if (parent.offsetTop) {
offsetY += parent.offsetTop;
}
}
return { x: offsetX, y: offsetY };
}
function GetControlBounds(element) {
var offset = GetControlLocation(element);
var width = element.offsetWidth;
var height = element.offsetHeight;
return { x: offset.x, y: offset.y, width: width, height: height };
}
But as expected that doesn't work any better; I still end up with my related controls mis-sized.
So in my never ending ignorance of all issues DOM I stumbled onto the solution to the problem by accident. The reason for the behavior FireFox has is that it doesn't update the DOM element properly until after the event or active function call completes and the browser event loop gets control back.
To get around this I ended up trying to delay the call to the routine that calls the Shadow rendering. Instead of calling it directly I use a window.setTimeout() call and lo and behold everything starts working correctly.
window.setTimeout("ShowShadow('" + Panel.id +"')",50);
does the trick in this scenario! On my machine the lowest value I can use is 50 – anything lower and I get spotty behavior where it sometimes works and sometimes not.
Since the Shadow generation function requires this behavior consistently I figured I better build support for it into the function itself so it can call itself back:
function ShowShadow(CtlId,Opacity,Offset,DelayShadow)
{
var Ctl = $(CtlId);
if (Ctl == null)
return;
if (Opacity == null)
Opacity = ".35";
if (Offset == null)
Offset = 8;
if (TimeFlag != null)
{ // Force a delay to allow target control to resize properly
window.setTimeout("ShowShadow('" + CtlId + "'," + Opacity.toString() + "," + Offset.toString() + ",null)",50);
return;
}
…
}
If you think this is ugly as hell raise your hand <g>. But it works. I've had issues with this particular problem on a number of occasions and this explains the funky behavior I've been seeing. Apparently, this problem has gotten worse in a recent FireFox update because I had the original code working previously. It's obviously a timing issue – so it was probably spotty even back then. I suspect machine speed also plays into that - a faster machine might blaze through JavaScript code faster than the DOM is being updated in the background. But this seems one hell of a lame design if that's really the case.
In the meantime this hack solves the problem for me. Hope this helps someone out…
Other Posts you might also like