/**
* Module dependencies.
*/
var parser = require('slick').parse;
/**
* Module exports.
*/
module.exports = exports = Selector;
/**
* CSS selector constructor.
*
* @param {String} selector text
* @param {Array} optionally, precalculated specificity
* @api public
*/
function Selector (text, spec) {
this.text = text;
this.spec = spec;
}
/**
* Get parsed selector.
*
* @api public
*/
Selector.prototype.parsed = function () {
if (!this.tokens) this.tokens = parse(this.text);
return this.tokens;
};
/**
* Lazy specificity getter
*
* @api public
*/
Selector.prototype.specificity = function () {
if (!this.spec) this.spec = specificity(this.text, this.parsed());
return this.spec;
function specificity (text, parsed) {
var expressions = parsed || parse(text)
, spec = [0, 0, 0, 0]
, nots = []
for (var i = 0; i < expressions.length; i++) {
var expression = expressions[i]
, pseudos = expression.pseudos
// id awards a point in the second column
if (expression.id) spec[1]++;
// classes and attributes award a point each in the third column
if (expression.attributes) spec[2] += expression.attributes.length;
if (expression.classList) spec[2] += expression.classList.length;
// tag awards a point in the fourth column
if (expression.tag && expression.tag !== '*') spec[3]++;
// pseudos award a point each in the fourth column
Iif (pseudos) {
spec[3] += pseudos.length;
for (var p = 0; p < pseudos.length; p++) {
if (pseudos[p].key === 'not'){
nots.push(pseudos[p].value);
spec[3]--;
}
}
}
}
for (var ii = nots.length; ii--;) {
var not = specificity(nots[ii]);
for (var jj = 4; jj--;) spec[jj] += not[jj];
}
return spec;
}
}
/**
* Parses a selector and returns the tokens.
*
* @param {String} selector
* @api private.
*/
function parse (text) {
try {
return parser(text)[0];
} catch (e) {
return [];
}
}
|