|
@@ -27,10 +27,10 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
const SELECTED_CONTENT_ROOT_ATTRIBUTE_NAME = "data-single-file-selected-content-root";
|
|
const SELECTED_CONTENT_ROOT_ATTRIBUTE_NAME = "data-single-file-selected-content-root";
|
|
|
const DEBUG = false;
|
|
const DEBUG = false;
|
|
|
|
|
|
|
|
- let DocUtil, cssTree, sessionId = 0;
|
|
|
|
|
|
|
+ let docUtil, cssTree, sessionId = 0;
|
|
|
|
|
|
|
|
function getClass(...args) {
|
|
function getClass(...args) {
|
|
|
- [DocUtil, cssTree] = args;
|
|
|
|
|
|
|
+ [docUtil, cssTree] = args;
|
|
|
return SingleFileClass;
|
|
return SingleFileClass;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -151,7 +151,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
this.batchRequest = new BatchRequest();
|
|
this.batchRequest = new BatchRequest();
|
|
|
this.processor = new Processor(options, this.batchRequest);
|
|
this.processor = new Processor(options, this.batchRequest);
|
|
|
if (this.options.doc) {
|
|
if (this.options.doc) {
|
|
|
- const docData = DocUtil.preProcessDoc(this.options.doc, this.options.win, this.options);
|
|
|
|
|
|
|
+ const docData = docUtil.preProcessDoc(this.options.doc, this.options.win, this.options);
|
|
|
this.options.canvasData = docData.canvasData;
|
|
this.options.canvasData = docData.canvasData;
|
|
|
this.options.fontsData = docData.fontsData;
|
|
this.options.fontsData = docData.fontsData;
|
|
|
this.options.stylesheetContents = docData.stylesheetContents;
|
|
this.options.stylesheetContents = docData.stylesheetContents;
|
|
@@ -163,7 +163,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
if (this.options.saveRawPage) {
|
|
if (this.options.saveRawPage) {
|
|
|
this.options.removeFrames = true;
|
|
this.options.removeFrames = true;
|
|
|
}
|
|
}
|
|
|
- this.options.content = this.options.content || (this.options.doc ? DocUtil.serialize(this.options.doc, false) : null);
|
|
|
|
|
|
|
+ this.options.content = this.options.content || (this.options.doc ? docUtil.serialize(this.options.doc, false) : null);
|
|
|
this.onprogress = options.onprogress || (() => { });
|
|
this.onprogress = options.onprogress || (() => { });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -178,7 +178,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
await this.executeStage(RESOLVE_URLS_STAGE);
|
|
await this.executeStage(RESOLVE_URLS_STAGE);
|
|
|
this.pendingPromises = this.executeStage(REPLACE_DATA_STAGE);
|
|
this.pendingPromises = this.executeStage(REPLACE_DATA_STAGE);
|
|
|
if (this.options.doc) {
|
|
if (this.options.doc) {
|
|
|
- DocUtil.postProcessDoc(this.options.doc, this.options);
|
|
|
|
|
|
|
+ docUtil.postProcessDoc(this.options.doc, this.options);
|
|
|
this.options.doc = null;
|
|
this.options.doc = null;
|
|
|
this.options.win = null;
|
|
this.options.win = null;
|
|
|
}
|
|
}
|
|
@@ -298,7 +298,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
const [resourceURL, asDataURI] = JSON.parse(requestKey);
|
|
const [resourceURL, asDataURI] = JSON.parse(requestKey);
|
|
|
const resourceRequests = this.requests.get(requestKey);
|
|
const resourceRequests = this.requests.get(requestKey);
|
|
|
try {
|
|
try {
|
|
|
- const content = await DocUtil.getContent(resourceURL, { asDataURI, maxResourceSize: options.maxResourceSize, maxResourceSizeEnabled: options.maxResourceSizeEnabled });
|
|
|
|
|
|
|
+ const content = await docUtil.getContent(resourceURL, { asDataURI, maxResourceSize: options.maxResourceSize, maxResourceSizeEnabled: options.maxResourceSizeEnabled });
|
|
|
indexResource = indexResource + 1;
|
|
indexResource = indexResource + 1;
|
|
|
onloadListener({ index: indexResource, url: resourceURL });
|
|
onloadListener({ index: indexResource, url: resourceURL });
|
|
|
resourceRequests.forEach(callbacks => {
|
|
resourceRequests.forEach(callbacks => {
|
|
@@ -346,10 +346,10 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
async loadPage(pageContent, charset) {
|
|
async loadPage(pageContent, charset) {
|
|
|
let content;
|
|
let content;
|
|
|
if (!pageContent || this.options.saveRawPage) {
|
|
if (!pageContent || this.options.saveRawPage) {
|
|
|
- content = await DocUtil.getContent(this.baseURI, { asDataURI: false, maxResourceSize: this.options.maxResourceSize, maxResourceSizeEnabled: this.options.maxResourceSizeEnabled, charset });
|
|
|
|
|
|
|
+ content = await docUtil.getContent(this.baseURI, { asDataURI: false, maxResourceSize: this.options.maxResourceSize, maxResourceSizeEnabled: this.options.maxResourceSizeEnabled, charset });
|
|
|
pageContent = content.data;
|
|
pageContent = content.data;
|
|
|
}
|
|
}
|
|
|
- this.doc = DocUtil.parseDocContent(pageContent, this.baseURI);
|
|
|
|
|
|
|
+ this.doc = docUtil.parseDocContent(pageContent, this.baseURI);
|
|
|
if (this.options.saveRawPage) {
|
|
if (this.options.saveRawPage) {
|
|
|
let charset;
|
|
let charset;
|
|
|
this.doc.querySelectorAll("meta[charset], meta[http-equiv=\"content-type\"]").forEach(element => {
|
|
this.doc.querySelectorAll("meta[charset], meta[http-equiv=\"content-type\"]").forEach(element => {
|
|
@@ -394,8 +394,8 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async getPageData() {
|
|
async getPageData() {
|
|
|
- DocUtil.postProcessDoc(this.doc, this.options);
|
|
|
|
|
- const url = DocUtil.parseURL(this.baseURI);
|
|
|
|
|
|
|
+ docUtil.postProcessDoc(this.doc, this.options);
|
|
|
|
|
+ const url = docUtil.parseURL(this.baseURI);
|
|
|
if (this.options.insertSingleFileComment) {
|
|
if (this.options.insertSingleFileComment) {
|
|
|
const infobarContent = (this.options.infobarContent || "").replace(/\\n/g, "\n").replace(/\\t/g, "\t");
|
|
const infobarContent = (this.options.infobarContent || "").replace(/\\n/g, "\n").replace(/\\t/g, "\t");
|
|
|
const commentNode = this.doc.createComment("\n Page saved with SingleFile" +
|
|
const commentNode = this.doc.createComment("\n Page saved with SingleFile" +
|
|
@@ -406,11 +406,11 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
}
|
|
|
let size;
|
|
let size;
|
|
|
if (this.options.displayStats) {
|
|
if (this.options.displayStats) {
|
|
|
- size = DocUtil.getContentSize(this.doc.documentElement.outerHTML);
|
|
|
|
|
|
|
+ size = docUtil.getContentSize(this.doc.documentElement.outerHTML);
|
|
|
}
|
|
}
|
|
|
- const content = DocUtil.serialize(this.doc, this.options.compressHTML);
|
|
|
|
|
|
|
+ const content = docUtil.serialize(this.doc, this.options.compressHTML);
|
|
|
if (this.options.displayStats) {
|
|
if (this.options.displayStats) {
|
|
|
- const contentSize = DocUtil.getContentSize(content);
|
|
|
|
|
|
|
+ const contentSize = docUtil.getContentSize(content);
|
|
|
this.stats.set("processed", "HTML bytes", contentSize);
|
|
this.stats.set("processed", "HTML bytes", contentSize);
|
|
|
this.stats.add("discarded", "HTML bytes", size - contentSize);
|
|
this.stats.add("discarded", "HTML bytes", size - contentSize);
|
|
|
}
|
|
}
|
|
@@ -442,7 +442,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
this.doc.body.querySelectorAll(":not(svg) title, meta, link[href][rel*=\"icon\"]").forEach(element => element instanceof this.options.win.HTMLElement && this.doc.head.appendChild(element));
|
|
this.doc.body.querySelectorAll(":not(svg) title, meta, link[href][rel*=\"icon\"]").forEach(element => element instanceof this.options.win.HTMLElement && this.doc.head.appendChild(element));
|
|
|
}
|
|
}
|
|
|
if (this.options.imageData) {
|
|
if (this.options.imageData) {
|
|
|
- const dataAttributeName = DocUtil.imagesAttributeName(this.options.sessionId);
|
|
|
|
|
|
|
+ const dataAttributeName = docUtil.imagesAttributeName(this.options.sessionId);
|
|
|
this.doc.querySelectorAll("img").forEach(imgElement => {
|
|
this.doc.querySelectorAll("img").forEach(imgElement => {
|
|
|
const imgData = this.options.imageData[Number(imgElement.getAttribute(dataAttributeName))];
|
|
const imgData = this.options.imageData[Number(imgElement.getAttribute(dataAttributeName))];
|
|
|
if (this.options.removeHiddenElements && imgData.size && !imgData.size.pxWidth && !imgData.size.pxHeight) {
|
|
if (this.options.removeHiddenElements && imgData.size && !imgData.size.pxWidth && !imgData.size.pxHeight) {
|
|
@@ -472,13 +472,13 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
|
|
|
|
|
insertShadowRootContents() {
|
|
insertShadowRootContents() {
|
|
|
if (this.options.shadowRootContents) {
|
|
if (this.options.shadowRootContents) {
|
|
|
- this.doc.querySelectorAll("[" + DocUtil.shadowRootAttributeName(this.options.sessionId) + "]").forEach((element, elementIndex) => {
|
|
|
|
|
|
|
+ this.doc.querySelectorAll("[" + docUtil.shadowRootAttributeName(this.options.sessionId) + "]").forEach((element, elementIndex) => {
|
|
|
const elementInfo = this.options.shadowRootContents[elementIndex];
|
|
const elementInfo = this.options.shadowRootContents[elementIndex];
|
|
|
if (elementInfo) {
|
|
if (elementInfo) {
|
|
|
const frameElement = this.doc.createElement("iframe");
|
|
const frameElement = this.doc.createElement("iframe");
|
|
|
frameElement.setAttribute("style", "all:initial!important;border:0!important;width:100%!important;height:" + elementInfo.height + "px!important");
|
|
frameElement.setAttribute("style", "all:initial!important;border:0!important;width:100%!important;height:" + elementInfo.height + "px!important");
|
|
|
const windowId = "shadow-" + this.options.framesData.length;
|
|
const windowId = "shadow-" + this.options.framesData.length;
|
|
|
- frameElement.setAttribute(DocUtil.windowIdAttributeName(this.options.sessionId), windowId);
|
|
|
|
|
|
|
+ frameElement.setAttribute(docUtil.windowIdAttributeName(this.options.sessionId), windowId);
|
|
|
this.options.framesData.push({ windowId, content: elementInfo.content, baseURI: this.baseURI });
|
|
this.options.framesData.push({ windowId, content: elementInfo.content, baseURI: this.baseURI });
|
|
|
element.appendChild(frameElement);
|
|
element.appendChild(frameElement);
|
|
|
}
|
|
}
|
|
@@ -625,22 +625,22 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
|
|
|
|
|
setInputValues() {
|
|
setInputValues() {
|
|
|
this.doc.querySelectorAll("input").forEach(input => {
|
|
this.doc.querySelectorAll("input").forEach(input => {
|
|
|
- const value = input.getAttribute(DocUtil.inputValueAttributeName(this.options.sessionId));
|
|
|
|
|
|
|
+ const value = input.getAttribute(docUtil.inputValueAttributeName(this.options.sessionId));
|
|
|
input.setAttribute("value", value || "");
|
|
input.setAttribute("value", value || "");
|
|
|
});
|
|
});
|
|
|
this.doc.querySelectorAll("input[type=radio], input[type=checkbox]").forEach(input => {
|
|
this.doc.querySelectorAll("input[type=radio], input[type=checkbox]").forEach(input => {
|
|
|
- const value = input.getAttribute(DocUtil.inputValueAttributeName(this.options.sessionId));
|
|
|
|
|
|
|
+ const value = input.getAttribute(docUtil.inputValueAttributeName(this.options.sessionId));
|
|
|
if (value == "true") {
|
|
if (value == "true") {
|
|
|
input.setAttribute("checked", "");
|
|
input.setAttribute("checked", "");
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
this.doc.querySelectorAll("textarea").forEach(textarea => {
|
|
this.doc.querySelectorAll("textarea").forEach(textarea => {
|
|
|
- const value = textarea.getAttribute(DocUtil.inputValueAttributeName(this.options.sessionId));
|
|
|
|
|
|
|
+ const value = textarea.getAttribute(docUtil.inputValueAttributeName(this.options.sessionId));
|
|
|
textarea.textContent = value || "";
|
|
textarea.textContent = value || "";
|
|
|
});
|
|
});
|
|
|
this.doc.querySelectorAll("select").forEach(select => {
|
|
this.doc.querySelectorAll("select").forEach(select => {
|
|
|
select.querySelectorAll("option").forEach(option => {
|
|
select.querySelectorAll("option").forEach(option => {
|
|
|
- const selected = option.getAttribute(DocUtil.inputValueAttributeName(this.options.sessionId)) != null;
|
|
|
|
|
|
|
+ const selected = option.getAttribute(docUtil.inputValueAttributeName(this.options.sessionId)) != null;
|
|
|
if (selected) {
|
|
if (selected) {
|
|
|
option.setAttribute("selected", "");
|
|
option.setAttribute("selected", "");
|
|
|
}
|
|
}
|
|
@@ -704,7 +704,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
removeHiddenElements() {
|
|
removeHiddenElements() {
|
|
|
- const hiddenElements = this.doc.querySelectorAll("[" + DocUtil.removedContentAttributeName(this.options.sessionId) + "]");
|
|
|
|
|
|
|
+ const hiddenElements = this.doc.querySelectorAll("[" + docUtil.removedContentAttributeName(this.options.sessionId) + "]");
|
|
|
this.stats.set("discarded", "hidden elements", hiddenElements.length);
|
|
this.stats.set("discarded", "hidden elements", hiddenElements.length);
|
|
|
this.stats.set("processed", "hidden elements", hiddenElements.length);
|
|
this.stats.set("processed", "hidden elements", hiddenElements.length);
|
|
|
hiddenElements.forEach(element => element.remove());
|
|
hiddenElements.forEach(element => element.remove());
|
|
@@ -715,7 +715,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
const href = element.getAttribute("href").trim();
|
|
const href = element.getAttribute("href").trim();
|
|
|
if (!Util.testIgnoredPath(href) && !href.startsWith("#")) {
|
|
if (!Util.testIgnoredPath(href) && !href.startsWith("#")) {
|
|
|
try {
|
|
try {
|
|
|
- element.setAttribute("href", DocUtil.resolveURL(href, this.options.baseURI || this.options.url));
|
|
|
|
|
|
|
+ element.setAttribute("href", docUtil.resolveURL(href, this.options.baseURI || this.options.url));
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
// ignored
|
|
// ignored
|
|
|
}
|
|
}
|
|
@@ -727,7 +727,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
this.doc.querySelectorAll("[style]").forEach(element => {
|
|
this.doc.querySelectorAll("[style]").forEach(element => {
|
|
|
let styleContent = element.getAttribute("style");
|
|
let styleContent = element.getAttribute("style");
|
|
|
if (this.options.compressCSS) {
|
|
if (this.options.compressCSS) {
|
|
|
- styleContent = DocUtil.compressCSS(styleContent);
|
|
|
|
|
|
|
+ styleContent = docUtil.compressCSS(styleContent);
|
|
|
}
|
|
}
|
|
|
styleContent = ProcessorHelper.resolveStylesheetURLs(styleContent, this.baseURI, this.options);
|
|
styleContent = ProcessorHelper.resolveStylesheetURLs(styleContent, this.baseURI, this.options);
|
|
|
const declarationList = cssTree.parse(styleContent, { context: "declarationList" });
|
|
const declarationList = cssTree.parse(styleContent, { context: "declarationList" });
|
|
@@ -775,7 +775,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
const frameElements = Array.from(this.doc.querySelectorAll("iframe, frame, object[type=\"text/html\"][data]"));
|
|
const frameElements = Array.from(this.doc.querySelectorAll("iframe, frame, object[type=\"text/html\"][data]"));
|
|
|
await Promise.all(frameElements.map(async frameElement => {
|
|
await Promise.all(frameElements.map(async frameElement => {
|
|
|
ProcessorHelper.setFrameEmptySrc(frameElement);
|
|
ProcessorHelper.setFrameEmptySrc(frameElement);
|
|
|
- const frameWindowId = frameElement.getAttribute(DocUtil.windowIdAttributeName(this.options.sessionId));
|
|
|
|
|
|
|
+ const frameWindowId = frameElement.getAttribute(docUtil.windowIdAttributeName(this.options.sessionId));
|
|
|
if (frameWindowId) {
|
|
if (frameWindowId) {
|
|
|
const frameData = this.options.framesData.find(frame => frame.windowId == frameWindowId);
|
|
const frameData = this.options.framesData.find(frame => frame.windowId == frameWindowId);
|
|
|
if (frameData) {
|
|
if (frameData) {
|
|
@@ -833,19 +833,19 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
|
|
|
|
|
removeUnusedStyles() {
|
|
removeUnusedStyles() {
|
|
|
if (!this.mediaAllInfo) {
|
|
if (!this.mediaAllInfo) {
|
|
|
- this.mediaAllInfo = DocUtil.getMediaAllInfo(this.doc, this.stylesheets, this.styles);
|
|
|
|
|
|
|
+ this.mediaAllInfo = docUtil.getMediaAllInfo(this.doc, this.stylesheets, this.styles);
|
|
|
}
|
|
}
|
|
|
- const stats = DocUtil.minifyCSSRules(this.stylesheets, this.styles, this.mediaAllInfo);
|
|
|
|
|
|
|
+ const stats = docUtil.minifyCSSRules(this.stylesheets, this.styles, this.mediaAllInfo);
|
|
|
this.stats.set("processed", "CSS rules", stats.processed);
|
|
this.stats.set("processed", "CSS rules", stats.processed);
|
|
|
this.stats.set("discarded", "CSS rules", stats.discarded);
|
|
this.stats.set("discarded", "CSS rules", stats.discarded);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
removeUnusedFonts() {
|
|
removeUnusedFonts() {
|
|
|
- DocUtil.removeUnusedFonts(this.doc, this.stylesheets, this.styles, this.options);
|
|
|
|
|
|
|
+ docUtil.removeUnusedFonts(this.doc, this.stylesheets, this.styles, this.options);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
removeAlternativeMedias() {
|
|
removeAlternativeMedias() {
|
|
|
- const stats = DocUtil.minifyMedias(this.stylesheets);
|
|
|
|
|
|
|
+ const stats = docUtil.minifyMedias(this.stylesheets);
|
|
|
this.stats.set("processed", "medias", stats.processed);
|
|
this.stats.set("processed", "medias", stats.processed);
|
|
|
this.stats.set("discarded", "medias", stats.discarded);
|
|
this.stats.set("discarded", "medias", stats.discarded);
|
|
|
}
|
|
}
|
|
@@ -896,31 +896,31 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
scriptElement.removeAttribute("src");
|
|
scriptElement.removeAttribute("src");
|
|
|
scriptElement.textContent = "";
|
|
scriptElement.textContent = "";
|
|
|
try {
|
|
try {
|
|
|
- resourceURL = DocUtil.resolveURL(scriptSrc, this.baseURI);
|
|
|
|
|
|
|
+ resourceURL = docUtil.resolveURL(scriptSrc, this.baseURI);
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
// ignored
|
|
// ignored
|
|
|
}
|
|
}
|
|
|
if (Util.testValidURL(resourceURL, this.baseURI, this.options.url)) {
|
|
if (Util.testValidURL(resourceURL, this.baseURI, this.options.url)) {
|
|
|
this.stats.add("processed", "scripts", 1);
|
|
this.stats.add("processed", "scripts", 1);
|
|
|
- const content = await DocUtil.getContent(resourceURL, { asDataURI: true, maxResourceSize: this.options.maxResourceSize, maxResourceSizeEnabled: this.options.maxResourceSizeEnabled });
|
|
|
|
|
|
|
+ const content = await docUtil.getContent(resourceURL, { asDataURI: true, maxResourceSize: this.options.maxResourceSize, maxResourceSizeEnabled: this.options.maxResourceSizeEnabled });
|
|
|
scriptElement.setAttribute("src", content.data);
|
|
scriptElement.setAttribute("src", content.data);
|
|
|
}
|
|
}
|
|
|
}));
|
|
}));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
removeAlternativeImages() {
|
|
removeAlternativeImages() {
|
|
|
- DocUtil.removeAlternativeImages(this.doc);
|
|
|
|
|
|
|
+ docUtil.removeAlternativeImages(this.doc);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
removeAlternativeFonts() {
|
|
removeAlternativeFonts() {
|
|
|
- DocUtil.removeAlternativeFonts(this.doc, this.stylesheets);
|
|
|
|
|
|
|
+ docUtil.removeAlternativeFonts(this.doc, this.stylesheets);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async processFrames() {
|
|
async processFrames() {
|
|
|
if (this.options.framesData) {
|
|
if (this.options.framesData) {
|
|
|
const frameElements = Array.from(this.doc.querySelectorAll("iframe, frame, object[type=\"text/html\"][data]"));
|
|
const frameElements = Array.from(this.doc.querySelectorAll("iframe, frame, object[type=\"text/html\"][data]"));
|
|
|
await Promise.all(frameElements.map(async frameElement => {
|
|
await Promise.all(frameElements.map(async frameElement => {
|
|
|
- const frameWindowId = frameElement.getAttribute(DocUtil.windowIdAttributeName(this.options.sessionId));
|
|
|
|
|
|
|
+ const frameWindowId = frameElement.getAttribute(docUtil.windowIdAttributeName(this.options.sessionId));
|
|
|
if (frameWindowId) {
|
|
if (frameWindowId) {
|
|
|
const frameData = this.options.framesData.find(frame => frame.windowId == frameWindowId);
|
|
const frameData = this.options.framesData.find(frame => frame.windowId == frameWindowId);
|
|
|
if (frameData) {
|
|
if (frameData) {
|
|
@@ -928,7 +928,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
this.stats.add("processed", "frames", 1);
|
|
this.stats.add("processed", "frames", 1);
|
|
|
await frameData.processor.run();
|
|
await frameData.processor.run();
|
|
|
const pageData = await frameData.processor.getPageData();
|
|
const pageData = await frameData.processor.getPageData();
|
|
|
- frameElement.removeAttribute(DocUtil.windowIdAttributeName(this.options.sessionId));
|
|
|
|
|
|
|
+ frameElement.removeAttribute(docUtil.windowIdAttributeName(this.options.sessionId));
|
|
|
if (pageData.content.match(NOSCRIPT_TAG_FOUND) || pageData.content.match(SCRIPT_TAG_FOUND)) {
|
|
if (pageData.content.match(NOSCRIPT_TAG_FOUND) || pageData.content.match(SCRIPT_TAG_FOUND)) {
|
|
|
frameElement.setAttribute("sandbox", "allow-scripts allow-same-origin");
|
|
frameElement.setAttribute("sandbox", "allow-scripts allow-same-origin");
|
|
|
} else {
|
|
} else {
|
|
@@ -1025,11 +1025,11 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
compressHTML() {
|
|
compressHTML() {
|
|
|
let size;
|
|
let size;
|
|
|
if (this.options.displayStats) {
|
|
if (this.options.displayStats) {
|
|
|
- size = DocUtil.getContentSize(this.doc.documentElement.outerHTML);
|
|
|
|
|
|
|
+ size = docUtil.getContentSize(this.doc.documentElement.outerHTML);
|
|
|
}
|
|
}
|
|
|
- DocUtil.minifyHTML(this.doc, { preservedSpaceAttributeName: DocUtil.preservedSpaceAttributeName(this.options.sessionId) });
|
|
|
|
|
|
|
+ docUtil.minifyHTML(this.doc, { preservedSpaceAttributeName: docUtil.preservedSpaceAttributeName(this.options.sessionId) });
|
|
|
if (this.options.displayStats) {
|
|
if (this.options.displayStats) {
|
|
|
- this.stats.add("discarded", "HTML bytes", size - DocUtil.getContentSize(this.doc.documentElement.outerHTML));
|
|
|
|
|
|
|
+ this.stats.add("discarded", "HTML bytes", size - docUtil.getContentSize(this.doc.documentElement.outerHTML));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -1055,7 +1055,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
class ProcessorHelper {
|
|
class ProcessorHelper {
|
|
|
static async evalTemplate(template, options, content, dontReplaceSlash) {
|
|
static async evalTemplate(template, options, content, dontReplaceSlash) {
|
|
|
const date = new Date();
|
|
const date = new Date();
|
|
|
- const url = DocUtil.parseURL(options.url);
|
|
|
|
|
|
|
+ const url = docUtil.parseURL(options.url);
|
|
|
template = await Util.evalTemplateVariable(template, "page-title", () => options.title || "No title", dontReplaceSlash);
|
|
template = await Util.evalTemplateVariable(template, "page-title", () => options.title || "No title", dontReplaceSlash);
|
|
|
template = await Util.evalTemplateVariable(template, "page-language", () => options.info.lang || "No language", dontReplaceSlash);
|
|
template = await Util.evalTemplateVariable(template, "page-language", () => options.info.lang || "No language", dontReplaceSlash);
|
|
|
template = await Util.evalTemplateVariable(template, "page-description", () => options.info.description || "No description", dontReplaceSlash);
|
|
template = await Util.evalTemplateVariable(template, "page-description", () => options.info.description || "No description", dontReplaceSlash);
|
|
@@ -1094,9 +1094,9 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
template = await Util.evalTemplateVariable(template, "tab-id", () => String(options.tabId || "No tab id"), dontReplaceSlash);
|
|
template = await Util.evalTemplateVariable(template, "tab-id", () => String(options.tabId || "No tab id"), dontReplaceSlash);
|
|
|
template = await Util.evalTemplateVariable(template, "url-last-segment", () => Util.getLastSegment(url) || "No last segment", dontReplaceSlash);
|
|
template = await Util.evalTemplateVariable(template, "url-last-segment", () => Util.getLastSegment(url) || "No last segment", dontReplaceSlash);
|
|
|
if (content) {
|
|
if (content) {
|
|
|
- template = await Util.evalTemplateVariable(template, "digest-sha-256", async () => DocUtil.digest("SHA-256", content), dontReplaceSlash);
|
|
|
|
|
- template = await Util.evalTemplateVariable(template, "digest-sha-384", async () => DocUtil.digest("SHA-384", content), dontReplaceSlash);
|
|
|
|
|
- template = await Util.evalTemplateVariable(template, "digest-sha-512", async () => DocUtil.digest("SHA-512", content), dontReplaceSlash);
|
|
|
|
|
|
|
+ template = await Util.evalTemplateVariable(template, "digest-sha-256", async () => docUtil.digest("SHA-256", content), dontReplaceSlash);
|
|
|
|
|
+ template = await Util.evalTemplateVariable(template, "digest-sha-384", async () => docUtil.digest("SHA-384", content), dontReplaceSlash);
|
|
|
|
|
+ template = await Util.evalTemplateVariable(template, "digest-sha-512", async () => docUtil.digest("SHA-512", content), dontReplaceSlash);
|
|
|
}
|
|
}
|
|
|
return template;
|
|
return template;
|
|
|
}
|
|
}
|
|
@@ -1204,17 +1204,17 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
let resourceURL = Util.normalizeURL(match.resourceURL);
|
|
let resourceURL = Util.normalizeURL(match.resourceURL);
|
|
|
if (!Util.testIgnoredPath(resourceURL) && Util.testValidPath(resourceURL, baseURI, options.url)) {
|
|
if (!Util.testIgnoredPath(resourceURL) && Util.testValidPath(resourceURL, baseURI, options.url)) {
|
|
|
try {
|
|
try {
|
|
|
- resourceURL = DocUtil.resolveURL(match.resourceURL, baseURI);
|
|
|
|
|
|
|
+ resourceURL = docUtil.resolveURL(match.resourceURL, baseURI);
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
// ignored
|
|
// ignored
|
|
|
}
|
|
}
|
|
|
if (Util.testValidURL(resourceURL, baseURI, options.url)) {
|
|
if (Util.testValidURL(resourceURL, baseURI, options.url)) {
|
|
|
const downloadOptions = { asDataURI: false, maxResourceSize: options.maxResourceSize, maxResourceSizeEnabled: options.maxResourceSizeEnabled, validateTextContentType: true };
|
|
const downloadOptions = { asDataURI: false, maxResourceSize: options.maxResourceSize, maxResourceSizeEnabled: options.maxResourceSizeEnabled, validateTextContentType: true };
|
|
|
- const content = await DocUtil.getContent(resourceURL, downloadOptions);
|
|
|
|
|
|
|
+ const content = await docUtil.getContent(resourceURL, downloadOptions);
|
|
|
resourceURL = content.resourceURL;
|
|
resourceURL = content.resourceURL;
|
|
|
let importedStylesheetContent = Util.removeCssComments(content.data);
|
|
let importedStylesheetContent = Util.removeCssComments(content.data);
|
|
|
if (options.compressCSS) {
|
|
if (options.compressCSS) {
|
|
|
- importedStylesheetContent = DocUtil.compressCSS(importedStylesheetContent);
|
|
|
|
|
|
|
+ importedStylesheetContent = docUtil.compressCSS(importedStylesheetContent);
|
|
|
}
|
|
}
|
|
|
importedStylesheetContent = Util.wrapMediaQuery(importedStylesheetContent, match.media);
|
|
importedStylesheetContent = Util.wrapMediaQuery(importedStylesheetContent, match.media);
|
|
|
if (stylesheetContent.includes(cssImport)) {
|
|
if (stylesheetContent.includes(cssImport)) {
|
|
@@ -1242,7 +1242,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
if (!resourceURL || Util.testValidPath(resourceURL, baseURI, options.url)) {
|
|
if (!resourceURL || Util.testValidPath(resourceURL, baseURI, options.url)) {
|
|
|
let resolvedURL;
|
|
let resolvedURL;
|
|
|
try {
|
|
try {
|
|
|
- resolvedURL = DocUtil.resolveURL(resourceURL, baseURI);
|
|
|
|
|
|
|
+ resolvedURL = docUtil.resolveURL(resourceURL, baseURI);
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
// ignored
|
|
// ignored
|
|
|
}
|
|
}
|
|
@@ -1274,11 +1274,11 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
resourceURL = Util.normalizeURL(resourceURL);
|
|
resourceURL = Util.normalizeURL(resourceURL);
|
|
|
if (resourceURL && resourceURL != baseURI && resourceURL != ABOUT_BLANK_URI) {
|
|
if (resourceURL && resourceURL != baseURI && resourceURL != ABOUT_BLANK_URI) {
|
|
|
const downloadOptions = { asDataURI: false, maxResourceSize: options.maxResourceSize, maxResourceSizeEnabled: options.maxResourceSizeEnabled, charset: options.charset };
|
|
const downloadOptions = { asDataURI: false, maxResourceSize: options.maxResourceSize, maxResourceSizeEnabled: options.maxResourceSizeEnabled, charset: options.charset };
|
|
|
- const content = await DocUtil.getContent(resourceURL, downloadOptions);
|
|
|
|
|
|
|
+ const content = await docUtil.getContent(resourceURL, downloadOptions);
|
|
|
resourceURL = content.resourceURL;
|
|
resourceURL = content.resourceURL;
|
|
|
let stylesheetContent = Util.removeCssComments(content.data);
|
|
let stylesheetContent = Util.removeCssComments(content.data);
|
|
|
if (options.compressCSS) {
|
|
if (options.compressCSS) {
|
|
|
- stylesheetContent = DocUtil.compressCSS(stylesheetContent);
|
|
|
|
|
|
|
+ stylesheetContent = docUtil.compressCSS(stylesheetContent);
|
|
|
}
|
|
}
|
|
|
stylesheetContent = await ProcessorHelper.resolveImportURLs(stylesheetContent, resourceURL, options, workStylesheet);
|
|
stylesheetContent = await ProcessorHelper.resolveImportURLs(stylesheetContent, resourceURL, options, workStylesheet);
|
|
|
return stylesheetContent;
|
|
return stylesheetContent;
|
|
@@ -1316,7 +1316,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
if (Util.testValidURL(resourceURL, baseURI, options.url)) {
|
|
if (Util.testValidURL(resourceURL, baseURI, options.url)) {
|
|
|
let { content } = await batchRequest.addURL(resourceURL, true);
|
|
let { content } = await batchRequest.addURL(resourceURL, true);
|
|
|
if (content != EMPTY_DATA_URI && !content.startsWith(PREFIX_DATA_URI_VND) && !content.startsWith(PREFIX_DATA_URI_IMAGE_SVG)) {
|
|
if (content != EMPTY_DATA_URI && !content.startsWith(PREFIX_DATA_URI_VND) && !content.startsWith(PREFIX_DATA_URI_IMAGE_SVG)) {
|
|
|
- const validResource = await DocUtil.validFont(urlFunction);
|
|
|
|
|
|
|
+ const validResource = await docUtil.validFont(urlFunction);
|
|
|
if (!validResource) {
|
|
if (!validResource) {
|
|
|
content = EMPTY_DATA_URI;
|
|
content = EMPTY_DATA_URI;
|
|
|
}
|
|
}
|
|
@@ -1324,7 +1324,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
replaceURLs(declaration, originalResourceURL, content);
|
|
replaceURLs(declaration, originalResourceURL, content);
|
|
|
}
|
|
}
|
|
|
} else if (resourceURL.startsWith(DATA_URI_PREFIX) && !resourceURL.startsWith(PREFIX_DATA_URI_VND) && !resourceURL.startsWith(PREFIX_DATA_URI_IMAGE_SVG)) {
|
|
} else if (resourceURL.startsWith(DATA_URI_PREFIX) && !resourceURL.startsWith(PREFIX_DATA_URI_VND) && !resourceURL.startsWith(PREFIX_DATA_URI_IMAGE_SVG)) {
|
|
|
- const validResource = await DocUtil.validFont(urlFunction);
|
|
|
|
|
|
|
+ const validResource = await docUtil.validFont(urlFunction);
|
|
|
if (!validResource) {
|
|
if (!validResource) {
|
|
|
replaceURLs(declaration, originalResourceURL, EMPTY_DATA_URI);
|
|
replaceURLs(declaration, originalResourceURL, EMPTY_DATA_URI);
|
|
|
}
|
|
}
|
|
@@ -1335,7 +1335,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
|
|
|
|
|
function replaceURLs(declaration, oldURL, newURL) {
|
|
function replaceURLs(declaration, oldURL, newURL) {
|
|
|
declaration.value.children.forEach(token => {
|
|
declaration.value.children.forEach(token => {
|
|
|
- if (token.type == "Url" && DocUtil.removeQuotes(Util.getCSSValue(token.value)) == oldURL) {
|
|
|
|
|
|
|
+ if (token.type == "Url" && docUtil.removeQuotes(Util.getCSSValue(token.value)) == oldURL) {
|
|
|
token.value.value = newURL;
|
|
token.value.value = newURL;
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
@@ -1379,7 +1379,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
if (token.data.children) {
|
|
if (token.data.children) {
|
|
|
findURLToken(url, token.data.children, callback, depth + 1);
|
|
findURLToken(url, token.data.children, callback, depth + 1);
|
|
|
}
|
|
}
|
|
|
- if (token.data.type == "Url" && DocUtil.removeQuotes(Util.getCSSValue(token.data.value)) == url) {
|
|
|
|
|
|
|
+ if (token.data.type == "Url" && docUtil.removeQuotes(Util.getCSSValue(token.data.value)) == url) {
|
|
|
callback(token, children, depth == 0);
|
|
callback(token, children, depth == 0);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -1394,7 +1394,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
resourceElement.setAttribute(attributeName, EMPTY_IMAGE);
|
|
resourceElement.setAttribute(attributeName, EMPTY_IMAGE);
|
|
|
if (Util.testValidPath(resourceURL, baseURI, options.url)) {
|
|
if (Util.testValidPath(resourceURL, baseURI, options.url)) {
|
|
|
try {
|
|
try {
|
|
|
- resourceURL = DocUtil.resolveURL(resourceURL, baseURI);
|
|
|
|
|
|
|
+ resourceURL = docUtil.resolveURL(resourceURL, baseURI);
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
// ignored
|
|
// ignored
|
|
|
}
|
|
}
|
|
@@ -1432,7 +1432,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
if (Util.testValidPath(resourceURL, baseURI, options.url) && !Util.testIgnoredPath(resourceURL)) {
|
|
if (Util.testValidPath(resourceURL, baseURI, options.url) && !Util.testIgnoredPath(resourceURL)) {
|
|
|
resourceElement.setAttribute(attributeName, EMPTY_IMAGE);
|
|
resourceElement.setAttribute(attributeName, EMPTY_IMAGE);
|
|
|
try {
|
|
try {
|
|
|
- resourceURL = DocUtil.resolveURL(resourceURL, baseURI);
|
|
|
|
|
|
|
+ resourceURL = docUtil.resolveURL(resourceURL, baseURI);
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
// ignored
|
|
// ignored
|
|
|
}
|
|
}
|
|
@@ -1441,7 +1441,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
const { content } = await batchRequest.addURL(resourceURL);
|
|
const { content } = await batchRequest.addURL(resourceURL);
|
|
|
const hashMatch = originalResourceURL.match(REGEXP_URL_HASH);
|
|
const hashMatch = originalResourceURL.match(REGEXP_URL_HASH);
|
|
|
if (hashMatch && hashMatch[0]) {
|
|
if (hashMatch && hashMatch[0]) {
|
|
|
- const svgDoc = DocUtil.parseSVGContent(content);
|
|
|
|
|
|
|
+ const svgDoc = docUtil.parseSVGContent(content);
|
|
|
const symbolElement = svgDoc.querySelector(hashMatch[0]);
|
|
const symbolElement = svgDoc.querySelector(hashMatch[0]);
|
|
|
if (symbolElement) {
|
|
if (symbolElement) {
|
|
|
resourceElement.setAttribute(attributeName, hashMatch[0]);
|
|
resourceElement.setAttribute(attributeName, hashMatch[0]);
|
|
@@ -1462,13 +1462,13 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
|
|
|
|
|
static async processSrcset(resourceElements, attributeName, prefixDataURI, baseURI, options, batchRequest) {
|
|
static async processSrcset(resourceElements, attributeName, prefixDataURI, baseURI, options, batchRequest) {
|
|
|
await Promise.all(Array.from(resourceElements).map(async resourceElement => {
|
|
await Promise.all(Array.from(resourceElements).map(async resourceElement => {
|
|
|
- const srcset = DocUtil.parseSrcset(resourceElement.getAttribute(attributeName));
|
|
|
|
|
|
|
+ const srcset = docUtil.parseSrcset(resourceElement.getAttribute(attributeName));
|
|
|
const srcsetValues = await Promise.all(srcset.map(async srcsetValue => {
|
|
const srcsetValues = await Promise.all(srcset.map(async srcsetValue => {
|
|
|
let resourceURL = Util.normalizeURL(srcsetValue.url);
|
|
let resourceURL = Util.normalizeURL(srcsetValue.url);
|
|
|
if (!Util.testIgnoredPath(resourceURL)) {
|
|
if (!Util.testIgnoredPath(resourceURL)) {
|
|
|
if (Util.testValidPath(resourceURL, baseURI, options.url)) {
|
|
if (Util.testValidPath(resourceURL, baseURI, options.url)) {
|
|
|
try {
|
|
try {
|
|
|
- resourceURL = DocUtil.resolveURL(resourceURL, baseURI);
|
|
|
|
|
|
|
+ resourceURL = docUtil.resolveURL(resourceURL, baseURI);
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
// ignored
|
|
// ignored
|
|
|
}
|
|
}
|
|
@@ -1647,7 +1647,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static replaceImageSource(imgElement, variableName, options) {
|
|
static replaceImageSource(imgElement, variableName, options) {
|
|
|
- const dataAttributeName = DocUtil.imagesAttributeName(options.sessionId);
|
|
|
|
|
|
|
+ const dataAttributeName = docUtil.imagesAttributeName(options.sessionId);
|
|
|
if (imgElement.getAttribute(dataAttributeName) != null) {
|
|
if (imgElement.getAttribute(dataAttributeName) != null) {
|
|
|
const imgData = options.imageData[Number(imgElement.getAttribute(dataAttributeName))];
|
|
const imgData = options.imageData[Number(imgElement.getAttribute(dataAttributeName))];
|
|
|
if (imgData.replaceable) {
|
|
if (imgData.replaceable) {
|