making bbPress (and WordPress) work better!

javascript

How to get an element’s TRUE position in javascript, including borders in Firefox

I’ve seen a bunch of scripts around the web to get an element’s (aka object) actual/absolute position on a page in javascript. Virtually all of them are wrong, for one very good reason – if you have borders on an element in ANY version of firefox, the position will be off by the border width.

I haven’t seen any script attempt to deal with borders.

This is because Firefox uses a broken “inner” model, regardless if you are in standards vs quirks mode, that was based on trying to mimic IE6 – the only other game in town when Firefox was evolved. But ironically, even IE has moved on to including borders since version 7/8 while Firefox remains the same from version 1 through 5. Good for backwards compatibility I guess but a headache for web developers.

So in plain English, in Firefox, margins count towards offsetLeft/offsetTop but NOT borders! It’s the only “html5” browser in existence right now that doesn’t include borders.

See these bug reports from SEVEN years ago, still unfixed:
https://bugzilla.mozilla.org/show_bug.cgi?id=255754
https://bugzilla.mozilla.org/show_bug.cgi?id=387922

Ignore where people claim their solution works – if it doesn’t include border calculations, it doesn’t work, they are misguided.

I used to have a very short and sweet function to grab an object’s true position on the page. (do not use this one)

function XY(o) {var z=o,x=z.offsetLeft||0,y=z.offsetTop||0; while(z=z.offsetParent) {x+=z.offsetLeft||0; y+=z.offsetTop||0;} return {x:o.X=x,y:o.Y=y};}

(it returns an object with .X .Y added (left and top) but also appends them to the original object for convenience)

However do not use the above script, it’s incomplete. Not only does it not properly deal with scrolled objects (div, iframe, etc.) it does not handle borders in firefox.

Sadly there is no fast & clean way to get border width in firefox, you have to use computedstyles from the best I can figure out, which must be relatively slow because of how it traverses stylesheets (if you know a faster way, please let me know).

So this (unfortunately larger) function I’ve come up with does finally produce identical results across Chrome, Firefox and IE8

function XY(o) {
var z=o, x=0,y=0, c; 
while(z && !isNaN(z.offsetLeft) && !isNaN(z.offsetTop)) {        
c = isNaN(window.globalStorage)?0:window.getComputedStyle(z,null); 
x += z.offsetLeft-z.scrollLeft+(c?parseInt(c.getPropertyValue('border-left-width'),10):0);
y += z.offsetTop-z.scrollTop+(c?parseInt(c.getPropertyValue('border-top-width'),10):0);
z = z.offsetParent;
} 
return {x:o.X=x,y:o.Y=y};
}

But even though it’s larger, it’s still far better than turning to an 80k library like jquery. Note my use of “window.globalStorage” which is a trustworthy way of detecting anything based on the real gecko engine (since FF 2+) while ignoring all other browsers. No user-agent sniffing needed. Can’t use the navigator property – it’s useless because Chrome will also return “Gecko”.


Firefox 4 Mobile – first to support WYSIWYG Editors (contentEditable/designMode)

Firefox 4 Mobile was just released today and I have some incredible news that no-one else seems to have noticed (yet).

It’s the first mobile browser to support contentEditable!

What does this mean? Well TinyMCE, CKEditor (FCKeditor) and other rich, visual editors will now be able to work on your android cellphone (and a very few Nokia devices like the N900)

Check it out here: http://firefox.com/m

If you have Windows, Mac, or Linux on your desktop, you can see what the fuss is about through the developer versions:

http://ftp.mozilla.org/pub/mozilla.org/mobile/releases/4.0/

No other mobile browser to date does this trick. Not mobile Safari for the iPhone, not mobile Chrome for Android, not Opera Mini/Mobile, not IE Mobile. See my post from last week about this lack-of-support problem..


List of mobile browsers that support contentEditable (designMode) WYSIWYG

As of March 2011, this is a trick question – NO mobile browser even attempts to support contentEditable/designMode (aka WYSIWYG, rich HTML textareas) on portable devices like cellphones, smartphones, iPad, iTouch, etc.

Desktop browsers have been supporting it since IE 5.5 in July 2000 over a decade ago. The Mozilla 1.3 (Gecko) engine implemented it in late 2002, so Firefox 1.5 had it in May 2003.

Also see: http://caniuse.com/contenteditable

So which one of these will be the first mobile browsers to have it?

Microsoft IE for Mobile
Google Android (Chrome/webkit)
Apple Safari Mobile (webkit)
Opera Mobile
Opera Mini
Firefox Mobile (Fennec)

However I have no information on the brand new Internet Explorer Mobile 9 (aka IE9 Mobile) which was only demonstrated February 2011 by Microsoft.

Since Microsoft invented content-editable, there is a chance they ported it into the mobile IE9 from their newest Trident engine. If anyone can confirm or deny this, please let me know? Thanks!


How web designers can test websites in IE9 on Windows XP

I’m a diehard Windows XP user and have no desire to upgrade to Vista or Windows 7. But this presents a problem now that Internet Explorer 9 has been officially released and in their (endless lack of) wisdom, Microsoft has decided not to allow it to run on Windows XP, to try to get people like me to upgrade.

