|
|
@@ -37,6 +37,7 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
const REGEXP_FONT_FORMAT = /\.([^.?#]+)((\?|#).*?)?$/;
|
|
|
const REGEXP_FONT_FORMAT_VALUE = /format\((.*?)\)\s*,?$/;
|
|
|
const REGEXP_FONT_SRC = /(.*?)\s*,?$/;
|
|
|
+ const PSEUDO_ELEMENTS = ["::after", "::before", "::first-line", "::first-letter", ":before", ":after", ":first-line", ":first-letter", "::placeholder", "::selection", "::marker", "::cue", "::slotted", "::spelling-error", "::grammar-error"];
|
|
|
const FONT_WEIGHTS = {
|
|
|
normal: 400,
|
|
|
bold: 700
|
|
|
@@ -68,11 +69,12 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
discarded: 0
|
|
|
}
|
|
|
};
|
|
|
+ const pseudoElementsContent = Array.from(doc.querySelectorAll("style")).map(style => getPseudoElementsContent(doc, style.sheet.cssRules)).join("");
|
|
|
doc.querySelectorAll("style").forEach(style => {
|
|
|
if (style.sheet) {
|
|
|
stats.rules.processed += style.sheet.cssRules.length;
|
|
|
stats.rules.discarded += style.sheet.cssRules.length;
|
|
|
- processRules(doc, style.sheet.cssRules, fontsDetails, declaredFonts, usedFonts, secondPass);
|
|
|
+ processRules(doc, style.sheet.cssRules, fontsDetails, declaredFonts, usedFonts, pseudoElementsContent, secondPass);
|
|
|
}
|
|
|
});
|
|
|
doc.querySelectorAll("style").forEach(style => {
|
|
|
@@ -82,7 +84,7 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
});
|
|
|
doc.querySelectorAll("[style]").forEach(element => {
|
|
|
if (element.style.fontFamily) {
|
|
|
- const fontFamilyNames = element.style.fontFamily.split(",").map(fontFamilyName => getFontFamilyName(fontFamilyName));
|
|
|
+ const fontFamilyNames = element.style.fontFamily.split(",").map(fontFamilyName => removeQuotes(fontFamilyName));
|
|
|
usedFonts.push(fontFamilyNames);
|
|
|
}
|
|
|
});
|
|
|
@@ -106,23 +108,39 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- function processRules(doc, rules, fontsDetails, declaredFonts, usedFonts, secondPass) {
|
|
|
+ function getPseudoElementsContent(doc, rules) {
|
|
|
+ if (rules) {
|
|
|
+ return Array.from(rules).map(rule => {
|
|
|
+ if (rule.type == CSSRule.MEDIA_RULE) {
|
|
|
+ return getPseudoElementsContent(doc, rule.cssRules);
|
|
|
+ } else if (rule.type == CSSRule.STYLE_RULE && testPseudoElements(rule.selectorText)) {
|
|
|
+ let content = rule.style.getPropertyValue("content");
|
|
|
+ content = content && removeQuotes(content);
|
|
|
+ return content;
|
|
|
+ }
|
|
|
+ }).join("");
|
|
|
+ } else {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function processRules(doc, rules, fontsDetails, declaredFonts, usedFonts, pseudoElementsContent, secondPass) {
|
|
|
if (rules) {
|
|
|
Array.from(rules).forEach(rule => {
|
|
|
if (rule.type == CSSRule.MEDIA_RULE) {
|
|
|
- processRules(doc, rule.cssRules, fontsDetails, declaredFonts, usedFonts, secondPass);
|
|
|
+ processRules(doc, rule.cssRules, fontsDetails, declaredFonts, usedFonts, pseudoElementsContent, secondPass);
|
|
|
} else if (rule.type == CSSRule.STYLE_RULE) {
|
|
|
if (rule.style && rule.style.fontFamily) {
|
|
|
- const fontFamilyNames = rule.style.fontFamily.split(",").map(fontFamilyName => getFontFamilyName(fontFamilyName));
|
|
|
+ const fontFamilyNames = rule.style.fontFamily.split(",").map(fontFamilyName => removeQuotes(fontFamilyName));
|
|
|
usedFonts.push(fontFamilyNames);
|
|
|
}
|
|
|
} else {
|
|
|
if (rule.type == CSSRule.FONT_FACE_RULE && rule.style) {
|
|
|
- const fontFamilyName = getFontFamilyName(rule.style.getPropertyValue("font-family"));
|
|
|
+ const fontFamilyName = removeQuotes(rule.style.getPropertyValue("font-family"));
|
|
|
if (fontFamilyName) {
|
|
|
declaredFonts.add(fontFamilyName);
|
|
|
}
|
|
|
- if (secondPass || testUnicodeRange(doc, rule)) {
|
|
|
+ if (secondPass || testUnicodeRange(doc.body.innerText + pseudoElementsContent, rule)) {
|
|
|
const fontKey = getFontKey(rule.style);
|
|
|
let fontInfo = fontsDetails.get(fontKey);
|
|
|
if (!fontInfo) {
|
|
|
@@ -247,7 +265,7 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
stylesheetContent += "@media " + Array.prototype.join.call(rule.media, ",") + "{";
|
|
|
stylesheetContent += deleteUnusedFonts(doc, rule.cssRules, unusedFonts);
|
|
|
stylesheetContent += "}";
|
|
|
- } else if (rule.type != CSSRule.FONT_FACE_RULE || (rule.type == CSSRule.FONT_FACE_RULE && rule.style && fontFamilyName && !unusedFonts.includes(getFontFamilyName(fontFamilyName)))) {
|
|
|
+ } else if (rule.type != CSSRule.FONT_FACE_RULE || (rule.type == CSSRule.FONT_FACE_RULE && rule.style && fontFamilyName && !unusedFonts.includes(removeQuotes(fontFamilyName)))) {
|
|
|
stylesheetContent += rule.cssText;
|
|
|
}
|
|
|
});
|
|
|
@@ -255,9 +273,8 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
return stylesheetContent;
|
|
|
}
|
|
|
|
|
|
- function testUnicodeRange(doc, rule) {
|
|
|
+ function testUnicodeRange(docContent, rule) {
|
|
|
const unicodeRange = rule.style.getPropertyValue("unicode-range");
|
|
|
- const docContent = doc.body.innerText;
|
|
|
if (unicodeRange) {
|
|
|
const unicodeRanges = unicodeRange.split(REGEXP_COMMA);
|
|
|
const result = unicodeRanges.filter(rangeValue => {
|
|
|
@@ -286,6 +303,18 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ function testPseudoElements(selectorText) {
|
|
|
+ let indexSelector = 0, found;
|
|
|
+ selectorText = selectorText.toLowerCase();
|
|
|
+ while (indexSelector < PSEUDO_ELEMENTS.length && !found) {
|
|
|
+ found = selectorText.includes(PSEUDO_ELEMENTS[indexSelector]);
|
|
|
+ if (!found) {
|
|
|
+ indexSelector++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return found;
|
|
|
+ }
|
|
|
+
|
|
|
function transformRange(range) {
|
|
|
range = range.replace(REGEXP_STARTS_U_PLUS, "");
|
|
|
while (range.length < 6) {
|
|
|
@@ -296,7 +325,7 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
|
|
|
function getFontKey(style) {
|
|
|
return JSON.stringify([
|
|
|
- getFontFamilyName(style.getPropertyValue("font-family")),
|
|
|
+ removeQuotes(style.getPropertyValue("font-family")),
|
|
|
getFontWeight(style.getPropertyValue("font-weight")),
|
|
|
style.getPropertyValue("font-style"),
|
|
|
style.getPropertyValue("unicode-range"),
|
|
|
@@ -307,14 +336,14 @@ this.fontsMinifier = this.fontsMinifier || (() => {
|
|
|
]);
|
|
|
}
|
|
|
|
|
|
- function getFontFamilyName(fontFamilyName) {
|
|
|
- fontFamilyName = fontFamilyName.toLowerCase().trim();
|
|
|
- if (fontFamilyName.match(REGEXP_SIMPLE_QUOTES_STRING)) {
|
|
|
- fontFamilyName = fontFamilyName.replace(REGEXP_SIMPLE_QUOTES_STRING, "$1");
|
|
|
+ function removeQuotes(string) {
|
|
|
+ string = string.toLowerCase().trim();
|
|
|
+ if (string.match(REGEXP_SIMPLE_QUOTES_STRING)) {
|
|
|
+ string = string.replace(REGEXP_SIMPLE_QUOTES_STRING, "$1");
|
|
|
} else {
|
|
|
- fontFamilyName = fontFamilyName.replace(REGEXP_DOUBLE_QUOTES_STRING, "$1");
|
|
|
+ string = string.replace(REGEXP_DOUBLE_QUOTES_STRING, "$1");
|
|
|
}
|
|
|
- return fontFamilyName.trim();
|
|
|
+ return string.trim();
|
|
|
}
|
|
|
|
|
|
function getFontWeight(weight) {
|