| 5089 | } |
| 5090 | |
| 5091 | function addCombinator( matcher, combinator, base ) { |
| 5092 | var dir = combinator.dir, |
| 5093 | checkNonElements = base && dir === "parentNode", |
| 5094 | doneName = done++; |
| 5095 | |
| 5096 | return combinator.first ? |
| 5097 | // Check against closest ancestor/preceding element |
| 5098 | function( elem, context, xml ) { |
| 5099 | while ( (elem = elem[ dir ]) ) { |
| 5100 | if ( elem.nodeType === 1 || checkNonElements ) { |
| 5101 | return matcher( elem, context, xml ); |
| 5102 | } |
| 5103 | } |
| 5104 | } : |
| 5105 | |
| 5106 | // Check against all ancestor/preceding elements |
| 5107 | function( elem, context, xml ) { |
| 5108 | var data, cache, outerCache, |
| 5109 | dirkey = dirruns + " " + doneName; |
| 5110 | |
| 5111 | // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching |
| 5112 | if ( xml ) { |
| 5113 | while ( (elem = elem[ dir ]) ) { |
| 5114 | if ( elem.nodeType === 1 || checkNonElements ) { |
| 5115 | if ( matcher( elem, context, xml ) ) { |
| 5116 | return true; |
| 5117 | } |
| 5118 | } |
| 5119 | } |
| 5120 | } else { |
| 5121 | while ( (elem = elem[ dir ]) ) { |
| 5122 | if ( elem.nodeType === 1 || checkNonElements ) { |
| 5123 | outerCache = elem[ expando ] || (elem[ expando ] = {}); |
| 5124 | if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) { |
| 5125 | if ( (data = cache[1]) === true || data === cachedruns ) { |
| 5126 | return data === true; |
| 5127 | } |
| 5128 | } else { |
| 5129 | cache = outerCache[ dir ] = [ dirkey ]; |
| 5130 | cache[1] = matcher( elem, context, xml ) || cachedruns; |
| 5131 | if ( cache[1] === true ) { |
| 5132 | return true; |
| 5133 | } |
| 5134 | } |
| 5135 | } |
| 5136 | } |
| 5137 | } |
| 5138 | }; |
| 5139 | } |
| 5140 | |
| 5141 | function elementMatcher( matchers ) { |
| 5142 | return matchers.length > 1 ? |