diff options
Diffstat (limited to 'bin/wiki/ImportarDesdeURL/node_modules/css-select/lib/pseudos.js')
-rw-r--r-- | bin/wiki/ImportarDesdeURL/node_modules/css-select/lib/pseudos.js | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/bin/wiki/ImportarDesdeURL/node_modules/css-select/lib/pseudos.js b/bin/wiki/ImportarDesdeURL/node_modules/css-select/lib/pseudos.js new file mode 100644 index 00000000..f6774ecf --- /dev/null +++ b/bin/wiki/ImportarDesdeURL/node_modules/css-select/lib/pseudos.js @@ -0,0 +1,393 @@ +/* + pseudo selectors + + --- + + they are available in two forms: + * filters called when the selector + is compiled and return a function + that needs to return next() + * pseudos get called on execution + they need to return a boolean +*/ + +var DomUtils = require("domutils"), + isTag = DomUtils.isTag, + getText = DomUtils.getText, + getParent = DomUtils.getParent, + getChildren = DomUtils.getChildren, + getSiblings = DomUtils.getSiblings, + hasAttrib = DomUtils.hasAttrib, + getName = DomUtils.getName, + getAttribute= DomUtils.getAttributeValue, + getNCheck = require("nth-check"), + checkAttrib = require("./attributes.js").rules.equals, + BaseFuncs = require("boolbase"), + trueFunc = BaseFuncs.trueFunc, + falseFunc = BaseFuncs.falseFunc; + +//helper methods +function getFirstElement(elems){ + for(var i = 0; elems && i < elems.length; i++){ + if(isTag(elems[i])) return elems[i]; + } +} + +function getAttribFunc(name, value){ + var data = {name: name, value: value}; + return function attribFunc(next){ + return checkAttrib(next, data); + }; +} + +function getChildFunc(next){ + return function(elem){ + return !!getParent(elem) && next(elem); + }; +} + +var filters = { + contains: function(next, text){ + return function contains(elem){ + return next(elem) && getText(elem).indexOf(text) >= 0; + }; + }, + icontains: function(next, text){ + var itext = text.toLowerCase(); + return function icontains(elem){ + return next(elem) && + getText(elem).toLowerCase().indexOf(itext) >= 0; + }; + }, + + //location specific methods + "nth-child": function(next, rule){ + var func = getNCheck(rule); + + if(func === falseFunc) return func; + if(func === trueFunc) return getChildFunc(next); + + return function nthChild(elem){ + var siblings = getSiblings(elem); + + for(var i = 0, pos = 0; i < siblings.length; i++){ + if(isTag(siblings[i])){ + if(siblings[i] === elem) break; + else pos++; + } + } + + return func(pos) && next(elem); + }; + }, + "nth-last-child": function(next, rule){ + var func = getNCheck(rule); + + if(func === falseFunc) return func; + if(func === trueFunc) return getChildFunc(next); + + return function nthLastChild(elem){ + var siblings = getSiblings(elem); + + for(var pos = 0, i = siblings.length - 1; i >= 0; i--){ + if(isTag(siblings[i])){ + if(siblings[i] === elem) break; + else pos++; + } + } + + return func(pos) && next(elem); + }; + }, + "nth-of-type": function(next, rule){ + var func = getNCheck(rule); + + if(func === falseFunc) return func; + if(func === trueFunc) return getChildFunc(next); + + return function nthOfType(elem){ + var siblings = getSiblings(elem); + + for(var pos = 0, i = 0; i < siblings.length; i++){ + if(isTag(siblings[i])){ + if(siblings[i] === elem) break; + if(getName(siblings[i]) === getName(elem)) pos++; + } + } + + return func(pos) && next(elem); + }; + }, + "nth-last-of-type": function(next, rule){ + var func = getNCheck(rule); + + if(func === falseFunc) return func; + if(func === trueFunc) return getChildFunc(next); + + return function nthLastOfType(elem){ + var siblings = getSiblings(elem); + + for(var pos = 0, i = siblings.length - 1; i >= 0; i--){ + if(isTag(siblings[i])){ + if(siblings[i] === elem) break; + if(getName(siblings[i]) === getName(elem)) pos++; + } + } + + return func(pos) && next(elem); + }; + }, + + //TODO determine the actual root element + root: function(next){ + return function(elem){ + return !getParent(elem) && next(elem); + }; + }, + + scope: function(next, rule, options, context){ + if(!context || context.length === 0){ + //equivalent to :root + return filters.root(next); + } + + if(context.length === 1){ + //NOTE: can't be unpacked, as :has uses this for side-effects + return function(elem){ + return context[0] === elem && next(elem); + }; + } + + return function(elem){ + return context.indexOf(elem) >= 0 && next(elem); + }; + }, + + //jQuery extensions (others follow as pseudos) + checkbox: getAttribFunc("type", "checkbox"), + file: getAttribFunc("type", "file"), + password: getAttribFunc("type", "password"), + radio: getAttribFunc("type", "radio"), + reset: getAttribFunc("type", "reset"), + image: getAttribFunc("type", "image"), + submit: getAttribFunc("type", "submit") +}; + +//while filters are precompiled, pseudos get called when they are needed +var pseudos = { + empty: function(elem){ + return !getChildren(elem).some(function(elem){ + return isTag(elem) || elem.type === "text"; + }); + }, + + "first-child": function(elem){ + return getFirstElement(getSiblings(elem)) === elem; + }, + "last-child": function(elem){ + var siblings = getSiblings(elem); + + for(var i = siblings.length - 1; i >= 0; i--){ + if(siblings[i] === elem) return true; + if(isTag(siblings[i])) break; + } + + return false; + }, + "first-of-type": function(elem){ + var siblings = getSiblings(elem); + + for(var i = 0; i < siblings.length; i++){ + if(isTag(siblings[i])){ + if(siblings[i] === elem) return true; + if(getName(siblings[i]) === getName(elem)) break; + } + } + + return false; + }, + "last-of-type": function(elem){ + var siblings = getSiblings(elem); + + for(var i = siblings.length-1; i >= 0; i--){ + if(isTag(siblings[i])){ + if(siblings[i] === elem) return true; + if(getName(siblings[i]) === getName(elem)) break; + } + } + + return false; + }, + "only-of-type": function(elem){ + var siblings = getSiblings(elem); + + for(var i = 0, j = siblings.length; i < j; i++){ + if(isTag(siblings[i])){ + if(siblings[i] === elem) continue; + if(getName(siblings[i]) === getName(elem)) return false; + } + } + + return true; + }, + "only-child": function(elem){ + var siblings = getSiblings(elem); + + for(var i = 0; i < siblings.length; i++){ + if(isTag(siblings[i]) && siblings[i] !== elem) return false; + } + + return true; + }, + + //:matches(a, area, link)[href] + link: function(elem){ + return hasAttrib(elem, "href"); + }, + visited: falseFunc, //seems to be a valid implementation + //TODO: :any-link once the name is finalized (as an alias of :link) + + //forms + //to consider: :target + + //:matches([selected], select:not([multiple]):not(> option[selected]) > option:first-of-type) + selected: function(elem){ + if(hasAttrib(elem, "selected")) return true; + else if(getName(elem) !== "option") return false; + + //the first <option> in a <select> is also selected + var parent = getParent(elem); + + if( + !parent || + getName(parent) !== "select" || + hasAttrib(parent, "multiple") + ) return false; + + var siblings = getChildren(parent), + sawElem = false; + + for(var i = 0; i < siblings.length; i++){ + if(isTag(siblings[i])){ + if(siblings[i] === elem){ + sawElem = true; + } else if(!sawElem){ + return false; + } else if(hasAttrib(siblings[i], "selected")){ + return false; + } + } + } + + return sawElem; + }, + //https://html.spec.whatwg.org/multipage/scripting.html#disabled-elements + //:matches( + // :matches(button, input, select, textarea, menuitem, optgroup, option)[disabled], + // optgroup[disabled] > option), + // fieldset[disabled] * //TODO not child of first <legend> + //) + disabled: function(elem){ + return hasAttrib(elem, "disabled"); + }, + enabled: function(elem){ + return !hasAttrib(elem, "disabled"); + }, + //:matches(:matches(:radio, :checkbox)[checked], :selected) (TODO menuitem) + checked: function(elem){ + return hasAttrib(elem, "checked") || pseudos.selected(elem); + }, + //:matches(input, select, textarea)[required] + required: function(elem){ + return hasAttrib(elem, "required"); + }, + //:matches(input, select, textarea):not([required]) + optional: function(elem){ + return !hasAttrib(elem, "required"); + }, + + //jQuery extensions + + //:not(:empty) + parent: function(elem){ + return !pseudos.empty(elem); + }, + //:matches(h1, h2, h3, h4, h5, h6) + header: function(elem){ + var name = getName(elem); + return name === "h1" || + name === "h2" || + name === "h3" || + name === "h4" || + name === "h5" || + name === "h6"; + }, + + //:matches(button, input[type=button]) + button: function(elem){ + var name = getName(elem); + return name === "button" || + name === "input" && + getAttribute(elem, "type") === "button"; + }, + //:matches(input, textarea, select, button) + input: function(elem){ + var name = getName(elem); + return name === "input" || + name === "textarea" || + name === "select" || + name === "button"; + }, + //input:matches(:not([type!='']), [type='text' i]) + text: function(elem){ + var attr; + return getName(elem) === "input" && ( + !(attr = getAttribute(elem, "type")) || + attr.toLowerCase() === "text" + ); + } +}; + +function verifyArgs(func, name, subselect){ + if(subselect === null){ + if(func.length > 1 && name !== "scope"){ + throw new SyntaxError("pseudo-selector :" + name + " requires an argument"); + } + } else { + if(func.length === 1){ + throw new SyntaxError("pseudo-selector :" + name + " doesn't have any arguments"); + } + } +} + +//FIXME this feels hacky +var re_CSS3 = /^(?:(?:nth|last|first|only)-(?:child|of-type)|root|empty|(?:en|dis)abled|checked|not)$/; + +module.exports = { + compile: function(next, data, options, context){ + var name = data.name, + subselect = data.data; + + if(options && options.strict && !re_CSS3.test(name)){ + throw SyntaxError(":" + name + " isn't part of CSS3"); + } + + if(typeof filters[name] === "function"){ + verifyArgs(filters[name], name, subselect); + return filters[name](next, subselect, options, context); + } else if(typeof pseudos[name] === "function"){ + var func = pseudos[name]; + verifyArgs(func, name, subselect); + + if(next === trueFunc) return func; + + return function pseudoArgs(elem){ + return func(elem, subselect) && next(elem); + }; + } else { + throw new SyntaxError("unmatched pseudo-class :" + name); + } + }, + filters: filters, + pseudos: pseudos +}; |