|
|
@@ -24,6 +24,16 @@ this.RulesMatcher = this.RulesMatcher || (() => {
|
|
|
|
|
|
const MEDIA_ALL = "all";
|
|
|
const IGNORED_PSEUDO_CLASSES = [":focus", ":focus-within", ":hover", ":link", ":visited", ":active"];
|
|
|
+ const SELECTOR_TOKEN_TYPE_TAG = "tag";
|
|
|
+ const SELECTOR_TOKEN_TYPE_ATTRIBUTE = "attribute";
|
|
|
+ const SELECTOR_TOKEN_TYPE_PSEUDO = "pseudo";
|
|
|
+ const SELECTOR_TOKEN_TYPE_PSEUDO_ELEMENT = "pseudo-element";
|
|
|
+ const SELECTOR_TOKEN_NAME_ID = "id";
|
|
|
+ const SELECTOR_TOKEN_NAME_CLASS = "class";
|
|
|
+ const SELECTOR_TOKEN_NAME_NOT = "not";
|
|
|
+ const SELECTOR_TOKEN_ACTION_EQUALS = "equals";
|
|
|
+ const SELECTOR_TOKEN_ACTION_ELEMENT = "element";
|
|
|
+ const SELECTOR_TOKEN_VALUE_STAR = "*";
|
|
|
|
|
|
class RulesMatcher {
|
|
|
constructor(doc) {
|
|
|
@@ -61,11 +71,13 @@ this.RulesMatcher = this.RulesMatcher || (() => {
|
|
|
|
|
|
function getMatchedElementsRules(doc, cssRules, mediaInfo, sheetIndex) {
|
|
|
Array.from(cssRules).forEach((cssRule, ruleIndex) => {
|
|
|
- if (cssRule.type == CSSRule.MEDIA_RULE) {
|
|
|
- const ruleMediaInfo = createMediaInfo(cssRule.media);
|
|
|
- mediaInfo.medias.set(cssRule.media, ruleMediaInfo);
|
|
|
+ const cssRuleType = cssRule.type;
|
|
|
+ if (cssRuleType == CSSRule.MEDIA_RULE) {
|
|
|
+ const cssRuleMedia = cssRule.media;
|
|
|
+ const ruleMediaInfo = createMediaInfo(cssRuleMedia);
|
|
|
+ mediaInfo.medias.set(cssRuleMedia, ruleMediaInfo);
|
|
|
getMatchedElementsRules(doc, cssRule.cssRules, ruleMediaInfo, sheetIndex);
|
|
|
- } else if (cssRule.type == CSSRule.STYLE_RULE) {
|
|
|
+ } else if (cssRuleType == CSSRule.STYLE_RULE) {
|
|
|
const selectorText = cssRule.selectorText;
|
|
|
if (selectorText) {
|
|
|
let selectors;
|
|
|
@@ -110,14 +122,12 @@ this.RulesMatcher = this.RulesMatcher || (() => {
|
|
|
}
|
|
|
|
|
|
function getInfo(element, cssRule, selector, mediaInfo, ruleIndex, sheetIndex) {
|
|
|
- let elementInfo;
|
|
|
- if (mediaInfo.elements.has(element)) {
|
|
|
- elementInfo = mediaInfo.elements.get(element);
|
|
|
- } else {
|
|
|
+ let elementInfo = mediaInfo.elements.get(element);
|
|
|
+ if (!elementInfo) {
|
|
|
elementInfo = [];
|
|
|
- const elementStyle = element.getAttribute("style");
|
|
|
- if (elementStyle) {
|
|
|
- elementInfo.push({ cssStyle: element.style });
|
|
|
+ const elementStyle = element.style;
|
|
|
+ if (elementStyle.length) {
|
|
|
+ elementInfo.push({ cssStyle: elementStyle });
|
|
|
}
|
|
|
mediaInfo.elements.set(element, elementInfo);
|
|
|
}
|
|
|
@@ -174,17 +184,18 @@ this.RulesMatcher = this.RulesMatcher || (() => {
|
|
|
stylesInfo.forEach(styleInfo => {
|
|
|
const important = cssStyle.getPropertyPriority(styleInfo.name);
|
|
|
const styleValue = cssStyle.getPropertyValue(styleInfo.name) + (important && "!" + important);
|
|
|
- elementStylesInfo.set(styleInfo.name, { styleValue, cssStyle: ruleInfo.cssStyle, important });
|
|
|
+ elementStylesInfo.set(styleInfo.name, { styleValue, cssStyle, important });
|
|
|
});
|
|
|
} else {
|
|
|
- const cssStyle = ruleInfo.cssRule.style;
|
|
|
+ const cssRule = ruleInfo.cssRule;
|
|
|
+ const cssStyle = cssRule.style;
|
|
|
const stylesInfo = parseCss.parseAListOfDeclarations(cssStyle.cssText);
|
|
|
stylesInfo.forEach(styleInfo => {
|
|
|
const important = cssStyle.getPropertyPriority(styleInfo.name);
|
|
|
const styleValue = cssStyle.getPropertyValue(styleInfo.name) + (important && "!" + important);
|
|
|
let elementStyleInfo = elementStylesInfo.get(styleInfo.name);
|
|
|
if (!elementStyleInfo || (important && !elementStyleInfo.important)) {
|
|
|
- elementStylesInfo.set(styleInfo.name, { styleValue, cssRule: ruleInfo.cssRule, selectorText: ruleInfo.selectorText, selectorsText: ruleInfo.selectorsText, important });
|
|
|
+ elementStylesInfo.set(styleInfo.name, { styleValue, cssRule, selectorText: ruleInfo.selectorText, selectorsText: ruleInfo.selectorsText, important });
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
@@ -210,15 +221,15 @@ this.RulesMatcher = this.RulesMatcher || (() => {
|
|
|
|
|
|
function computeSpecificity(selector, specificity = { a: 0, b: 0, c: 0 }) {
|
|
|
selector.forEach(token => {
|
|
|
- if (token.expandedSelector && token.type == "attribute" && token.name === "id" && token.action === "equals") {
|
|
|
+ if (token.expandedSelector && token.type == SELECTOR_TOKEN_TYPE_ATTRIBUTE && token.name == SELECTOR_TOKEN_NAME_ID && token.action == SELECTOR_TOKEN_ACTION_EQUALS) {
|
|
|
specificity.a++;
|
|
|
}
|
|
|
- if ((!token.expandedSelector && token.type == "attribute") ||
|
|
|
- (token.expandedSelector && token.type == "attribute" && token.name === "class" && token.action === "element") ||
|
|
|
- (token.type == "pseudo" && token.name != "not")) {
|
|
|
+ if ((!token.expandedSelector && token.type == SELECTOR_TOKEN_TYPE_ATTRIBUTE) ||
|
|
|
+ (token.expandedSelector && token.type == SELECTOR_TOKEN_TYPE_ATTRIBUTE && token.name == SELECTOR_TOKEN_NAME_CLASS && token.action == SELECTOR_TOKEN_ACTION_ELEMENT) ||
|
|
|
+ (token.type == SELECTOR_TOKEN_TYPE_PSEUDO && token.name != SELECTOR_TOKEN_NAME_NOT)) {
|
|
|
specificity.b++;
|
|
|
}
|
|
|
- if ((token.type == "tag" && token.value != "*") || (token.type == "pseudo-element")) {
|
|
|
+ if ((token.type == SELECTOR_TOKEN_TYPE_TAG && token.value != SELECTOR_TOKEN_VALUE_STAR) || (token.type == SELECTOR_TOKEN_TYPE_PSEUDO_ELEMENT)) {
|
|
|
specificity.c++;
|
|
|
}
|
|
|
if (token.data) {
|