|
|
@@ -28,22 +28,22 @@ this.matchedRules = this.matchedRules || (() => {
|
|
|
const DEBUG = false;
|
|
|
|
|
|
class MatchedRules {
|
|
|
- constructor(doc, docStyle) {
|
|
|
+ constructor(doc, stylesheets, styles) {
|
|
|
this.doc = doc;
|
|
|
this.mediaAllInfo = createMediaInfo(MEDIA_ALL);
|
|
|
const matchedElementsCache = new Map();
|
|
|
let sheetIndex = 0;
|
|
|
- const styleElement = doc.createElement("style");
|
|
|
- doc.body.appendChild(styleElement);
|
|
|
- docStyle.stylesheets.forEach(stylesheetInfo => {
|
|
|
+ const workStyleElement = doc.createElement("style");
|
|
|
+ doc.body.appendChild(workStyleElement);
|
|
|
+ stylesheets.forEach(stylesheetInfo => {
|
|
|
const cssRules = stylesheetInfo.stylesheet.children;
|
|
|
if (cssRules) {
|
|
|
if (stylesheetInfo.mediaText && stylesheetInfo.mediaText != MEDIA_ALL) {
|
|
|
const mediaInfo = createMediaInfo(stylesheetInfo.mediaText);
|
|
|
this.mediaAllInfo.medias.set("style-" + sheetIndex + "-" + stylesheetInfo.mediaText, mediaInfo);
|
|
|
- getMatchedElementsRules(doc, cssRules, mediaInfo, sheetIndex, docStyle, matchedElementsCache, styleElement.sheet);
|
|
|
+ getMatchedElementsRules(doc, cssRules, mediaInfo, sheetIndex, styles, matchedElementsCache, workStyleElement.sheet);
|
|
|
} else {
|
|
|
- getMatchedElementsRules(doc, cssRules, this.mediaAllInfo, sheetIndex, docStyle, matchedElementsCache, styleElement.sheet);
|
|
|
+ getMatchedElementsRules(doc, cssRules, this.mediaAllInfo, sheetIndex, styles, matchedElementsCache, workStyleElement.sheet);
|
|
|
}
|
|
|
}
|
|
|
sheetIndex++;
|
|
|
@@ -59,8 +59,8 @@ this.matchedRules = this.matchedRules || (() => {
|
|
|
startTime = Date.now();
|
|
|
log(" -- STARTED computeCascade");
|
|
|
}
|
|
|
- computeCascade(this.mediaAllInfo, [], this.mediaAllInfo, styleElement.sheet);
|
|
|
- styleElement.remove();
|
|
|
+ computeCascade(this.mediaAllInfo, [], this.mediaAllInfo, workStyleElement.sheet);
|
|
|
+ workStyleElement.remove();
|
|
|
if (DEBUG) {
|
|
|
log(" -- ENDED computeCascade", Date.now() - startTime);
|
|
|
}
|
|
|
@@ -72,8 +72,8 @@ this.matchedRules = this.matchedRules || (() => {
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
- getMediaAllInfo(doc, docStyle) {
|
|
|
- return new MatchedRules(doc, docStyle).getMediaAllInfo();
|
|
|
+ getMediaAllInfo(doc, stylesheets, styles) {
|
|
|
+ return new MatchedRules(doc, stylesheets, styles).getMediaAllInfo();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
@@ -85,7 +85,7 @@ this.matchedRules = this.matchedRules || (() => {
|
|
|
return mediaInfo;
|
|
|
}
|
|
|
|
|
|
- function getMatchedElementsRules(doc, cssRules, mediaInfo, sheetIndex, docStyle, matchedElementsCache, stylesheet) {
|
|
|
+ function getMatchedElementsRules(doc, cssRules, mediaInfo, sheetIndex, styles, matchedElementsCache, workStylesheet) {
|
|
|
let mediaIndex = 0;
|
|
|
let ruleIndex = 0;
|
|
|
let startTime;
|
|
|
@@ -100,16 +100,16 @@ this.matchedRules = this.matchedRules || (() => {
|
|
|
const ruleMediaInfo = createMediaInfo(mediaText);
|
|
|
mediaInfo.medias.set("rule-" + sheetIndex + "-" + mediaIndex + "-" + mediaText, ruleMediaInfo);
|
|
|
mediaIndex++;
|
|
|
- getMatchedElementsRules(doc, cssRule.block.children, ruleMediaInfo, sheetIndex, docStyle, matchedElementsCache, stylesheet);
|
|
|
+ getMatchedElementsRules(doc, cssRule.block.children, ruleMediaInfo, sheetIndex, styles, matchedElementsCache, workStylesheet);
|
|
|
} else if (cssRule.type == "Rule") {
|
|
|
const selectors = cssRule.prelude.children.toArray();
|
|
|
const selectorsText = cssRule.prelude.children.toArray().map(selector => cssTree.generate(selector));
|
|
|
const ruleInfo = { cssRule, mediaInfo, ruleIndex, sheetIndex, matchedSelectors: new Set(), declarations: new Set(), selectors, selectorsText };
|
|
|
- if (!invalidSelector(selectorsText.join(","), stylesheet)) {
|
|
|
+ if (!invalidSelector(selectorsText.join(","), workStylesheet)) {
|
|
|
for (let selector = cssRule.prelude.children.head, selectorIndex = 0; selector; selector = selector.next, selectorIndex++) {
|
|
|
const selectorText = selectorsText[selectorIndex];
|
|
|
const selectorInfo = { selector, selectorText, ruleInfo };
|
|
|
- getMatchedElementsSelector(doc, selectorInfo, docStyle, matchedElementsCache);
|
|
|
+ getMatchedElementsSelector(doc, selectorInfo, styles, matchedElementsCache);
|
|
|
}
|
|
|
}
|
|
|
ruleIndex++;
|
|
|
@@ -121,11 +121,11 @@ this.matchedRules = this.matchedRules || (() => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- function invalidSelector(selectorText, stylesheet) {
|
|
|
+ function invalidSelector(selectorText, workStylesheet) {
|
|
|
let invalidSelector;
|
|
|
try {
|
|
|
- stylesheet.insertRule(selectorText + "{}");
|
|
|
- stylesheet.deleteRule(0);
|
|
|
+ workStylesheet.insertRule(selectorText + "{}");
|
|
|
+ workStylesheet.deleteRule(0);
|
|
|
} catch (error) {
|
|
|
if (!selectorText.match(REGEXP_VENDOR_IDENTIFIER)) {
|
|
|
invalidSelector = true;
|
|
|
@@ -134,7 +134,7 @@ this.matchedRules = this.matchedRules || (() => {
|
|
|
return invalidSelector;
|
|
|
}
|
|
|
|
|
|
- function getMatchedElementsSelector(doc, selectorInfo, docStyle, matchedElementsCache) {
|
|
|
+ function getMatchedElementsSelector(doc, selectorInfo, styles, matchedElementsCache) {
|
|
|
let selectorText;
|
|
|
const selectorData = cssTree.parse(cssTree.generate(selectorInfo.selector.data), { context: "selector" });
|
|
|
const filteredSelectorText = getFilteredSelector({ data: selectorData });
|
|
|
@@ -159,7 +159,7 @@ this.matchedRules = this.matchedRules || (() => {
|
|
|
}
|
|
|
if (matchedElements.length) {
|
|
|
if (filteredSelectorText == selectorInfo.selectorText) {
|
|
|
- matchedElements.forEach(element => addRule(element, selectorInfo, docStyle.styles));
|
|
|
+ matchedElements.forEach(element => addRule(element, selectorInfo, styles));
|
|
|
} else {
|
|
|
let pseudoSelectors = selectorInfo.ruleInfo.mediaInfo.pseudoRules.get(selectorInfo.ruleInfo.cssRule);
|
|
|
if (!pseudoSelectors) {
|
|
|
@@ -234,36 +234,37 @@ this.matchedRules = this.matchedRules || (() => {
|
|
|
elementInfo.push(selectorInfo);
|
|
|
}
|
|
|
|
|
|
- function computeCascade(mediaInfo, parentMediaInfo, mediaAllInfo, stylesheet) {
|
|
|
- mediaInfo.elements.forEach((elementInfo, element) => getDeclarationsInfo(elementInfo, stylesheet, element).forEach((declarationsInfo, property) => {
|
|
|
- if (declarationsInfo.selectorInfo.ruleInfo || mediaInfo == mediaAllInfo) {
|
|
|
- let info;
|
|
|
- if (declarationsInfo.selectorInfo.ruleInfo) {
|
|
|
- info = declarationsInfo.selectorInfo.ruleInfo;
|
|
|
- const cssRule = info.cssRule;
|
|
|
- const ascendantMedia = [mediaInfo, ...parentMediaInfo].find(media => media.rules.get(cssRule)) || mediaInfo;
|
|
|
- ascendantMedia.rules.set(cssRule, info);
|
|
|
- if (cssRule) {
|
|
|
- info.matchedSelectors.add(declarationsInfo.selectorInfo.selectorText);
|
|
|
+ function computeCascade(mediaInfo, parentMediaInfo, mediaAllInfo, workStylesheet) {
|
|
|
+ mediaInfo.elements.forEach((elementInfo/*, element*/) =>
|
|
|
+ getDeclarationsInfo(elementInfo, workStylesheet/*, element*/).forEach((declarationsInfo, property) => {
|
|
|
+ if (declarationsInfo.selectorInfo.ruleInfo || mediaInfo == mediaAllInfo) {
|
|
|
+ let info;
|
|
|
+ if (declarationsInfo.selectorInfo.ruleInfo) {
|
|
|
+ info = declarationsInfo.selectorInfo.ruleInfo;
|
|
|
+ const cssRule = info.cssRule;
|
|
|
+ const ascendantMedia = [mediaInfo, ...parentMediaInfo].find(media => media.rules.get(cssRule)) || mediaInfo;
|
|
|
+ ascendantMedia.rules.set(cssRule, info);
|
|
|
+ if (cssRule) {
|
|
|
+ info.matchedSelectors.add(declarationsInfo.selectorInfo.selectorText);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ info = declarationsInfo.selectorInfo.styleInfo;
|
|
|
+ const cssStyle = info.cssStyle;
|
|
|
+ const matchedStyleInfo = mediaAllInfo.matchedStyles.get(cssStyle);
|
|
|
+ if (!matchedStyleInfo) {
|
|
|
+ mediaAllInfo.matchedStyles.set(cssStyle, info);
|
|
|
+ }
|
|
|
}
|
|
|
- } else {
|
|
|
- info = declarationsInfo.selectorInfo.styleInfo;
|
|
|
- const cssStyle = info.cssStyle;
|
|
|
- const matchedStyleInfo = mediaAllInfo.matchedStyles.get(cssStyle);
|
|
|
- if (!matchedStyleInfo) {
|
|
|
- mediaAllInfo.matchedStyles.set(cssStyle, info);
|
|
|
+ if (!info.declarations.has(property)) {
|
|
|
+ info.declarations.add(property);
|
|
|
}
|
|
|
}
|
|
|
- if (!info.declarations.has(property)) {
|
|
|
- info.declarations.add(property);
|
|
|
- }
|
|
|
- }
|
|
|
- }));
|
|
|
+ }));
|
|
|
delete mediaInfo.elements;
|
|
|
- mediaInfo.medias.forEach(childMediaInfo => computeCascade(childMediaInfo, [mediaInfo, ...parentMediaInfo], mediaAllInfo, stylesheet));
|
|
|
+ mediaInfo.medias.forEach(childMediaInfo => computeCascade(childMediaInfo, [mediaInfo, ...parentMediaInfo], mediaAllInfo, workStylesheet));
|
|
|
}
|
|
|
|
|
|
- function getDeclarationsInfo(elementInfo, stylesheet/*, element */) {
|
|
|
+ function getDeclarationsInfo(elementInfo, workStylesheet/*, element */) {
|
|
|
const declarationsInfo = new Map();
|
|
|
elementInfo.forEach(selectorInfo => {
|
|
|
let declarations;
|
|
|
@@ -272,17 +273,17 @@ this.matchedRules = this.matchedRules || (() => {
|
|
|
} else {
|
|
|
declarations = selectorInfo.ruleInfo.cssRule.block.children;
|
|
|
}
|
|
|
- processDeclarations(declarationsInfo, declarations, selectorInfo, stylesheet);
|
|
|
+ processDeclarations(declarationsInfo, declarations, selectorInfo, workStylesheet);
|
|
|
});
|
|
|
return declarationsInfo;
|
|
|
}
|
|
|
|
|
|
- function processDeclarations(declarationsInfo, declarations, selectorInfo, stylesheet) {
|
|
|
+ function processDeclarations(declarationsInfo, declarations, selectorInfo, workStylesheet) {
|
|
|
const processedProperties = new Set();
|
|
|
for (let declaration = declarations.tail; declaration; declaration = declaration.prev) {
|
|
|
const declarationData = declaration.data;
|
|
|
const declarationText = cssTree.generate(declarationData);
|
|
|
- if (declarationData.type == "Declaration" && (declarationText.match(REGEXP_VENDOR_IDENTIFIER) || !processedProperties.has(declarationData.property)) && !invalidDeclaration(declarationText, stylesheet)) {
|
|
|
+ if (declarationData.type == "Declaration" && (declarationText.match(REGEXP_VENDOR_IDENTIFIER) || !processedProperties.has(declarationData.property)) && !invalidDeclaration(declarationText, workStylesheet)) {
|
|
|
const declarationInfo = declarationsInfo.get(declarationData);
|
|
|
if (!declarationInfo || (declarationData.important && !declarationInfo.important)) {
|
|
|
declarationsInfo.set(declarationData, { selectorInfo, important: declarationData.important });
|
|
|
@@ -292,15 +293,15 @@ this.matchedRules = this.matchedRules || (() => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- function invalidDeclaration(declarationText, stylesheet) {
|
|
|
+ function invalidDeclaration(declarationText, workStylesheet) {
|
|
|
let invalidDeclaration;
|
|
|
- stylesheet.insertRule("single-file-declaration { " + declarationText + "}");
|
|
|
- if (!stylesheet.cssRules[0].style.length) {
|
|
|
+ workStylesheet.insertRule("single-file-declaration { " + declarationText + "}");
|
|
|
+ if (!workStylesheet.cssRules[0].style.length) {
|
|
|
if (!declarationText.match(REGEXP_VENDOR_IDENTIFIER)) {
|
|
|
invalidDeclaration = true;
|
|
|
}
|
|
|
}
|
|
|
- stylesheet.deleteRule(0);
|
|
|
+ workStylesheet.deleteRule(0);
|
|
|
return invalidDeclaration;
|
|
|
}
|
|
|
|