* 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]
This commit is contained in:
parent
afbef44cd6
commit
03ae9dd3ee
@ -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]
|
||||
|
57
src/dom.js
57
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
|
||||
});
|
||||
|
@ -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) {
|
||||
|
@ -207,8 +207,10 @@
|
||||
<ul class="A B" id="class_names_ul">
|
||||
<li class="C"></li>
|
||||
<li class="A C"></li>
|
||||
<li class="1"></li>
|
||||
</ul>
|
||||
<div class="B C D"></div>
|
||||
<div id="unextended"></div>
|
||||
</div>
|
||||
|
||||
<div id="style_test_1" style="display:none;"></div>
|
||||
@ -337,7 +339,9 @@
|
||||
</div>
|
||||
<div id="notInlineAbsoluted"></div>
|
||||
<div id="inlineAbsoluted" style="position: absolute"></div>
|
||||
|
||||
|
||||
<div id="unextended"></div>
|
||||
|
||||
<!-- Tests follow -->
|
||||
<script type="text/javascript" language="javascript" charset="utf-8">
|
||||
// <![CDATA[
|
||||
@ -381,10 +385,31 @@
|
||||
}},
|
||||
|
||||
testGetElementsByClassName: function() {with(this) {
|
||||
var div = $('class_names'), list = $('class_names_ul');
|
||||
|
||||
assertElementsMatch(document.getElementsByClassName('A'), 'p.A', 'ul#class_names_ul.A', 'li.A.C');
|
||||
assertElementsMatch(document.getElementsByClassName('A', 'class_names_ul'), 'li.A.C');
|
||||
assertElementsMatch(document.getElementsByClassName('B', 'class_names'), 'ul#class_names_ul.A.B', 'div.B.C.D');
|
||||
assertElementsMatch(document.getElementsByClassName('B', 'class_names_ul'));
|
||||
|
||||
if (Prototype.Browser.IE)
|
||||
assertUndefined(document.getElementById('unextended').show);
|
||||
|
||||
assertElementsMatch(list.getElementsByClassName('A'), 'li.A.C');
|
||||
assertElementsMatch(list.getElementsByClassName('C A'), 'li.A.C');
|
||||
assertElementsMatch(div.getElementsByClassName('B'), 'ul#class_names_ul.A.B', 'div.B.C.D');
|
||||
assertElementsMatch(div.getElementsByClassName('D C B'), 'div.B.C.D');
|
||||
assertElementsMatch(div.getElementsByClassName($w('D C B')), 'div.B.C.D');
|
||||
assertElementsMatch(list.getElementsByClassName('B'));
|
||||
assertElementsMatch(list.getElementsByClassName('1'), 'li.1');
|
||||
assertElementsMatch(list.getElementsByClassName([1]), 'li.1');
|
||||
assertElementsMatch(list.getElementsByClassName(['1 junk']));
|
||||
assertElementsMatch(list.getElementsByClassName(''));
|
||||
assertElementsMatch(list.getElementsByClassName(' '));
|
||||
assertElementsMatch(list.getElementsByClassName(['']));
|
||||
assertElementsMatch(list.getElementsByClassName([' ', '']));
|
||||
assertElementsMatch(list.getElementsByClassName({}));
|
||||
assertEqual(Array, [].constructor)
|
||||
|
||||
// those lookups shouldn't have extended all nodes in document
|
||||
if (Prototype.Browser.IE) assertUndefined(document.getElementById('unextended')['show']);
|
||||
}},
|
||||
|
||||
testElementInsertWithHTML: function() {with(this) {
|
||||
|
Loading…
Reference in New Issue
Block a user