|
|
@@ -30,14 +30,15 @@ this.RulesMatcher = this.RulesMatcher || (() => {
|
|
|
this.doc = doc;
|
|
|
this.mediaAllInfo = createMediaInfo(MEDIA_ALL);
|
|
|
const matchedElementsCache = new Map();
|
|
|
+ const unmatchedSelectorsCache = new Set();
|
|
|
doc.querySelectorAll("style").forEach((styleElement, styleIndex) => {
|
|
|
if (styleElement.sheet) {
|
|
|
if (styleElement.media && styleElement.media != MEDIA_ALL) {
|
|
|
const mediaInfo = createMediaInfo(styleElement.media);
|
|
|
this.mediaAllInfo.medias.set(styleElement.media, mediaInfo);
|
|
|
- getMatchedElementsRules(doc, styleElement.sheet.cssRules, mediaInfo, styleIndex, matchedElementsCache);
|
|
|
+ getMatchedElementsRules(doc, styleElement.sheet.cssRules, mediaInfo, styleIndex, matchedElementsCache, unmatchedSelectorsCache);
|
|
|
} else {
|
|
|
- getMatchedElementsRules(doc, styleElement.sheet.cssRules, this.mediaAllInfo, styleIndex, matchedElementsCache);
|
|
|
+ getMatchedElementsRules(doc, styleElement.sheet.cssRules, this.mediaAllInfo, styleIndex, matchedElementsCache, unmatchedSelectorsCache);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
@@ -60,18 +61,18 @@ this.RulesMatcher = this.RulesMatcher || (() => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- function getMatchedElementsRules(doc, cssRules, mediaInfo, sheetIndex, matchedElementsCache) {
|
|
|
+ function getMatchedElementsRules(doc, cssRules, mediaInfo, sheetIndex, matchedElementsCache, unmatchedSelectorsCache) {
|
|
|
Array.from(cssRules).forEach((cssRule, ruleIndex) => {
|
|
|
if (cssRule.type == CSSRule.MEDIA_RULE) {
|
|
|
const ruleMediaInfo = createMediaInfo(cssRule.media);
|
|
|
mediaInfo.medias.set(cssRule.media, ruleMediaInfo);
|
|
|
- getMatchedElementsRules(doc, cssRule.cssRules, ruleMediaInfo, sheetIndex, matchedElementsCache);
|
|
|
+ getMatchedElementsRules(doc, cssRule.cssRules, ruleMediaInfo, sheetIndex, matchedElementsCache, unmatchedSelectorsCache);
|
|
|
} else if (cssRule.type == CSSRule.STYLE_RULE) {
|
|
|
if (cssRule.selectorText) {
|
|
|
try {
|
|
|
let selectors = cssWhat.parse(cssRule.selectorText);
|
|
|
const selectorsText = selectors.map(selector => cssWhat.stringify([selector]));
|
|
|
- selectors.forEach(selector => getMatchedElementsSelector(doc, cssRule, selector, selectorsText, mediaInfo, ruleIndex, sheetIndex, matchedElementsCache));
|
|
|
+ selectors.forEach(selector => getMatchedElementsSelector(doc, cssRule, selector, selectorsText, mediaInfo, ruleIndex, sheetIndex, matchedElementsCache, unmatchedSelectorsCache));
|
|
|
} catch (error) {
|
|
|
/* ignored */
|
|
|
}
|
|
|
@@ -80,11 +81,18 @@ this.RulesMatcher = this.RulesMatcher || (() => {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- function getMatchedElementsSelector(doc, cssRule, selector, selectorsText, mediaInfo, ruleIndex, sheetIndex, matchedElementsCache) {
|
|
|
+ function getMatchedElementsSelector(doc, cssRule, selector, selectorsText, mediaInfo, ruleIndex, sheetIndex, matchedElementsCache, unmatchedSelectorsCache) {
|
|
|
const selectorText = cssWhat.stringify([selector]);
|
|
|
let matchedElements = matchedElementsCache.get(selectorText);
|
|
|
if (!matchedElements) {
|
|
|
- matchedElements = doc.querySelectorAll(selectorText);
|
|
|
+ if (unmatchedSelectorsCache.has(selectorText)) {
|
|
|
+ matchedElements = [];
|
|
|
+ } else {
|
|
|
+ matchedElements = doc.querySelectorAll(selectorText);
|
|
|
+ if (!matchedElements.length) {
|
|
|
+ unmatchedSelectorsCache.add(selectorText);
|
|
|
+ }
|
|
|
+ }
|
|
|
matchedElementsCache.set(selectorText, matchedElements);
|
|
|
}
|
|
|
if (matchedElements.length) {
|