| 1512 | } |
| 1513 | |
| 1514 | function addCombinator(matcher, combinator, base) { |
| 1515 | var dir = combinator.dir, |
| 1516 | checkNonElements = base && dir === "parentNode", |
| 1517 | doneName = done++; |
| 1518 | |
| 1519 | return combinator.first ? |
| 1520 | // Check against closest ancestor/preceding element |
| 1521 | |
| 1522 | function(elem, context, xml) { |
| 1523 | while ((elem = elem[dir])) { |
| 1524 | if (elem.nodeType === 1 || checkNonElements) { |
| 1525 | return matcher(elem, context, xml); |
| 1526 | } |
| 1527 | } |
| 1528 | } : |
| 1529 | |
| 1530 | // Check against all ancestor/preceding elements |
| 1531 | |
| 1532 | function(elem, context, xml) { |
| 1533 | var data, cache, outerCache, |
| 1534 | dirkey = dirruns + " " + doneName; |
| 1535 | |
| 1536 | // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching |
| 1537 | if (xml) { |
| 1538 | while ((elem = elem[dir])) { |
| 1539 | if (elem.nodeType === 1 || checkNonElements) { |
| 1540 | if (matcher(elem, context, xml)) { |
| 1541 | return true; |
| 1542 | } |
| 1543 | } |
| 1544 | } |
| 1545 | } else { |
| 1546 | while ((elem = elem[dir])) { |
| 1547 | if (elem.nodeType === 1 || checkNonElements) { |
| 1548 | outerCache = elem[expando] || (elem[expando] = {}); |
| 1549 | if ((cache = outerCache[dir]) && cache[0] === dirkey) { |
| 1550 | if ((data = cache[1]) === true || data === cachedruns) { |
| 1551 | return data === true; |
| 1552 | } |
| 1553 | } else { |
| 1554 | cache = outerCache[dir] = [dirkey]; |
| 1555 | cache[1] = matcher(elem, context, xml) || cachedruns; |
| 1556 | if (cache[1] === true) { |
| 1557 | return true; |
| 1558 | } |
| 1559 | } |
| 1560 | } |
| 1561 | } |
| 1562 | } |
| 1563 | }; |
| 1564 | } |
| 1565 | |
| 1566 | function elementMatcher(matchers) { |
| 1567 | return matchers.length > 1 ? |