You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
5.8 KiB
190 lines
5.8 KiB
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 |
|
};
|
|
|