98 lines
2.1 KiB
JavaScript
98 lines
2.1 KiB
JavaScript
'use strict';
|
|
|
|
var parser = require('slick/parser');
|
|
|
|
module.exports = exports = Selector;
|
|
|
|
/**
|
|
* CSS selector constructor.
|
|
*
|
|
* @param {String} selector text
|
|
* @param {Array} optionally, precalculated specificity
|
|
* @api public
|
|
*/
|
|
|
|
function Selector(text, styleAttribute) {
|
|
this.text = text;
|
|
this.spec = undefined;
|
|
this.styleAttribute = styleAttribute || false;
|
|
}
|
|
|
|
/**
|
|
* 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() {
|
|
var styleAttribute = this.styleAttribute;
|
|
if (!this.spec) { this.spec = specificity(this.text, this.parsed()); }
|
|
return this.spec;
|
|
|
|
function specificity(text, parsed) {
|
|
var expressions = parsed || parse(text);
|
|
var spec = [styleAttribute ? 1 : 0, 0, 0, 0];
|
|
var nots = [];
|
|
|
|
for (var i = 0; i < expressions.length; i++) {
|
|
var expression = expressions[i];
|
|
var 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
|
|
if (pseudos) {
|
|
spec[3] += pseudos.length;
|
|
|
|
for (var p = 0; p < pseudos.length; p++) {
|
|
if (pseudos[p].name === '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 [];
|
|
}
|
|
}
|