Merged some recent fixes in from Sizzle.

This commit is contained in:
John Resig 2009-01-19 18:09:11 +00:00
parent cde93dc547
commit 8e8d7ade43
3 changed files with 68 additions and 46 deletions

View File

@ -35,34 +35,21 @@ var Sizzle = function(selector, context, results, seed) {
}
}
if ( parts.length > 1 && Expr.match.POS.exec( selector ) ) {
if ( parts.length > 1 && origPOS.exec( selector ) ) {
if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
var later = "", match;
// Position selectors must be done after the filter
while ( (match = Expr.match.POS.exec( selector )) ) {
later += match[0];
selector = selector.replace( Expr.match.POS, "" );
}
set = Sizzle.filter( later, Sizzle( /\s$/.test(selector) ? selector + "*" : selector, context ) );
set = posProcess( parts[0] + parts[1], context );
} else {
set = Expr.relative[ parts[0] ] ?
[ context ] :
Sizzle( parts.shift(), context );
while ( parts.length ) {
var tmpSet = [];
selector = parts.shift();
if ( Expr.relative[ selector ] )
selector += parts.shift();
for ( var i = 0, l = set.length; i < l; i++ ) {
Sizzle( selector, set[i], tmpSet );
}
set = tmpSet;
set = posProcess( selector, set );
}
}
} else {
@ -170,7 +157,7 @@ Sizzle.filter = function(expr, set, inplace, not){
while ( expr && set.length ) {
for ( var type in Expr.filter ) {
if ( (match = Expr.match[ type ].exec( expr )) != null ) {
var filter = Expr.filter[ type ], goodArray = null, goodPos = 0, found, item;
var filter = Expr.filter[ type ], found, item;
anyFound = false;
if ( curLoop == result ) {
@ -184,26 +171,13 @@ Sizzle.filter = function(expr, set, inplace, not){
anyFound = found = true;
} else if ( match === true ) {
continue;
} else if ( match[0] === true ) {
goodArray = [];
var last = null, elem;
for ( var i = 0; (elem = curLoop[i]) !== undefined; i++ ) {
if ( elem && last !== elem ) {
goodArray.push( elem );
last = elem;
}
}
}
}
if ( match ) {
for ( var i = 0; (item = curLoop[i]) !== undefined; i++ ) {
for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
if ( item ) {
if ( goodArray && item != goodArray[goodPos] ) {
goodPos++;
}
found = filter( item, match, goodPos, goodArray );
found = filter( item, match, i, curLoop );
var pass = not ^ !!found;
if ( inplace && found != null ) {
@ -358,12 +332,14 @@ var Expr = Sizzle.selectors = {
CLASS: function(match, curLoop, inplace, result, not){
match = " " + match[1].replace(/\\/g, "") + " ";
for ( var i = 0; curLoop[i]; i++ ) {
if ( not ^ (" " + curLoop[i].className + " ").indexOf(match) >= 0 ) {
if ( !inplace )
result.push( curLoop[i] );
} else if ( inplace ) {
curLoop[i] = false;
for ( var i = 0; curLoop[i] != null; i++ ) {
if ( curLoop[i] ) {
if ( not ^ (" " + curLoop[i].className + " ").indexOf(match) >= 0 ) {
if ( !inplace )
result.push( curLoop[i] );
} else if ( inplace ) {
curLoop[i] = false;
}
}
}
@ -373,8 +349,8 @@ var Expr = Sizzle.selectors = {
return match[1].replace(/\\/g, "");
},
TAG: function(match, curLoop){
for ( var i = 0; !curLoop[i]; i++ ){}
return isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
for ( var i = 0; curLoop[i] === false; i++ ){}
return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
},
CHILD: function(match){
if ( match[1] == "nth" ) {
@ -394,7 +370,7 @@ var Expr = Sizzle.selectors = {
return match;
},
ATTR: function(match){
var name = match[1];
var name = match[1].replace(/\\/g, "");
if ( Expr.attrMap[name] ) {
match[1] = Expr.attrMap[name];
@ -616,6 +592,8 @@ var Expr = Sizzle.selectors = {
}
};
var origPOS = Expr.match.POS;
for ( var type in Expr.match ) {
Expr.match[ type ] = RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
}
@ -750,7 +728,7 @@ if ( document.querySelectorAll ) (function(){
Sizzle.matches = oldSizzle.matches;
})();
if ( document.documentElement.getElementsByClassName ) {
if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) {
Expr.order.splice(1, 0, "CLASS");
Expr.find.CLASS = function(match, context) {
return context.getElementsByClassName(match[1]);
@ -835,6 +813,26 @@ var isXML = function(elem){
elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
};
var posProcess = function(selector, context){
var tmpSet = [], later = "", match,
root = context.nodeType ? [context] : context;
// Position selectors must be done after the filter
// And so must :not(positional) so we move all PSEUDOs to the end
while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
later += match[0];
selector = selector.replace( Expr.match.PSEUDO, "" );
}
selector = Expr.relative[selector] ? selector + "*" : selector;
for ( var i = 0, l = root.length; i < l; i++ ) {
Sizzle( selector, root[i], tmpSet );
}
return Sizzle.filter( later, tmpSet );
}
// EXPOSE
jQuery.find = Sizzle;
jQuery.filter = Sizzle.filter;

View File

@ -29,7 +29,7 @@
<h2 id="userAgent"></h2>
<!-- Test HTML -->
<div id="nothiddendiv" style="height:1px;background:white;">
<div id="nothiddendiv" style="height:1px;background:white;" class="nothiddendiv">
<div id="nothiddendivchild"></div>
</div>
<!-- this iframe is outside the #main so it won't reload constantly wasting time, but it means the tests must be "safe" and clean up after themselves -->

View File

@ -141,7 +141,7 @@ test("multiple", function() {
});
test("child and adjacent", function() {
expect(41);
expect(44);
t( "Child", "p > a", ["simon1","google","groups","mark","yahoo","simon"] );
t( "Child", "p> a", ["simon1","google","groups","mark","yahoo","simon"] );
t( "Child", "p >a", ["simon1","google","groups","mark","yahoo","simon"] );
@ -156,6 +156,11 @@ test("child and adjacent", function() {
t( "Adjacent", "p + p", ["ap","en","sap"] );
t( "Comma, Child, and Adjacent", "a + a, code > a", ["groups","anchor1","anchor2"] );
t( "Verify deep class selector", "div.blah > p > a", [] );
t( "No element deep selector", "div.foo > span > a", [] );
t( "No element not selector", ".container div:not(.excluded) div", [] );
isSet( jQuery("> :first", document.getElementById("nothiddendiv")), q("nothiddendivchild"), "Verify child context positional selctor" );
isSet( jQuery("> :eq(0)", document.getElementById("nothiddendiv")), q("nothiddendivchild"), "Verify child context positional selctor" );
isSet( jQuery("> *:first", document.getElementById("nothiddendiv")), q("nothiddendivchild"), "Verify child context positional selctor" );
@ -239,7 +244,7 @@ test("attributes", function() {
});
test("pseudo (:) selectors", function() {
expect(34);
expect(51);
t( "First Child", "p:first-child", ["firstp","sndp"] );
t( "Last Child", "p:last-child", ["sap"] );
t( "Only Child", "a:only-child", ["simon1","anchor1","yahoo","anchor2"] );
@ -267,6 +272,25 @@ test("pseudo (:) selectors", function() {
t( "Is A Parent", "p:parent", ["firstp","ap","sndp","en","sap","first"] );
t( "Is Visible", "#form input:visible", ["text1","text2","radio1","radio2","check1","check2","name"] );
t( "Is Hidden", "#form input:hidden", ["hidden1","hidden2"] );
t( "Check position filtering", "div#nothiddendiv:eq(0)", ["nothiddendiv"] );
t( "Check position filtering", "div#nothiddendiv:last", ["nothiddendiv"] );
t( "Check position filtering", "div#nothiddendiv:not(:gt(0))", ["nothiddendiv"] );
t( "Check position filtering", "#foo > :not(:first)", ["en", "sap"] );
t( "Check position filtering", "select > :not(:gt(2))", ["option1a", "option1b", "option1c"] );
t( "Check position filtering", "select:lt(2) :not(:first)", ["option1b", "option1c", "option1d", "option2a", "option2b", "option2c", "option2d"] );
t( "Check position filtering", "div.nothiddendiv:eq(0)", ["nothiddendiv"] );
t( "Check position filtering", "div.nothiddendiv:last", ["nothiddendiv"] );
t( "Check position filtering", "div.nothiddendiv:not(:gt(0))", ["nothiddendiv"] );
t( "Check element position", "div div:eq(0)", ["nothiddendivchild"] );
t( "Check element position", "div div:eq(5)", ["fadeout"] );
t( "Check element position", "div div:eq(27)", ["t2037"] );
t( "Check element position", "div div:first", ["nothiddendivchild"] );
t( "Check element position", "div > div:first", ["nothiddendivchild"] );
t( "Check element position", "#dl div:first div:first", ["foo"] );
t( "Check element position", "#dl div:first > div:first", ["foo"] );
t( "Check element position", "div#nothiddendiv:first > div:first", ["nothiddendivchild"] );
t( "Form element :input", "#form :input", ["text1", "text2", "radio1", "radio2", "check1", "check2", "hidden1", "hidden2", "name", "button", "area1", "select1", "select2", "select3"] );
t( "Form element :radio", "#form :radio", ["radio1", "radio2"] );