So here’s how you can test your web designs on IE9 and make sure that everything is okay.

(the #1 problem I have found is that IE9 does NOT like or deal well with special IE6 fixes that are left over that were either ignored or did no harm in IE7 or IE8 – I will give you a solution for that following this)

First downloaded the free and legal Microsoft Windows 7 enterprise trial ISO (2.2GB)
microsoft.com x86fre_enterprise_en-us_EVAL_Eval_Enterprise-GRMCENEVAL_EN_DVD.iso
(you only need the 32bit version, it will run faster, if it won’t download it’s because of the refer, copy the link and paste it directly in your browser – download is speed limited so it will take at least 20 minutes)

Next install the free VMWare Player into Windows XP
http://download3.vmware.com/software/vmplayer/VMware-player-2.5.5-328052.exe
( or http://www.vmware.com/download/player/download.html you might actually need version 3+ for windows 7)

Last, use one of the free vmx generator tools to make a configuration for VMplayer ready for Windows 7 and set the Windows7 ISO as the CD drive

http://www.easyvmx.com/supersimple.shtml
(choose Vista, not Vista 64 – also, Windows7 needs a TON of space so choose 12GB at a minimum, I did 8GB and it’s already maxed out with nothing else installed – the file starts off small but will grow as needed)

Edit the vmx file and add these lines (removing any existing ide1:0 lines)

ide1:0.present = "TRUE"
ide1:0.deviceType = "cdrom-image"
ide1:0.fileName = "7600.16385.090713-1255_x86fre_enterprise_en-us_EVAL_Eval_Enterprise-GRMCENEVAL_EN_DVD.iso"

It should take 30 minutes to do all this, except maybe the ISO download which is huge and takes quite awhile.

The great thing about the enterprise trial is it lasts for 60 days, then you can “rearm” (google it) for a couple more times, but even when it’s expired, you can use it for an hour before auto-shutdown which is plenty of time to test pages in IE9

Okay now I promised a trick to help deal with IE9 – here’s my solution:

Most javascript that detects IE doesn’t detect the version, just if it’s IE or not. For example: isIE=/blah/; What we really need is something to replace that which is short and sweet and accurate.

So here’s what I came up with:

isIE=window.opera?0:parseInt((navigator.userAgent.match(/MSIE (\d+)/) || [0,0])[1]);

Then just replace any instance of

if (isIE) {blah}

With this:

if (isIE && isIE<9) {blah}

Hope that helps!


Firefox 3.5 finally supports DEFER on javascript

I was pleased to discover that after a mere 9 years
that Mozilla/Firefox finally supports defer on javascript.

Yup, 9 years, I couldn’t believe the time either, see for yourself:
http://bugzilla.mozilla.org/show_bug.cgi?id=28293

What this means is that Firefox finally has a feature
that Internet Explorer has had since version 4 (1997)
(it was made a standard by W3C HTML 4.01 in December 1999)

This means you should be doing this now on all your javascript, inline and external loading:
<script defer="defer" type="text/javascript" ...
(the repeat of the word is simply because of modern validation standards, without it the validation nutters have conniptions)

This causes the script to delay executing until the page is loaded. In some cases the script is also delayed in loading. The short answer is it will make your page seem to load faster for your visitors.

The only time you can’t use DEFER is when you are relying on javascript to inject something inline in your page, ie.
<script defer="defer" type="text/javascript" >
document.write('hello');
</script>
world
will NOT show “hello world” but rather “world hello“.
(if you removed the DEFER it would show “hello world” as expected)

I still don’t know what the status of webkit/safari/chrome is on DEFER or Opera for that matter, much more googling required.


stop using “window.onload” in JavaScript

2012 update: this entry is four years old – time for a modern revisit of my old, ugly code – try this instead:

window.addEventListener ? 
window.addEventListener("load",yourFunction,false) : 
window.attachEvent && window.attachEvent("onload",yourFunction);

——————————————–

I don’t write full blown AJAX but I do code some JavaScript from time to time. One big tip I can offer other “casual” javascript coders, since many times a script must be executed after a page is loaded, is to STOP using window.onload=your_function;

The reason for this is simple – you should be APPENDING your script to the page loaded hook, not CLOBBERING any existing scripts that may be already attached. The “window.onload” method can only hook one function at a time and these days it’s common to use several third party scripts on a site. If you are not careful, you may be left scratching your head why something stopped working – because you accidentally stopped it from loading.

There used to be some clever workarounds for this, like making a function that checked onload and appending it to a list of functions to call and replacing it with your own onload. But with modern browsers today, all that mess is not needed. Just replace your code with this (albeit longer) code:
if (window.attachEvent) {window.attachEvent('onload', your_function);}
else if (window.addEventListener) {window.addEventListener('load', your_function, false);}
else {document.addEventListener('load', your_function, false);}

Tested working in all major modern browser (IE, Firefox, Safari, Opera) and it appends instead of replaces the onload process. Hope that helps!