diff --git a/sizzle.js b/sizzle.js index 10580704..e3fe7f5a 100644 --- a/sizzle.js +++ b/sizzle.js @@ -34,7 +34,7 @@ var Sizzle = function( selector, context, results, seed ) { if ( context.nodeType !== 1 && context.nodeType !== 9 ) { return []; } - + if ( !selector || typeof selector !== "string" ) { return results; } @@ -44,7 +44,7 @@ var Sizzle = function( selector, context, results, seed ) { contextXML = Sizzle.isXML( context ), parts = [], soFar = selector; - + // Reset the position of the chunker regexp (start from head) do { chunker.exec( "" ); @@ -52,9 +52,9 @@ var Sizzle = function( selector, context, results, seed ) { if ( m ) { soFar = m[3]; - + parts.push( m[1] ); - + if ( m[2] ) { extra = m[3]; break; @@ -78,7 +78,7 @@ var Sizzle = function( selector, context, results, seed ) { if ( Expr.relative[ selector ] ) { selector += parts.shift(); } - + set = posProcess( selector, set, seed ); } } @@ -206,7 +206,7 @@ Sizzle.find = function( expr, context, isXML ) { for ( i = 0, len = Expr.order.length; i < len; i++ ) { type = Expr.order[i]; - + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { left = match[1]; match.splice( 1, 1 ); @@ -333,7 +333,7 @@ Sizzle.error = function( msg ) { * @param {Array|Element} elem */ var getText = Sizzle.getText = function( elem ) { - var i, node, + var i, node, nodeType = elem.nodeType, ret = ""; @@ -368,7 +368,7 @@ var getText = Sizzle.getText = function( elem ) { }; var Expr = Sizzle.selectors = { - order: [ "ID", "NAME", "TAG" ], + order: [ "ID", "TAG" ], match: { ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, @@ -489,7 +489,7 @@ var Expr = Sizzle.selectors = { find: { ID: function( match, context, isXML ) { if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); + var m = context.getElementById( match[1] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 return m && m.parentNode ? [m] : []; @@ -497,24 +497,15 @@ var Expr = Sizzle.selectors = { }, NAME: function( match, context ) { - if ( typeof context.getElementsByName !== "undefined" ) { - var ret = [], - results = context.getElementsByName( match[1] ); - - for ( var i = 0, l = results.length; i < l; i++ ) { - if ( results[i].getAttribute("name") === match[1] ) { - ret.push( results[i] ); - } - } - - return ret.length === 0 ? null : ret; - } + try { + return context.getElementsByName( match[1] ); + } catch( getElementsByNameError ) {} }, TAG: function( match, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { + try { return context.getElementsByTagName( match[1] ); - } + } catch( getElementsByTagNameError ) {} } }, preFilter: { @@ -578,7 +569,7 @@ var Expr = Sizzle.selectors = { ATTR: function( match, curLoop, inplace, result, not, isXML ) { var name = match[1] = match[1].replace( rBackslash, "" ); - + if ( !isXML && Expr.attrMap[name] ) { match[1] = Expr.attrMap[name]; } @@ -612,7 +603,7 @@ var Expr = Sizzle.selectors = { } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { return true; } - + return match; }, @@ -622,7 +613,7 @@ var Expr = Sizzle.selectors = { return match; } }, - + filters: { enabled: function( elem ) { return elem.disabled === false && elem.type !== "hidden"; @@ -635,14 +626,14 @@ var Expr = Sizzle.selectors = { checked: function( elem ) { return elem.checked === true; }, - + selected: function( elem ) { // Accessing this property makes selected-by-default // options in Safari work properly if ( elem.parentNode ) { elem.parentNode.selectedIndex; } - + return elem.selected === true; }, @@ -664,7 +655,7 @@ var Expr = Sizzle.selectors = { text: function( elem ) { var attr = elem.getAttribute( "type" ), type = elem.type; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) // use getAttribute instead to test this case return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); }, @@ -782,22 +773,23 @@ var Expr = Sizzle.selectors = { switch ( type ) { case "only": case "first": - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; } } - if ( type === "first" ) { - return true; + if ( type === "first" ) { + return true; } node = elem; + /* falls through */ case "last": - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; } } @@ -810,22 +802,22 @@ var Expr = Sizzle.selectors = { if ( first === 1 && last === 0 ) { return true; } - + doneName = match[0]; parent = elem.parentNode; - + if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { count = 0; - + for ( node = parent.firstChild; node; node = node.nextSibling ) { if ( node.nodeType === 1 ) { node.nodeIndex = ++count; } - } + } parent[ expando ] = doneName; } - + diff = elem.nodeIndex - last; if ( first === 0 ) { @@ -844,7 +836,7 @@ var Expr = Sizzle.selectors = { TAG: function( elem, match ) { return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; }, - + CLASS: function( elem, match ) { return (" " + (elem.className || elem.getAttribute("class")) + " ") .indexOf( match ) > -1; @@ -914,7 +906,7 @@ var makeArray = function( array, results ) { results.push.apply( results, array ); return results; } - + return array; }; @@ -1047,25 +1039,33 @@ if ( document.documentElement.compareDocumentPosition ) { }; } -// Check to see if the browser returns elements by name when -// querying by getElementById (and provide a workaround) +// Optimize for browsers with compatible getElementsByName +// Workaround browsers that return by name from getElementById (function(){ - // We're going to inject a fake input element with a specified name + // We're going to inject an input and non-input element with the same name var form = document.createElement("div"), - id = "script" + (new Date()).getTime(), - root = document.documentElement; + id = "script" + ( - new Date() ); - form.innerHTML = ""; + form.id = id + 0; + form.innerHTML = "
"; // Inject it into the root element, check its status, and remove it quickly - root.insertBefore( form, root.firstChild ); + document.documentElement.insertBefore( form, document.documentElement.firstChild ); - // The workaround has to do additional checks after a getElementById + // Optimize NAME checks if the browser provides a compatible getElementsByName + // (returning all elements with matching name and not the one with matching id) + if ( document.getElementsByName && + document.getElementsByName( id ).length === 2 + document.getElementsByName( id + 0 ).length ) { + + Expr.order.splice(1, 0, "NAME"); + } + + // The getElementById workaround has to do additional checks // Which slows things down for other browsers (hence the branching) if ( document.getElementById( id ) ) { Expr.find.ID = function( match, context, isXML ) { if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); + var m = context.getElementById( match[1] ); return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? @@ -1082,10 +1082,10 @@ if ( document.documentElement.compareDocumentPosition ) { }; } - root.removeChild( form ); + document.documentElement.removeChild( form ); // release memory in IE - root = form = null; + form = null; })(); (function(){ @@ -1146,7 +1146,7 @@ if ( document.querySelectorAll ) { if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { return; } - + Sizzle = function( query, context, extra, seed ) { context = context || document; @@ -1155,24 +1155,24 @@ if ( document.querySelectorAll ) { if ( !seed && !Sizzle.isXML(context) ) { // See if we find a selector to speed up var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); - + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { // Speed-up: Sizzle("TAG") if ( match[1] ) { return makeArray( context.getElementsByTagName( query ), extra ); - + // Speed-up: Sizzle(".CLASS") } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { return makeArray( context.getElementsByClassName( match[2] ), extra ); } } - + if ( context.nodeType === 9 ) { // Speed-up: Sizzle("body") // The body element only exists once, optimize finding it if ( query === "body" && context.body ) { return makeArray( [ context.body ], extra ); - + // Speed-up: Sizzle("#ID") } else if ( match && match[3] ) { var elem = context.getElementById( match[3] ); @@ -1185,12 +1185,12 @@ if ( document.querySelectorAll ) { if ( elem.id === match[3] ) { return makeArray( [ elem ], extra ); } - + } else { return makeArray( [], extra ); } } - + try { return makeArray( context.querySelectorAll(query), extra ); } catch(qsaError) {} @@ -1228,7 +1228,7 @@ if ( document.querySelectorAll ) { } } } - + return oldSizzle(query, context, extra, seed); }; @@ -1255,7 +1255,7 @@ if ( document.querySelectorAll ) { // This should fail with an exception // Gecko does not error, returns false instead matches.call( document.documentElement, "[test!='']:sizzle" ); - + } catch( pseudoError ) { pseudoWorks = true; } @@ -1265,7 +1265,7 @@ if ( document.querySelectorAll ) { expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); if ( !Sizzle.isXML( node ) ) { - try { + try { if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { var ret = matches.call( node, expr ); @@ -1302,7 +1302,7 @@ if ( document.querySelectorAll ) { if ( div.getElementsByClassName("e").length === 1 ) { return; } - + Expr.order.splice(1, 0, "CLASS"); Expr.find.CLASS = function( match, context, isXML ) { if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { @@ -1353,7 +1353,7 @@ function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { if ( elem ) { var match = false; - + elem = elem[dir]; while ( elem ) { @@ -1406,7 +1406,7 @@ if ( document.documentElement.contains ) { Sizzle.isXML = function( elem ) { // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) + // (such as loading iframes in IE - #4833) var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; diff --git a/test/unit/selector.js b/test/unit/selector.js index a1f464f1..827d6e1c 100644 --- a/test/unit/selector.js +++ b/test/unit/selector.js @@ -187,13 +187,14 @@ test("class", function() { }); test("name", function() { - expect(15); + expect(16); t( "Name selector", "input[name=action]", ["text1"] ); t( "Name selector with single quotes", "input[name='action']", ["text1"] ); t( "Name selector with double quotes", 'input[name="action"]', ["text1"] ); t( "Name selector non-input", "[name=test]", ["length", "fx-queue"] ); + t( "Name selector non-input non-qSA", ":not(:selected)[name=test]", ["length", "fx-queue"] ); t( "Name selector non-input", "[name=div]", ["fadein"] ); t( "Name selector non-input", "*[name=iframe]", ["iframe"] );