| Leo Repp | 58b9f11 | 2021-11-22 11:57:47 +0100 | [diff] [blame^] | 1 | "use strict"; |
| 2 | |
| 3 | module.exports = CSSselect; |
| 4 | |
| 5 | var DomUtils = require("domutils"); |
| 6 | var falseFunc = require("boolbase").falseFunc; |
| 7 | var compileRaw = require("./lib/compile.js"); |
| 8 | |
| 9 | function wrapCompile(func) { |
| 10 | return function addAdapter(selector, options, context) { |
| 11 | options = options || {}; |
| 12 | options.adapter = options.adapter || DomUtils; |
| 13 | |
| 14 | return func(selector, options, context); |
| 15 | }; |
| 16 | } |
| 17 | |
| 18 | var compile = wrapCompile(compileRaw); |
| 19 | var compileUnsafe = wrapCompile(compileRaw.compileUnsafe); |
| 20 | |
| 21 | function getSelectorFunc(searchFunc) { |
| 22 | return function select(query, elems, options) { |
| 23 | options = options || {}; |
| 24 | options.adapter = options.adapter || DomUtils; |
| 25 | |
| 26 | if (typeof query !== "function") { |
| 27 | query = compileUnsafe(query, options, elems); |
| 28 | } |
| 29 | if (query.shouldTestNextSiblings) { |
| 30 | elems = appendNextSiblings((options && options.context) || elems, options.adapter); |
| 31 | } |
| 32 | if (!Array.isArray(elems)) elems = options.adapter.getChildren(elems); |
| 33 | else elems = options.adapter.removeSubsets(elems); |
| 34 | return searchFunc(query, elems, options); |
| 35 | }; |
| 36 | } |
| 37 | |
| 38 | function getNextSiblings(elem, adapter) { |
| 39 | var siblings = adapter.getSiblings(elem); |
| 40 | if (!Array.isArray(siblings)) return []; |
| 41 | siblings = siblings.slice(0); |
| 42 | while (siblings.shift() !== elem); |
| 43 | return siblings; |
| 44 | } |
| 45 | |
| 46 | function appendNextSiblings(elems, adapter) { |
| 47 | // Order matters because jQuery seems to check the children before the siblings |
| 48 | if (!Array.isArray(elems)) elems = [elems]; |
| 49 | var newElems = elems.slice(0); |
| 50 | |
| 51 | for (var i = 0, len = elems.length; i < len; i++) { |
| 52 | var nextSiblings = getNextSiblings(newElems[i], adapter); |
| 53 | newElems.push.apply(newElems, nextSiblings); |
| 54 | } |
| 55 | return newElems; |
| 56 | } |
| 57 | |
| 58 | var selectAll = getSelectorFunc(function selectAll(query, elems, options) { |
| 59 | return query === falseFunc || !elems || elems.length === 0 ? [] : options.adapter.findAll(query, elems); |
| 60 | }); |
| 61 | |
| 62 | var selectOne = getSelectorFunc(function selectOne(query, elems, options) { |
| 63 | return query === falseFunc || !elems || elems.length === 0 ? null : options.adapter.findOne(query, elems); |
| 64 | }); |
| 65 | |
| 66 | function is(elem, query, options) { |
| 67 | options = options || {}; |
| 68 | options.adapter = options.adapter || DomUtils; |
| 69 | return (typeof query === "function" ? query : compile(query, options))(elem); |
| 70 | } |
| 71 | |
| 72 | /* |
| 73 | the exported interface |
| 74 | */ |
| 75 | function CSSselect(query, elems, options) { |
| 76 | return selectAll(query, elems, options); |
| 77 | } |
| 78 | |
| 79 | CSSselect.compile = compile; |
| 80 | CSSselect.filters = compileRaw.Pseudos.filters; |
| 81 | CSSselect.pseudos = compileRaw.Pseudos.pseudos; |
| 82 | |
| 83 | CSSselect.selectAll = selectAll; |
| 84 | CSSselect.selectOne = selectOne; |
| 85 | |
| 86 | CSSselect.is = is; |
| 87 | |
| 88 | //legacy methods (might be removed) |
| 89 | CSSselect.parse = compile; |
| 90 | CSSselect.iterate = selectAll; |
| 91 | |
| 92 | //hooks |
| 93 | CSSselect._compileUnsafe = compileUnsafe; |
| 94 | CSSselect._compileToken = compileRaw.compileToken; |