X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fselector.js;h=fcab67fbecdd19456e537348b88783f505bc4d58;hb=f8ef75eb9124ce924be5fb521c783efd5c996e33;hp=f1745e4732bf1b59c9f53c1ef6525c37c6cf9291;hpb=20827707a94c8569bcc422f71bf5b37bc55695df;p=jquery.git diff --git a/src/selector.js b/src/selector.js index f1745e4..fcab67f 100644 --- a/src/selector.js +++ b/src/selector.js @@ -1,34 +1,35 @@ /*! - * Sizzle CSS Selector Engine - v0.9.3 + * Sizzle CSS Selector Engine - v1.0 * Copyright 2009, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * More information: http://sizzlejs.com/ */ (function(){ -var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[]+)+|[>+~])(\s*,\s*)?/g, +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g, done = 0, toString = Object.prototype.toString; var Sizzle = function(selector, context, results, seed) { results = results || []; - context = context || document; + var origContext = context = context || document; - if ( context.nodeType !== 1 && context.nodeType !== 9 ) + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { return []; - + } + if ( !selector || typeof selector !== "string" ) { return results; } - var parts = [], m, set, checkSet, check, mode, extra, prune = true; - + var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context); + // Reset the position of the chunker regexp (start from head) chunker.lastIndex = 0; - + while ( (m = chunker.exec(selector)) !== null ) { parts.push( m[1] ); - + if ( m[2] ) { extra = RegExp.rightContext; break; @@ -53,31 +54,43 @@ var Sizzle = function(selector, context, results, seed) { } } } else { - var ret = seed ? - { expr: parts.pop(), set: makeArray(seed) } : - Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context, isXML(context) ); - set = Sizzle.filter( ret.expr, ret.set ); - - if ( parts.length > 0 ) { - checkSet = makeArray(set); - } else { - prune = false; + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; } - while ( parts.length ) { - var cur = parts.pop(), pop = cur; + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; - if ( !Expr.relative[ cur ] ) { - cur = ""; + if ( parts.length > 0 ) { + checkSet = makeArray(set); } else { - pop = parts.pop(); + prune = false; } - if ( pop == null ) { - pop = context; - } + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } - Expr.relative[ cur ]( checkSet, pop, isXML(context) ); + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; } } @@ -92,7 +105,7 @@ var Sizzle = function(selector, context, results, seed) { if ( toString.call(checkSet) === "[object Array]" ) { if ( !prune ) { results.push.apply( results, checkSet ); - } else if ( context.nodeType === 1 ) { + } else if ( context && context.nodeType === 1 ) { for ( var i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { results.push( set[i] ); @@ -110,23 +123,26 @@ var Sizzle = function(selector, context, results, seed) { } if ( extra ) { - Sizzle( extra, context, results, seed ); + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } - if ( sortOrder ) { - hasDuplicate = false; - results.sort(sortOrder); + return results; +}; - if ( hasDuplicate ) { - for ( var i = 1; i < results.length; i++ ) { - if ( results[i] === results[i-1] ) { - results.splice(i--, 1); - } +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = false; + results.sort(sortOrder); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); } } } } - - return results; }; Sizzle.matches = function(expr, set){ @@ -142,7 +158,7 @@ Sizzle.find = function(expr, context, isXML){ for ( var i = 0, l = Expr.order.length; i < l; i++ ) { var type = Expr.order[i], match; - + if ( (match = Expr.match[ type ].exec( expr )) ) { var left = RegExp.leftContext; @@ -165,7 +181,8 @@ Sizzle.find = function(expr, context, isXML){ }; Sizzle.filter = function(expr, set, inplace, not){ - var old = expr, result = [], curLoop = set, match, anyFound; + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && isXML(set[0]); while ( expr && set.length ) { for ( var type in Expr.filter ) { @@ -178,7 +195,7 @@ Sizzle.filter = function(expr, set, inplace, not){ } if ( Expr.preFilter[ type ] ) { - match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not ); + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); if ( !match ) { anyFound = found = true; @@ -261,23 +278,32 @@ var Expr = Sizzle.selectors = { }, relative: { "+": function(checkSet, part, isXML){ - var isPartStr = typeof part === "string", + var isPartStr = typeof part === "string", isTag = isPartStr && !/\W/.test(part), isPartStrNotTag = isPartStr && !isTag; - if ( isTag && !isXML ) part = part.toUpperCase(); + + if ( isTag && !isXML ) { + part = part.toUpperCase(); + } + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { - if ( elem = checkSet[i] ) { - while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}; + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? - elem : elem === part; + elem || false : + elem === part; } } - if (isPartStrNotTag) { + + if ( isPartStrNotTag ) { Sizzle.filter( part, checkSet, true ); } }, ">": function(checkSet, part, isXML){ - if ( typeof part === "string" && !/\W/.test(part) ) { + var isPartStr = typeof part === "string"; + + if ( isPartStr && !/\W/.test(part) ) { part = isXML ? part : part.toUpperCase(); for ( var i = 0, l = checkSet.length; i < l; i++ ) { @@ -291,13 +317,13 @@ var Expr = Sizzle.selectors = { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { - checkSet[i] = typeof part === "string" ? + checkSet[i] = isPartStr ? elem.parentNode : elem.parentNode === part; } } - if ( typeof part === "string" ) { + if ( isPartStr ) { Sizzle.filter( part, checkSet, true ); } } @@ -332,7 +358,14 @@ var Expr = Sizzle.selectors = { }, NAME: function(match, context, isXML){ if ( typeof context.getElementsByName !== "undefined" ) { - var ret = context.getElementsByName(match[1]); + 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; } }, @@ -341,9 +374,13 @@ var Expr = Sizzle.selectors = { } }, preFilter: { - CLASS: function(match, curLoop, inplace, result, not){ + CLASS: function(match, curLoop, inplace, result, not, isXML){ match = " " + match[1].replace(/\\/g, "") + " "; + if ( isXML ) { + return match; + } + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { if ( elem ) { if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { @@ -381,10 +418,10 @@ var Expr = Sizzle.selectors = { return match; }, - ATTR: function(match){ + ATTR: function(match, curLoop, inplace, result, not, isXML){ var name = match[1].replace(/\\/g, ""); - - if ( Expr.attrMap[name] ) { + + if ( !isXML && Expr.attrMap[name] ) { match[1] = Expr.attrMap[name]; } @@ -406,10 +443,10 @@ var Expr = Sizzle.selectors = { } return false; } - } else if ( Expr.match.POS.test( match[0] ) ) { + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { return true; } - + return match; }, POS: function(match){ @@ -503,6 +540,25 @@ var Expr = Sizzle.selectors = { } }, filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + + return true; + } + }, CHILD: function(elem, match){ var type = match[1], node = elem; switch (type) { @@ -524,20 +580,20 @@ var Expr = Sizzle.selectors = { if ( first == 1 && last == 0 ) { return true; } - + var doneName = match[0], parent = elem.parentNode; - + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { var count = 0; for ( node = parent.firstChild; node; node = node.nextSibling ) { if ( node.nodeType === 1 ) { node.nodeIndex = ++count; } - } + } parent.sizcache = doneName; } - + var diff = elem.nodeIndex - last; if ( first == 0 ) { return diff == 0; @@ -546,25 +602,6 @@ var Expr = Sizzle.selectors = { } } }, - PSEUDO: function(elem, match, i, array){ - var name = match[1], filter = Expr.filters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - } else if ( name === "contains" ) { - return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; - } else if ( name === "not" ) { - var not = match[3]; - - for ( var i = 0, l = not.length; i < l; i++ ) { - if ( not[i] === elem ) { - return false; - } - } - - return true; - } - }, ID: function(elem, match){ return elem.nodeType === 1 && elem.getAttribute("id") === match; }, @@ -572,7 +609,8 @@ var Expr = Sizzle.selectors = { return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; }, CLASS: function(elem, match){ - return match.test( elem.className ); + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; }, ATTR: function(elem, match){ var name = match[1], @@ -618,7 +656,7 @@ var Expr = Sizzle.selectors = { var origPOS = Expr.match.POS; for ( var type in Expr.match ) { - Expr.match[ type ] = RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); } var makeArray = function(array, results) { @@ -628,7 +666,7 @@ var makeArray = function(array, results) { results.push.apply( results, array ); return results; } - + return array; }; @@ -662,18 +700,15 @@ try { var sortOrder; -if ( Array.prototype.indexOf ) { - var indexOf = Array.prototype.indexOf, - allSort = document.getElementsByTagName("*"); - +if ( document.documentElement.compareDocumentPosition ) { sortOrder = function( a, b ) { - var ret = indexOf.call( allSort, a ) - indexOf.call( allSort, b ); + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; if ( ret === 0 ) { hasDuplicate = true; } return ret; }; -} else if ( document.documentElement.sourceIndex === 1 ) { +} else if ( "sourceIndex" in document.documentElement ) { sortOrder = function( a, b ) { var ret = a.sourceIndex - b.sourceIndex; if ( ret === 0 ) { @@ -681,15 +716,28 @@ if ( Array.prototype.indexOf ) { } return ret; }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.selectNode(a); + aRange.collapse(true); + bRange.selectNode(b); + bRange.collapse(true); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; } // Check to see if the browser returns elements by name when // querying by getElementById (and provide a workaround) (function(){ // We're going to inject a fake input element with a specified name - var form = document.createElement("form"), + var form = document.createElement("div"), id = "script" + (new Date).getTime(); - form.innerHTML = ""; + form.innerHTML = ""; // Inject it into the root element, check its status, and remove it quickly var root = document.documentElement; @@ -763,7 +811,7 @@ if ( document.querySelectorAll ) (function(){ if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { return; } - + Sizzle = function(query, context, extra, seed){ context = context || document; @@ -774,14 +822,13 @@ if ( document.querySelectorAll ) (function(){ return makeArray( context.querySelectorAll(query), extra ); } catch(e){} } - + return oldSizzle(query, context, extra, seed); }; - Sizzle.find = oldSizzle.find; - Sizzle.filter = oldSizzle.filter; - Sizzle.selectors = oldSizzle.selectors; - Sizzle.matches = oldSizzle.matches; + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } })(); if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ @@ -799,8 +846,10 @@ if ( document.getElementsByClassName && document.documentElement.getElementsByCl return; Expr.order.splice(1, 0, "CLASS"); - Expr.find.CLASS = function(match, context) { - return context.getElementsByClassName(match[1]); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } }; })(); @@ -891,7 +940,7 @@ var contains = document.compareDocumentPosition ? function(a, b){ var isXML = function(elem){ return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || - !!elem.ownerDocument && isXML( elem.ownerDocument ); + !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; }; var posProcess = function(selector, context){ @@ -916,20 +965,15 @@ var posProcess = function(selector, context){ // EXPOSE jQuery.find = Sizzle; -jQuery.filter = Sizzle.filter; jQuery.expr = Sizzle.selectors; jQuery.expr[":"] = jQuery.expr.filters; Sizzle.selectors.filters.hidden = function(elem){ - return "hidden" === elem.type || - jQuery.css(elem, "display") === "none" || - jQuery.css(elem, "visibility") === "hidden"; + return elem.offsetWidth === 0 && elem.offsetHeight === 0; }; Sizzle.selectors.filters.visible = function(elem){ - return "hidden" !== elem.type && - jQuery.css(elem, "display") !== "none" && - jQuery.css(elem, "visibility") !== "hidden"; + return elem.offsetWidth > 0 || elem.offsetHeight > 0; }; Sizzle.selectors.filters.animated = function(elem){ @@ -938,7 +982,7 @@ Sizzle.selectors.filters.animated = function(elem){ }).length; }; -jQuery.multiFilter = function( expr, elems, not ) { +jQuery.filter = jQuery.multiFilter = function( expr, elems, not ) { if ( not ) { expr = ":not(" + expr + ")"; }