|
|
@@ -33,6 +33,12 @@ this.docHelper = this.docHelper || (() => {
|
|
|
const MASK_TAGNAME = "singlefile-mask";
|
|
|
const BACKDROP_THRESHOLD_SIZE = .95;
|
|
|
const BACKDROP_THRESHOLD_ZINDEX = 999;
|
|
|
+ const REGEXP_SIMPLE_QUOTES_STRING = /^'(.*?)'$/;
|
|
|
+ const REGEXP_DOUBLE_QUOTES_STRING = /^"(.*?)"$/;
|
|
|
+ const FONT_WEIGHTS = {
|
|
|
+ normal: "400",
|
|
|
+ bold: "700"
|
|
|
+ };
|
|
|
|
|
|
return {
|
|
|
preProcessDoc,
|
|
|
@@ -56,37 +62,61 @@ this.docHelper = this.docHelper || (() => {
|
|
|
element.parentElement.replaceChild(disabledNoscriptElement, element);
|
|
|
});
|
|
|
doc.head.querySelectorAll("*:not(base):not(link):not(meta):not(noscript):not(script):not(style):not(template):not(title)").forEach(element => element.hidden = true);
|
|
|
- if (options.removeHiddenElements) {
|
|
|
- const markerRemovedContent = removedContentAttributeName(options.sessionId);
|
|
|
- let ignoredTags = JSON.parse(JSON.stringify(IGNORED_REMOVED_TAG_NAMES));
|
|
|
- if (!options.removeScripts) {
|
|
|
- ignoredTags = ignoredTags.concat("SCRIPT");
|
|
|
- }
|
|
|
- if (win) {
|
|
|
- markHiddenCandidates(win, doc.body, false, markerRemovedContent, new Set(), ignoredTags);
|
|
|
- markHiddenElements(win, doc.body, markerRemovedContent);
|
|
|
- markBackdropBackground(doc, win, markerRemovedContent);
|
|
|
- }
|
|
|
- }
|
|
|
- if (win && options.compressHTML) {
|
|
|
- doc.querySelectorAll("*").forEach(element => {
|
|
|
- const style = win.getComputedStyle(element);
|
|
|
- if (style && style.whiteSpace.startsWith("pre")) {
|
|
|
- element.setAttribute(preservedSpaceAttributeName(options.sessionId), "");
|
|
|
+ let canvasData, imageData, usedFonts;
|
|
|
+ if (win) {
|
|
|
+ canvasData = getCanvasData(doc, win);
|
|
|
+ imageData = getImageData(doc, win, options);
|
|
|
+ if (options.removeHiddenElements || options.removeAlternativeFonts || options.compressHTML) {
|
|
|
+ const styles = getStyles(win, doc.body);
|
|
|
+ if (options.removeHiddenElements) {
|
|
|
+ const markerRemovedContent = removedContentAttributeName(options.sessionId);
|
|
|
+ let ignoredTags = JSON.parse(JSON.stringify(IGNORED_REMOVED_TAG_NAMES));
|
|
|
+ if (!options.removeScripts) {
|
|
|
+ ignoredTags = ignoredTags.concat("SCRIPT");
|
|
|
+ }
|
|
|
+ markHiddenCandidates(win, doc.body, styles, false, markerRemovedContent, new Set(), ignoredTags);
|
|
|
+ markHiddenElements(win, doc.body, styles, markerRemovedContent);
|
|
|
+ markBackdropBackground(doc, win, markerRemovedContent);
|
|
|
}
|
|
|
- });
|
|
|
+ if (options.removeAlternativeFonts) {
|
|
|
+ usedFonts = getUsedFonts(styles);
|
|
|
+ }
|
|
|
+ if (options.compressHTML) {
|
|
|
+ styles.forEach((style, element) => {
|
|
|
+ if (style.whiteSpace.startsWith("pre")) {
|
|
|
+ element.setAttribute(preservedSpaceAttributeName(options.sessionId), "");
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
retrieveInputValues(doc, options);
|
|
|
return {
|
|
|
- canvasData: win && getCanvasData(doc, win),
|
|
|
+ canvasData,
|
|
|
fontsData: getFontsData(doc),
|
|
|
stylesheetContents: getStylesheetContents(doc),
|
|
|
responsiveImageData: getResponsiveImageData(doc, options),
|
|
|
- imageData: win && getImageData(doc, win, options),
|
|
|
- postersData: getPostersData(doc)
|
|
|
+ imageData,
|
|
|
+ postersData: getPostersData(doc),
|
|
|
+ usedFonts
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+ function getUsedFonts(styles) {
|
|
|
+ const usedFonts = new Set();
|
|
|
+ styles.forEach(style => {
|
|
|
+ const fontFamilyNames = style.fontFamily.split(",");
|
|
|
+ fontFamilyNames.forEach(fontFamilyName => {
|
|
|
+ style.fontFamily = removeQuotes(fontFamilyName);
|
|
|
+ usedFonts.add(getFontKey(style));
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return Array.from(usedFonts).map(key => {
|
|
|
+ const [fontFamily, fontWeight, fontStyle, fontVariant] = JSON.parse(key);
|
|
|
+ return { fontFamily, fontWeight, fontStyle, fontVariant };
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
function markBackdropBackground(doc, win, markerRemovedContent) {
|
|
|
const threshold = BACKDROP_THRESHOLD_SIZE;
|
|
|
let elements = getCandidateElements();
|
|
|
@@ -106,9 +136,28 @@ this.docHelper = this.docHelper || (() => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- function markHiddenCandidates(win, element, elementHidden, markerRemovedContent, removedCandidates, ignoredTags) {
|
|
|
+ function getStyles(win, element, styles = new Map()) {
|
|
|
const elements = Array.from(element.childNodes).filter(node => node instanceof win.HTMLElement);
|
|
|
- elements.forEach(element => markHiddenCandidates(win, element, elementHidden || testHiddenElement(win, element), markerRemovedContent, removedCandidates, ignoredTags));
|
|
|
+ elements.forEach(element => {
|
|
|
+ getStyles(win, element, styles);
|
|
|
+ const computedStyle = win.getComputedStyle(element);
|
|
|
+ styles.set(element, {
|
|
|
+ display: computedStyle.display,
|
|
|
+ opacity: computedStyle.opacity,
|
|
|
+ visibility: computedStyle.visibility,
|
|
|
+ fontFamily: computedStyle.fontFamily,
|
|
|
+ fontWeight: getFontWeight(computedStyle.fontWeight),
|
|
|
+ fontStyle: computedStyle.fontStyle || "normal",
|
|
|
+ fontVariant: computedStyle.fontVariant || "normal",
|
|
|
+ whiteSpace: computedStyle.whiteSpace
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return styles;
|
|
|
+ }
|
|
|
+
|
|
|
+ function markHiddenCandidates(win, element, styles, elementHidden, markerRemovedContent, removedCandidates, ignoredTags) {
|
|
|
+ const elements = Array.from(element.childNodes).filter(node => node instanceof win.HTMLElement);
|
|
|
+ elements.forEach(element => markHiddenCandidates(win, element, styles, elementHidden || testHiddenElement(element, styles.get(element)), markerRemovedContent, removedCandidates, ignoredTags));
|
|
|
if (elementHidden && !ignoredTags.includes(element.tagName)) {
|
|
|
if (elements.length) {
|
|
|
if (!elements.find(element => !removedCandidates.has(element))) {
|
|
|
@@ -121,28 +170,26 @@ this.docHelper = this.docHelper || (() => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- function markHiddenElements(win, element, markerRemovedContent) {
|
|
|
+ function markHiddenElements(win, element, styles, markerRemovedContent) {
|
|
|
const elements = Array.from(element.childNodes).filter(node => node.nodeType == win.Node.ELEMENT_NODE);
|
|
|
elements.forEach(element => markHiddenElements(win, element, markerRemovedContent));
|
|
|
if (element.parentElement.getAttribute(markerRemovedContent) != "") {
|
|
|
element.removeAttribute(markerRemovedContent);
|
|
|
+ } else {
|
|
|
+ styles.delete(element);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- function testHiddenElement(win, element) {
|
|
|
+ function testHiddenElement(element, style) {
|
|
|
let hidden = element.hidden;
|
|
|
- if (!hidden) {
|
|
|
- const style = win.getComputedStyle(element);
|
|
|
- if (style) {
|
|
|
- hidden = style.display == "none";
|
|
|
- if (!hidden && (style.opacity == "0" || style.visibility == "hidden")) {
|
|
|
- const boundingRect = element.getBoundingClientRect();
|
|
|
- hidden = !boundingRect.width && !boundingRect.height;
|
|
|
- }
|
|
|
+ if (!hidden && style) {
|
|
|
+ hidden = style.display == "none";
|
|
|
+ if (!hidden && (style.opacity == "0" || style.visibility == "hidden")) {
|
|
|
+ const boundingRect = element.getBoundingClientRect();
|
|
|
+ hidden = !boundingRect.width && !boundingRect.height;
|
|
|
}
|
|
|
}
|
|
|
- hidden = Boolean(hidden);
|
|
|
- return hidden;
|
|
|
+ return Boolean(hidden);
|
|
|
}
|
|
|
|
|
|
function postProcessDoc(doc, options) {
|
|
|
@@ -381,4 +428,27 @@ this.docHelper = this.docHelper || (() => {
|
|
|
return docTypeString + doc.documentElement.outerHTML;
|
|
|
}
|
|
|
|
|
|
+ function getFontKey(style) {
|
|
|
+ return JSON.stringify([
|
|
|
+ style.fontFamily,
|
|
|
+ style.fontWeight,
|
|
|
+ style.fontStyle,
|
|
|
+ style.fontVariant
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ function removeQuotes(string) {
|
|
|
+ string = string.toLowerCase().trim();
|
|
|
+ if (string.match(REGEXP_SIMPLE_QUOTES_STRING)) {
|
|
|
+ string = string.replace(REGEXP_SIMPLE_QUOTES_STRING, "$1");
|
|
|
+ } else {
|
|
|
+ string = string.replace(REGEXP_DOUBLE_QUOTES_STRING, "$1");
|
|
|
+ }
|
|
|
+ return string.trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ function getFontWeight(weight) {
|
|
|
+ return FONT_WEIGHTS[weight] || weight;
|
|
|
+ }
|
|
|
+
|
|
|
})();
|