PluginProbe ʕ •ᴥ•ʔ
SiteOrigin CSS / 1.5.10
SiteOrigin CSS v1.5.10
1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.10 1.5.11 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 trunk 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2.0
so-css / js / specificity.js
so-css / js Last commit date
URI.js 9 years ago URI.min.js 6 years ago css.js 4 years ago css.min.js 4 years ago csslint.js 9 years ago csslint.min.js 6 years ago editor.js 2 years ago editor.min.js 2 years ago inspector.js 4 years ago inspector.min.js 4 years ago jquery.sizes.js 11 years ago jquery.sizes.min.js 6 years ago specificity.js 11 years ago specificity.min.js 6 years ago
specificity.js
141 lines
1 /**
2 * Calculates the specificity of CSS selectors
3 * https://github.com/keeganstreet/specificity - licensed under MIT.
4 *
5 * Returns an array of objects with the following properties:
6 * - selector: the input
7 * - specificity: e.g. 0,1,0,0
8 * - parts: array with details about each part of the selector that counts towards the specificity
9 */
10 var SPECIFICITY = (function() {
11 var calculate,
12 calculateSingle;
13
14 calculate = function(input) {
15 var selectors,
16 selector,
17 i,
18 len,
19 results = [];
20
21 // Separate input by commas
22 selectors = input.split(',');
23
24 for (i = 0, len = selectors.length; i < len; i += 1) {
25 selector = selectors[i];
26 if (selector.length > 0) {
27 results.push(calculateSingle(selector));
28 }
29 }
30
31 return results;
32 };
33
34 // Calculate the specificity for a selector by dividing it into simple selectors and counting them
35 calculateSingle = function(input) {
36 var selector = input,
37 findMatch,
38 typeCount = {
39 'a': 0,
40 'b': 0,
41 'c': 0
42 },
43 parts = [],
44 // The following regular expressions assume that selectors matching the preceding regular expressions have been removed
45 attributeRegex = /(\[[^\]]+\])/g,
46 idRegex = /(#[^\s\+>~\.\[:]+)/g,
47 classRegex = /(\.[^\s\+>~\.\[:]+)/g,
48 pseudoElementRegex = /(::[^\s\+>~\.\[:]+|:first-line|:first-letter|:before|:after)/gi,
49 // A regex for pseudo classes with brackets - :nth-child(), :nth-last-child(), :nth-of-type(), :nth-last-type(), :lang()
50 pseudoClassWithBracketsRegex = /(:[\w-]+\([^\)]*\))/gi,
51 // A regex for other pseudo classes, which don't have brackets
52 pseudoClassRegex = /(:[^\s\+>~\.\[:]+)/g,
53 elementRegex = /([^\s\+>~\.\[:]+)/g;
54
55 // Find matches for a regular expression in a string and push their details to parts
56 // Type is "a" for IDs, "b" for classes, attributes and pseudo-classes and "c" for elements and pseudo-elements
57 findMatch = function(regex, type) {
58 var matches, i, len, match, index, length;
59 if (regex.test(selector)) {
60 matches = selector.match(regex);
61 for (i = 0, len = matches.length; i < len; i += 1) {
62 typeCount[type] += 1;
63 match = matches[i];
64 index = selector.indexOf(match);
65 length = match.length;
66 parts.push({
67 selector: match,
68 type: type,
69 index: index,
70 length: length
71 });
72 // Replace this simple selector with whitespace so it won't be counted in further simple selectors
73 selector = selector.replace(match, Array(length + 1).join(' '));
74 }
75 }
76 };
77
78 // Remove the negation psuedo-class (:not) but leave its argument because specificity is calculated on its argument
79 (function() {
80 var regex = /:not\(([^\)]*)\)/g;
81 if (regex.test(selector)) {
82 selector = selector.replace(regex, ' $1 ');
83 }
84 }());
85
86 // Remove anything after a left brace in case a user has pasted in a rule, not just a selector
87 (function() {
88 var regex = /{[^]*/gm,
89 matches, i, len, match;
90 if (regex.test(selector)) {
91 matches = selector.match(regex);
92 for (i = 0, len = matches.length; i < len; i += 1) {
93 match = matches[i];
94 selector = selector.replace(match, Array(match.length + 1).join(' '));
95 }
96 }
97 }());
98
99 // Add attribute selectors to parts collection (type b)
100 findMatch(attributeRegex, 'b');
101
102 // Add ID selectors to parts collection (type a)
103 findMatch(idRegex, 'a');
104
105 // Add class selectors to parts collection (type b)
106 findMatch(classRegex, 'b');
107
108 // Add pseudo-element selectors to parts collection (type c)
109 findMatch(pseudoElementRegex, 'c');
110
111 // Add pseudo-class selectors to parts collection (type b)
112 findMatch(pseudoClassWithBracketsRegex, 'b');
113 findMatch(pseudoClassRegex, 'b');
114
115 // Remove universal selector and separator characters
116 selector = selector.replace(/[\*\s\+>~]/g, ' ');
117
118 // Remove any stray dots or hashes which aren't attached to words
119 // These may be present if the user is live-editing this selector
120 selector = selector.replace(/[#\.]/g, ' ');
121
122 // The only things left should be element selectors (type c)
123 findMatch(elementRegex, 'c');
124
125 // Order the parts in the order they appear in the original selector
126 // This is neater for external apps to deal with
127 parts.sort(function(a, b) {
128 return a.index - b.index;
129 });
130
131 return {
132 selector: input,
133 specificity: '0,' + typeCount.a.toString() + ',' + typeCount.b.toString() + ',' + typeCount.c.toString(),
134 parts: parts
135 };
136 };
137
138 return {
139 calculate: calculate
140 };
141 }());