Fixed bug in $() and getElementById
Reported by Ricky | June 9th, 2008 @ 08:17 PM
IE7 and Opera 9.27 (but not IE8, I'm told) will find <tag name="whatever"> when you are looking for <tag id="whatever">.
The easiest way to see the ie7 bug is the attached file animalcow.html, which is standalone except that it uses prototype.js. Use 1.6.0.2 to see the bug.
This fix overrides and replaces getElementById() to be W3C compliant (and ie8 compliant) and therefore fixes $().
The fix is in dom.js, in the beginning. The test code for ie7 and opera is in dom_test.js, and the html of the tests is in dom.html. All changes are in the attached patch.
I think I can attach 2 different files. We'll see.
The key is to use the non-standard document.all on browsers that have it. Luckily, this seems to be the same set as the browsers that have the bug.
I've tested the fixed prototype.js on Windows XP SP3 only, with
Firefox 3 RC2
IE7
Opera 9.27
Safari 3.1.1
All 4 browser say '24 assertions, 0 failures, 0 errors' for dom_test.html in testDollarFunction.
Credit is due to:
and to
PROS:
Fixes the bug.
CONS:
My changes to dom_test.js seem verbose.
The code changes the dom routine, getElementById(), which could break some already broken code. You can change that by changing a function name and a couple-of-line edit to dom.js. This is a philosophical question for the prototype developers.
Comments and changes to this ticket
-

-

Ricky June 9th, 2008 @ 08:22 PM
For IE8, this code will need to change, as it will needlessly (but harmlessly, I hope) over-ride getElementById().
-
-

Ricky June 10th, 2008 @ 08:20 AM
The bug wrecked my app, which I consider poor performance. In other words, I haven't done any side-by-side performance testing.
Subjectively, there is no difference in my small tests. The additional search loop only kicks in if the code discovers that the found element is not the right one, which should only happen, so far as I know, when the there is duplicate text for name and id, name="goober", and elsewhere id="goober".
By the way, Microsoft has indirectly acknowledged that they have a misfeature (bug, to you and me). In the docs for ie7 the describe getElementById as matching on either name or id. But in the docs for ie8 they describe it as matching only on id. I consider this a confession. I like to imagine Ballmer, sobbing on the witness stand.
-
Tobie Langel June 16th, 2008 @ 12:10 AM
This has been discussed before and wasn't integrated into core for performance reasons.
Whatever is decided this time, I'm not very keen on the idea of overwriting the existing `document.getelementById` method.
-
Tobie Langel June 16th, 2008 @ 12:10 AM
- → State changed from new to enhancement
-

Ricky June 21st, 2008 @ 10:11 PM
If this has been discussed before it should be in the docs for $(). It isn't even in the Porteneuve book.
Have performance tests been done? Are there results available?
The only reason I did it by over-riding getElementById is that Microsoft has changed their implementation. Anyway, that is a side issue. $() is supposed to smooth over variations and defects among browsers; Prototype can have it's own private implementation. Else what is Prototype for?
Should I submit a version that does not over-ride the standard function?
-
Juriy Zaytsev June 21st, 2008 @ 11:08 PM
Changes like this is always a tough decision.
On one hand, such quirks could waste hours of valuable time (if a developer is working on an outdated/developed-by-many-people project) and it is a library's job to prevent this from happening.
On the other hand, one small change in $ could hog the entire library, bringing an app to its knees (performance-wise).
We could solve problems like these with a global switch, separate function or an optional argument (passed to $).
Introducing separate function is problematic - considering that $ is a global variable (and has such unique name).
Optional argument to a $ is problematic as well - function already accepts N number of them, so these changes would break compatibility.
Global switch seems like a pretty good solution. Something like $.IGNORE_NAMES = true; (which would be false by default)
Frameworks like YUI already use global configuration. I'm not sure why prototype avoids this.
Thoughts?
-

Ricky June 22nd, 2008 @ 07:07 AM
Unless we do something, the $() is not working as advertised. This has got to be a bug. We should change the documentation or change the code.
For IE7, the broken getElementById function actually works according to Microsoft's IE7 documentation, so one could argue it's not a bug. It violates the W3C spec, so you could argue the other way, too. I'll let the philosophers decide that one.
-
John-David Dalton July 2nd, 2008 @ 03:10 PM
- → Tag changed from to dom ie ie6 ie7 needs_patch needs_tests opera
I don't see this as a big deal.
Its a bug in the browser and any tinkering with it to try to fix it will only slow down this core method.
We could do
function $(element) { if (arguments.length > 1) { for (var i = 0, elements = [], length = arguments.length; i < length; i++) elements.push($(arguments[i])); return elements; } if (Object.isString(element)) { var id = element; element = document.getElementById(id); if (document.all && id === element.getAttribute('name') && id !== element.getAttribute('id')) { var elements = document.all[id], length = elements.length || 0; while (length--) { if (elements[length].getAttribute('name') !== id && elements[length].getAttribute('id') === id) return Element.extend(elements[length]); } return null; } } return Element.extend(element); } -
Juriy Zaytsev July 2nd, 2008 @ 03:51 PM
John,
Using global switch gives control to the hands of developers.
There's no slowdown unless you know what you are doing.
Regarding browser bugs, 80% of what's in prototype.js is a workaround for them ;)
I actually find this addition useful.
-
Please Login or create a free account to add a new comment.
You can update this ticket by sending an email to from your email client. (help)
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
The Prototype JavaScript library.
