From 6dc30ae7f60c44dd83dfb19da61957b20324eb9e Mon Sep 17 00:00:00 2001
From: John Resig <jeresig@gmail.com>
Date: Tue, 13 Jan 2009 16:40:19 +0000
Subject: [PATCH] Merged Sizzle changes back into jQuery.

---
 src/selector.js       |   37 ++++++++++++++++++++++++++-----------
 test/index.html       |    1 +
 test/unit/selector.js |   25 ++++++++++++++++++++-----
 3 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/src/selector.js b/src/selector.js
index 085f0b3..56c8a2a 100644
--- a/src/selector.js
+++ b/src/selector.js
@@ -45,7 +45,7 @@ var Sizzle = function(selector, context, results, seed) {
 				selector = selector.replace( Expr.match.POS, "" );
 			}
 
-			set = Sizzle.filter( later, Sizzle( selector, context ) );
+			set = Sizzle.filter( later, Sizzle( /\s$/.test(selector) ? selector + "*" : selector, context ) );
 		} else {
 			set = Expr.relative[ parts[0] ] ?
 				[ context ] :
@@ -259,7 +259,7 @@ var Expr = Sizzle.selectors = {
 		ID: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
 		CLASS: /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
 		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,
-		ATTR: /\[((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\]/,
+		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
 		TAG: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,
 		CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
 		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
@@ -269,6 +269,11 @@ var Expr = Sizzle.selectors = {
 		"class": "className",
 		"for": "htmlFor"
 	},
+	attrHandle: {
+		href: function(elem){
+			return elem.getAttribute("href");
+		}
+	},
 	relative: {
 		"+": function(checkSet, part){
 			for ( var i = 0, l = checkSet.length; i < l; i++ ) {
@@ -322,7 +327,7 @@ var Expr = Sizzle.selectors = {
 				checkFn = dirNodeCheck;
 			}
 
-			checkFn("parentNode", part, doneName, checkSet, nodeCheck);
+			checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
 		},
 		"~": function(checkSet, part, isXML){
 			var doneName = "done" + (done++), checkFn = dirCheck;
@@ -332,7 +337,7 @@ var Expr = Sizzle.selectors = {
 				checkFn = dirNodeCheck;
 			}
 
-			checkFn("previousSibling", part, doneName, checkSet, nodeCheck);
+			checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
 		}
 	},
 	find: {
@@ -580,7 +585,7 @@ var Expr = Sizzle.selectors = {
 			return match.test( elem.className );
 		},
 		ATTR: function(elem, match){
-			var result = elem[ match[1] ] || elem.getAttribute( match[1] ), value = result + "", type = match[2], check = match[4];
+			var result = Expr.attrHandle[ match[1] ] ? Expr.attrHandle[ match[1] ]( elem ) : elem[ match[1] ] || elem.getAttribute( match[1] ), value = result + "", type = match[2], check = match[4];
 			return result == null ?
 				false :
 				type === "=" ?
@@ -685,9 +690,10 @@ try {
 	root.removeChild( form );
 })();
 
-// Check to see if the browser returns only elements
-// when doing getElementsByTagName("*")
 (function(){
+	// Check to see if the browser returns only elements
+	// when doing getElementsByTagName("*")
+
 	// Create a fake element
 	var div = document.createElement("div");
 	div.appendChild( document.createComment("") );
@@ -713,6 +719,14 @@ try {
 			return results;
 		};
 	}
+
+	// Check to see if an attribute returns normalized href attributes
+	div.innerHTML = "<a href='#'></a>";
+	if ( div.firstChild.getAttribute("href") !== "#" ) {
+		Expr.attrHandle.href = function(elem){
+			return elem.getAttribute("href", 2);
+		};
+	}
 })();
 
 if ( document.querySelectorAll ) (function(){
@@ -743,7 +757,7 @@ if ( document.documentElement.getElementsByClassName ) {
 	};
 }
 
-function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck ) {
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
 	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
 		var elem = checkSet[i];
 		if ( elem ) {
@@ -757,7 +771,7 @@ function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck ) {
 					break;
 				}
 
-				if ( elem.nodeType === 1 )
+				if ( elem.nodeType === 1 && !isXML )
 					elem[doneName] = i;
 
 				if ( elem.nodeName === cur ) {
@@ -773,7 +787,7 @@ function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck ) {
 	}
 }
 
-function dirCheck( dir, cur, doneName, checkSet, nodeCheck ) {
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
 	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
 		var elem = checkSet[i];
 		if ( elem ) {
@@ -787,7 +801,8 @@ function dirCheck( dir, cur, doneName, checkSet, nodeCheck ) {
 				}
 
 				if ( elem.nodeType === 1 ) {
-					elem[doneName] = i;
+					if ( !isXML )
+						elem[doneName] = i;
 
 					if ( typeof cur !== "string" ) {
 						if ( elem === cur ) {
diff --git a/test/index.html b/test/index.html
index 30e955c..cd5a247 100644
--- a/test/index.html
+++ b/test/index.html
@@ -54,6 +54,7 @@
 		<ul id="firstUL"></ul>
 		<ol id="empty"></ol>
 		<form id="form" action="formaction">
+			<label for="action" id="label-for">Action:</label>
 			<input type="text" name="action" value="Test" id="text1" maxlength="30"/>
 			<input type="text" name="text2" value="Test" id="text2" disabled="disabled"/>
 			<input type="radio" name="radio1" id="radio1" value="on"/>
diff --git a/test/unit/selector.js b/test/unit/selector.js
index 183bacb..638f508 100644
--- a/test/unit/selector.js
+++ b/test/unit/selector.js
@@ -2,6 +2,8 @@ module("selector");
 
 test("element", function() {
 	expect(9);
+	reset();
+
 	ok( jQuery("*").size() >= 30, "Select all" );
 	var all = jQuery("*"), good = true;
 	for ( var i = 0; i < all.length; i++ )
@@ -39,7 +41,7 @@ test("broken", function() {
 				name + ": " + selector );
 		}
 	}
-
+	
 	broken( "Broken Selector", "[", [] );
 	broken( "Broken Selector", "(", [] );
 	broken( "Broken Selector", "{", [] );
@@ -139,7 +141,7 @@ test("multiple", function() {
 });
 
 test("child and adjacent", function() {
-	expect(38);
+	expect(41);
 	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"] );
@@ -154,6 +156,10 @@ test("child and adjacent", function() {
 	t( "Adjacent", "p + p", ["ap","en","sap"] );
 	t( "Comma, Child, and Adjacent", "a + a, code > a", ["groups","anchor1","anchor2"] );
 
+	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" );
+
 	t( "Non-existant ancestors", ".fototab > .thumbnails > a", [] );
 	
 	t( "First Child", "p:first-child", ["firstp","sndp"] );
@@ -162,8 +168,8 @@ test("child and adjacent", function() {
 	t( "Last Child", "p:last-child", ["sap"] );
 	t( "Last Child", "a:last-child", ["simon1","anchor1","mark","yahoo","anchor2","simon"] );
 	
-	t( "Nth-child", "#main form#form > *:nth-child(2)", ["text2"] );
-	t( "Nth-child", "#main form#form > :nth-child(2)", ["text2"] );
+	t( "Nth-child", "#main form#form > *:nth-child(2)", ["text1"] );
+	t( "Nth-child", "#main form#form > :nth-child(2)", ["text1"] );
 
 	t( "Nth-child", "#form select:first option:nth-child(3)", ["option1c"] );
 	t( "Nth-child", "#form select:first option:nth-child(0n+3)", ["option1c"] );
@@ -186,15 +192,24 @@ test("child and adjacent", function() {
 });
 
 test("attributes", function() {
-	expect(21);
+	expect(27);
 	t( "Attribute Exists", "a[title]", ["google"] );
 	t( "Attribute Exists", "*[title]", ["google"] );
 	t( "Attribute Exists", "[title]", ["google"] );
+	t( "Attribute Exists", "a[ title ]", ["google"] );
 	
 	t( "Attribute Equals", "a[rel='bookmark']", ["simon1"] );
 	t( "Attribute Equals", 'a[rel="bookmark"]', ["simon1"] );
 	t( "Attribute Equals", "a[rel=bookmark]", ["simon1"] );
 	t( "Attribute Equals", "a[href='http://www.google.com/']", ["google"] );
+	t( "Attribute Equals", "a[ rel = 'bookmark' ]", ["simon1"] );
+
+	document.getElementById("anchor2").href = "#2";
+	t( "href Attribute", "p a[href^=#]", ["anchor2"] );
+	t( "href Attribute", "p a[href*=#]", ["simon1", "anchor2"] );
+
+	t( "for Attribute", "form label[for]", ["label-for"] );
+	t( "for Attribute in form", "#form [for=action]", ["label-for"] );
 	
 	var results = ["hidden1","radio1","radio2"];
 	
-- 
1.7.10.4