Thursday, April 21, 2005

DOM 0 with XHTML caveat

Here's an interesting gotcha, unearthed from Bobby van der Sluis' popular article on JavaScript good practices that's making the rounds: when you serve an XHTML document as application/xhtml+xml, the good old DOM Level 0 collections like document.images and document.forms go bye-bye, at least in Mozilla-based browsers.

I'm okay with this, but I love me some backwards-compatible DOM 0, especially when I know exactly which element I need to access via script. Luckily, it's perfectly okay to serve XHTML 1.0 as "HTML compatible" text/html. It's when you start serving XHTML 1.1 as text/html that people start yelling and pointing.

Here's the Bugzilla discussion of this behavior.

16 Comments:

At 1:06 PM, Anonymous Anonymous said...

Personally, I never use the DOM0 functions anyway; document.getElementsByTagName('form') is the same as document.forms, and works everywhere, so I never even think to use the old way. Is there any advantage to doing so? I can't think of one...

sil

 
At 3:14 PM, Blogger scottandrew said...

1. Backward compatibility.
2. Shorter code.
3. No need to iterate thru a collection.

 
At 8:05 PM, Anonymous alan said...

Those collections are available in DOM Level 2, but they're part of the HTML DOM, thus not available when serving a document as XML.

To add to Scott's reasons for using those functions, they are also sometimes faster than their DOM core counterparts, especially in IE.

 
At 12:36 AM, Anonymous Anonymous said...

"Luckily, it's perfectly okay to serve XHTML 1.0 as "HTML compatible" text/html."

Hixie has a few things to say about just how okay that is: http://www.hixie.ch/advocacy/xhtml
(To sum it up: not at all.)

 
At 6:34 AM, Blogger Marty said...

Anon, that link makes my head hurt. Almost enough to make me want to return to the food service industry! Ugh.

(tag soup rules)

 
At 8:40 AM, Blogger scottandrew said...

This comment has been removed by a blog administrator.

 
At 8:56 AM, Blogger scottandrew said...

I've seen that Hixie screed invoked a kabillion times, but it simply doesn't change the fact that it's hunky-dory to serve HTML-compatible XHTML 1.0 as text/html:

http://www.w3.org/TR/xhtml-media-types/#summary

Earlier in the same doc:

"XHTML Documents which follow the guidelines set forth in Appendix C, 'HTML Compatibility Guidelines' may be labeled with the Internet Media Type "text/html", as they are compatible with most HTML browsers."

Of course, YOU are welcome to take Hixie's advice and/or serve it any way you want. I don't particularly care.

This blog is about JS in the real world, not mime-type evangelism. Can we get back to talking about JS now?

 
At 12:47 PM, Blogger Jeremy Dunck said...

3. No need to iterate thru a collection.

Huh? document.images is a collection, no?

As for backwards compat:
document.__defineGetter__('images', function(){return document.getElementsByTagName('img')});

Of course, that works against shorter code...

And, of course, it's simpler to just serve text/html and forget this problem.

 
At 12:54 PM, Blogger Jeremy Dunck said...

Ack.. Err, nevermind, apparently I'm smoking crack.

 
At 12:56 PM, Anonymous Mark Kawakami said...

It seems to me that if you suspect this is going to be an issue in your code you can add these back in easily, by putting in something like:

if(!document.images) { var images = document.getElementsByTagName("img") };
if(!document.forms) { var forms = document.getElementsByTagName("forms") };

The only hard part is where to add it. Obviously it needs the entire page to load or the collections will be incomplete (or entirely empty) but before any other functions that might use it run. But I think in most situations, it (or something like it) should work to give you your backwards compatibility.

Also, man, it bums me out that Blogger won't allow <code> or any other similar code-type tags in their comments. Weak, Blogger, weak!

 
At 2:39 PM, Blogger scottandrew said...

Mark: your solution is similar to Jeremy's, but it doesn't allow me to go straight to the element I want. For example:

var f = document.forms["signupForm"];

If I were to use getElementsByTagName("form") here instead, I'd have to iterate over the resulting collection to get to the FORM element I want. The old-school method seems much simpler.

Sure, you can structure your faux document.forms to do this, but you'd be reinventing the wheel, no?

 
At 10:59 AM, Anonymous Manny Fleurmond said...

Hey Jeremy, what is this:
As for backwards compat:
document.__defineGetter__('images', function(){return document.getElementsByTagName('img')});

Of course, that works against shorter code...


the defineGetter thing. What exactly does it do?

 
At 5:38 PM, Blogger Jeremy Dunck said...

Well, the reason I said I was smoking crack is that __defineGetter__ is moz-specific. There's a __defineSetter__ relative.

I noticed it in Dean Edward's moz behaviours recently; dunno how I didn't hear of it before.

It's for creating getters and setters with the guise of a simple variable property.

See this from his source:

CSSStyleDeclaration.prototype.__defineGetter__("pixelLeft", function() {
return parseInt(this.left) || 0;
});

Serious kung fu here.

 
At 10:24 PM, Blogger Google Page Rank 6 said...

Increase your Adsense Earnings

I noticed you have adsense ads on your page, Would you like to increase your earnings from them, Free and Legitimate way to make your clicks increase.
Come see my Blogger blog and it will tell you more.

 
At 7:11 AM, Blogger HiiFii Webservices said...

I wanted to show you some superb resourses on the net.
Learn to earn 90000$/Month
For which you may also see my Personal Website
Here.
and for a Personal Education Career Tools
free Study Database.
This site is for seeing the
Hifi Electronics.
And this is for
World Class Gadgets

 
At 6:01 PM, Blogger satxxkenn said...

Cool blog - Check out my site if you need help finding a good low interest credit card. Credit Cards

 

Post a Comment

<< Home