123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- var falseFunc = require("boolbase").falseFunc;
- //https://github.com/slevithan/XRegExp/blob/master/src/xregexp.js#L469
- var reChars = /[-[\]{}()*+?.,\\^$|#\s]/g;
- /*
- attribute selectors
- */
- var attributeRules = {
- __proto__: null,
- equals: function(next, data, options) {
- var name = data.name;
- var value = data.value;
- var adapter = options.adapter;
- if (data.ignoreCase) {
- value = value.toLowerCase();
- return function equalsIC(elem) {
- var attr = adapter.getAttributeValue(elem, name);
- return attr != null && attr.toLowerCase() === value && next(elem);
- };
- }
- return function equals(elem) {
- return adapter.getAttributeValue(elem, name) === value && next(elem);
- };
- },
- hyphen: function(next, data, options) {
- var name = data.name;
- var value = data.value;
- var len = value.length;
- var adapter = options.adapter;
- if (data.ignoreCase) {
- value = value.toLowerCase();
- return function hyphenIC(elem) {
- var attr = adapter.getAttributeValue(elem, name);
- return (
- attr != null &&
- (attr.length === len || attr.charAt(len) === "-") &&
- attr.substr(0, len).toLowerCase() === value &&
- next(elem)
- );
- };
- }
- return function hyphen(elem) {
- var attr = adapter.getAttributeValue(elem, name);
- return (
- attr != null &&
- attr.substr(0, len) === value &&
- (attr.length === len || attr.charAt(len) === "-") &&
- next(elem)
- );
- };
- },
- element: function(next, data, options) {
- var name = data.name;
- var value = data.value;
- var adapter = options.adapter;
- if (/\s/.test(value)) {
- return falseFunc;
- }
- value = value.replace(reChars, "\\$&");
- var pattern = "(?:^|\\s)" + value + "(?:$|\\s)",
- flags = data.ignoreCase ? "i" : "",
- regex = new RegExp(pattern, flags);
- return function element(elem) {
- var attr = adapter.getAttributeValue(elem, name);
- return attr != null && regex.test(attr) && next(elem);
- };
- },
- exists: function(next, data, options) {
- var name = data.name;
- var adapter = options.adapter;
- return function exists(elem) {
- return adapter.hasAttrib(elem, name) && next(elem);
- };
- },
- start: function(next, data, options) {
- var name = data.name;
- var value = data.value;
- var len = value.length;
- var adapter = options.adapter;
- if (len === 0) {
- return falseFunc;
- }
- if (data.ignoreCase) {
- value = value.toLowerCase();
- return function startIC(elem) {
- var attr = adapter.getAttributeValue(elem, name);
- return attr != null && attr.substr(0, len).toLowerCase() === value && next(elem);
- };
- }
- return function start(elem) {
- var attr = adapter.getAttributeValue(elem, name);
- return attr != null && attr.substr(0, len) === value && next(elem);
- };
- },
- end: function(next, data, options) {
- var name = data.name;
- var value = data.value;
- var len = -value.length;
- var adapter = options.adapter;
- if (len === 0) {
- return falseFunc;
- }
- if (data.ignoreCase) {
- value = value.toLowerCase();
- return function endIC(elem) {
- var attr = adapter.getAttributeValue(elem, name);
- return attr != null && attr.substr(len).toLowerCase() === value && next(elem);
- };
- }
- return function end(elem) {
- var attr = adapter.getAttributeValue(elem, name);
- return attr != null && attr.substr(len) === value && next(elem);
- };
- },
- any: function(next, data, options) {
- var name = data.name;
- var value = data.value;
- var adapter = options.adapter;
- if (value === "") {
- return falseFunc;
- }
- if (data.ignoreCase) {
- var regex = new RegExp(value.replace(reChars, "\\$&"), "i");
- return function anyIC(elem) {
- var attr = adapter.getAttributeValue(elem, name);
- return attr != null && regex.test(attr) && next(elem);
- };
- }
- return function any(elem) {
- var attr = adapter.getAttributeValue(elem, name);
- return attr != null && attr.indexOf(value) >= 0 && next(elem);
- };
- },
- not: function(next, data, options) {
- var name = data.name;
- var value = data.value;
- var adapter = options.adapter;
- if (value === "") {
- return function notEmpty(elem) {
- return !!adapter.getAttributeValue(elem, name) && next(elem);
- };
- } else if (data.ignoreCase) {
- value = value.toLowerCase();
- return function notIC(elem) {
- var attr = adapter.getAttributeValue(elem, name);
- return attr != null && attr.toLowerCase() !== value && next(elem);
- };
- }
- return function not(elem) {
- return adapter.getAttributeValue(elem, name) !== value && next(elem);
- };
- }
- };
- module.exports = {
- compile: function(next, data, options) {
- if (options && options.strict && (data.ignoreCase || data.action === "not")) {
- throw new Error("Unsupported attribute selector");
- }
- return attributeRules[data.action](next, data, options);
- },
- rules: attributeRules
- };
|