From 03ae9dd3eef11c846fb4b3fc2a1bd250d3ae08c1 Mon Sep 17 00:00:00 2001 From: Thomas Fuchs Date: Sun, 17 Jun 2007 22:26:46 +0000 Subject: [PATCH] * Make document.getElementsByClassName match the WHATWG Web Applications 1.0 specification which was adopted in Firefox 3 (http://www.whatwg.org/specs/web-apps/current-work/#getelementsbyclassname). It now supports multiple class names given as an array or a space-separated list in a string. The method will only return the nodes that match all the class names. In browsers that implement the method natively it will not be overwritten. Closes #8401. [Mislav Marohnic] --- CHANGELOG | 6 +++++ src/dom.js | 57 ++++++++++++++++++++++++++++---------------- test/lib/unittest.js | 2 +- test/unit/dom.html | 33 +++++++++++++++++++++---- 4 files changed, 73 insertions(+), 25 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8a1635e..a23a2b5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,11 @@ *SVN* +* Make document.getElementsByClassName match the WHATWG Web Applications 1.0 specification which was adopted in Firefox 3 +(http://www.whatwg.org/specs/web-apps/current-work/#getelementsbyclassname). It now supports multiple class names given as an array or a space-separated list in a string. The method will only return the nodes that match all the class names. In browsers that implement the method natively it will not be overwritten. Closes #8401. [Mislav Marohnić] + Examples: + document.getElementsByClassName('foo bar') + document.getElementsByClassName(['foo', 'bar']) + * Fix a Safari rendering issue when floating elements could temporarily disappear when opacity was set to 1. Closes #7063. References #3044, #3813, #6706. [Thomas Fuchs, davidjrice] * Prevent a crash in Safari when calling String#evalJSON(true) on very large strings. Add String#isJSON. Closes #7834. [Tobie Langel] diff --git a/src/dom.js b/src/dom.js index 7a608b8..f14fb80 100644 --- a/src/dom.js +++ b/src/dom.js @@ -18,22 +18,7 @@ if (Prototype.BrowserFeatures.XPath) { results.push(query.snapshotItem(i)); return results; }; - - document.getElementsByClassName = function(className, parentElement) { - var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]"; - return document._getElementsByXPath(q, parentElement); - } - -} else document.getElementsByClassName = function(className, parentElement) { - var children = ($(parentElement) || document.body).getElementsByTagName('*'); - var elements = [], child; - for (var i = 0, length = children.length; i < length; i++) { - child = children[i]; - if (Element.hasClassName(child, className)) - elements.push(Element.extend(child)); - } - return elements; -}; +} /*--------------------------------------------------------------------------*/ @@ -243,10 +228,6 @@ Element.Methods = { return Selector.findChildElements(element, args); }, - getElementsByClassName: function(element, className) { - return document.getElementsByClassName(className, element); - }, - readAttribute: function(element, name) { element = $(element); if (Prototype.Browser.IE) { @@ -614,6 +595,42 @@ Element.Methods = { } }; +if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ + function isArray(className) { + return className.constructor == Array || (/\s/.test(className) && !className.toString().blank()); + } + function classNamesArray(classNames) { + return classNames.constructor == Array ? classNames : $w(classNames.toString()); + } + function iter(name) { + return name.toString().blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; + } + + instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? + function(element, className) { + var cond = isArray(className) ? classNamesArray(className).map(iter).join('') : iter(className); + return cond ? document._getElementsByXPath('.//*' + cond, element) : []; + } : function(element, className) { + var elements = [], classNames = (isArray(className) ? classNamesArray(className) : null); + if (classNames ? !classNames.length : className.toString().blank()) return elements; + var nodes = $(element).getElementsByTagName('*'); + className = ' ' + (classNames ? classNames.join(' ') : className) + ' '; + + for (var i = 0, child, cn; child = nodes[i]; i++) { + if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || + (classNames && classNames.all(function(name) { + return !name.toString().blank() && cn.include(' ' + name + ' '); + })))) + elements.push(Element.extend(child)); + } + return elements; + }; + + return function(className, parentElement) { + return $(parentElement || document.body).getElementsByClassName(className); + }; +}(Element.Methods); + Object.extend(Element.Methods, { childElements: Element.Methods.immediateDescendants }); diff --git a/test/lib/unittest.js b/test/lib/unittest.js index 75b7dc4..1be1fc6 100644 --- a/test/lib/unittest.js +++ b/test/lib/unittest.js @@ -484,7 +484,7 @@ Test.Unit.Assertions.prototype = { assertElementsMatch: function() { var expressions = $A(arguments), elements = $A(expressions.shift()); if (elements.length != expressions.length) { - this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions'); + this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions (' + expressions.inspect() + ')'); return false; } elements.zip(expressions).all(function(pair, index) { diff --git a/test/unit/dom.html b/test/unit/dom.html index 0f3eac4..06baeb0 100644 --- a/test/unit/dom.html +++ b/test/unit/dom.html @@ -207,8 +207,10 @@
+
@@ -337,7 +339,9 @@
- + +
+