|
@@ -88,11 +88,11 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
{ option: "removeHiddenElements", action: "removeHiddenElements" }
|
|
{ option: "removeHiddenElements", action: "removeHiddenElements" }
|
|
|
],
|
|
],
|
|
|
parallel: [
|
|
parallel: [
|
|
|
- { action: "inlineStylesheets" },
|
|
|
|
|
- { action: "linkStylesheets" },
|
|
|
|
|
- { action: "attributeStyles" },
|
|
|
|
|
- { option: "!removeFrames", action: "frames" },
|
|
|
|
|
- { option: "!removeImports", action: "htmlImports" }
|
|
|
|
|
|
|
+ { action: "resolveStylesheetURLs" },
|
|
|
|
|
+ { action: "resolveLinkedStylesheetURLs" },
|
|
|
|
|
+ { action: "resolveStyleAttributeURLs" },
|
|
|
|
|
+ { option: "!removeFrames", action: "resolveFrameURLs" },
|
|
|
|
|
+ { option: "!removeImports", action: "resolveHtmlImportURLs" }
|
|
|
]
|
|
]
|
|
|
}, {
|
|
}, {
|
|
|
sequential: [
|
|
sequential: [
|
|
@@ -102,10 +102,10 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
{ option: "removeAlternativeMedias", action: "removeAlternativeMedias" }
|
|
{ option: "removeAlternativeMedias", action: "removeAlternativeMedias" }
|
|
|
],
|
|
],
|
|
|
parallel: [
|
|
parallel: [
|
|
|
- { action: "inlineStylesheets" },
|
|
|
|
|
- { action: "attributeStyles" },
|
|
|
|
|
|
|
+ { action: "processStylesheets" },
|
|
|
|
|
+ { action: "processStyleAttributes" },
|
|
|
{ action: "pageResources" },
|
|
{ action: "pageResources" },
|
|
|
- { option: "!removeScripts", action: "scripts" }
|
|
|
|
|
|
|
+ { option: "!removeScripts", action: "processScripts" }
|
|
|
]
|
|
]
|
|
|
}, {
|
|
}, {
|
|
|
sequential: [
|
|
sequential: [
|
|
@@ -115,8 +115,8 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
{ option: "compressCSS", action: "compressCSS" }
|
|
{ option: "compressCSS", action: "compressCSS" }
|
|
|
],
|
|
],
|
|
|
parallel: [
|
|
parallel: [
|
|
|
- { option: "!removeFrames", action: "frames" },
|
|
|
|
|
- { option: "!removeImports", action: "htmlImports" },
|
|
|
|
|
|
|
+ { option: "!removeFrames", action: "processFrames" },
|
|
|
|
|
+ { option: "!removeImports", action: "processHtmlImports" },
|
|
|
]
|
|
]
|
|
|
}, {
|
|
}, {
|
|
|
sequential: [
|
|
sequential: [
|
|
@@ -194,7 +194,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
startTime = Date.now();
|
|
startTime = Date.now();
|
|
|
log(" -- STARTED task =", task.action);
|
|
log(" -- STARTED task =", task.action);
|
|
|
}
|
|
}
|
|
|
- this.executeTask(task, !step);
|
|
|
|
|
|
|
+ this.executeTask(task);
|
|
|
if (DEBUG) {
|
|
if (DEBUG) {
|
|
|
log(" -- ENDED task =", task.action, "delay =", Date.now() - startTime);
|
|
log(" -- ENDED task =", task.action, "delay =", Date.now() - startTime);
|
|
|
}
|
|
}
|
|
@@ -206,7 +206,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
startTime = Date.now();
|
|
startTime = Date.now();
|
|
|
log(" // STARTED task =", task.action);
|
|
log(" // STARTED task =", task.action);
|
|
|
}
|
|
}
|
|
|
- const promise = this.executeTask(task, !step);
|
|
|
|
|
|
|
+ const promise = this.executeTask(task);
|
|
|
if (DEBUG) {
|
|
if (DEBUG) {
|
|
|
promise.then(() => log(" // ENDED task =", task.action, "delay =", Date.now() - startTime));
|
|
promise.then(() => log(" // ENDED task =", task.action, "delay =", Date.now() - startTime));
|
|
|
}
|
|
}
|
|
@@ -218,9 +218,9 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- executeTask(task, initialization) {
|
|
|
|
|
|
|
+ executeTask(task) {
|
|
|
if (!task.option || ((task.option.startsWith("!") && !this.options[task.option]) || this.options[task.option])) {
|
|
if (!task.option || ((task.option.startsWith("!") && !this.options[task.option]) || this.options[task.option])) {
|
|
|
- return this.processor[task.action](initialization);
|
|
|
|
|
|
|
+ return this.processor[task.action]();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -717,22 +717,18 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
await resourcePromises;
|
|
await resourcePromises;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async inlineStylesheets(initialization) {
|
|
|
|
|
|
|
+ async resolveStylesheetURLs() {
|
|
|
|
|
+ await Promise.all(Array.from(this.doc.querySelectorAll("style")).map(async styleElement => styleElement.textContent = await DomProcessorHelper.resolveImportURLs(styleElement.textContent, this.baseURI, { maxResourceSize: this.options.maxResourceSize, maxResourceSizeEnabled: this.options.maxResourceSizeEnabled })));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async processStylesheets() {
|
|
|
await Promise.all(Array.from(this.doc.querySelectorAll("style")).map(async (styleElement, indexStyle) => {
|
|
await Promise.all(Array.from(this.doc.querySelectorAll("style")).map(async (styleElement, indexStyle) => {
|
|
|
- if (!initialization) {
|
|
|
|
|
- this.stats.add("processed", "stylesheets", 1);
|
|
|
|
|
- }
|
|
|
|
|
- let stylesheetContent = styleElement.textContent;
|
|
|
|
|
- if (initialization) {
|
|
|
|
|
- stylesheetContent = await DomProcessorHelper.resolveImportURLs(styleElement.textContent, this.baseURI, { maxResourceSize: this.options.maxResourceSize, maxResourceSizeEnabled: this.options.maxResourceSizeEnabled });
|
|
|
|
|
- } else {
|
|
|
|
|
- stylesheetContent = await DomProcessorHelper.processStylesheet(styleElement.textContent, this.baseURI, this.options, false, indexStyle, this.batchRequest);
|
|
|
|
|
- }
|
|
|
|
|
- styleElement.textContent = stylesheetContent;
|
|
|
|
|
|
|
+ this.stats.add("processed", "stylesheets", 1);
|
|
|
|
|
+ styleElement.textContent = await DomProcessorHelper.processStylesheet(styleElement.textContent, this.baseURI, this.options, false, indexStyle, this.batchRequest);
|
|
|
}));
|
|
}));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async scripts() {
|
|
|
|
|
|
|
+ async processScripts() {
|
|
|
await Promise.all(Array.from(this.doc.querySelectorAll("script[src]")).map(async scriptElement => {
|
|
await Promise.all(Array.from(this.doc.querySelectorAll("script[src]")).map(async scriptElement => {
|
|
|
if (scriptElement.src) {
|
|
if (scriptElement.src) {
|
|
|
this.stats.add("processed", "scripts", 1);
|
|
this.stats.add("processed", "scripts", 1);
|
|
@@ -743,7 +739,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}));
|
|
}));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async frames(initialization) {
|
|
|
|
|
|
|
+ async resolveFrameURLs() {
|
|
|
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 => {
|
|
@@ -753,39 +749,50 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
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) {
|
|
|
- if (initialization) {
|
|
|
|
|
- const options = Object.create(this.options);
|
|
|
|
|
- options.insertSingleFileComment = false;
|
|
|
|
|
- options.insertFaviconLink = false;
|
|
|
|
|
- options.doc = null;
|
|
|
|
|
- options.win = null;
|
|
|
|
|
- options.url = frameData.baseURI;
|
|
|
|
|
- options.windowId = frameWindowId;
|
|
|
|
|
- if (frameData.content) {
|
|
|
|
|
- options.content = frameData.content;
|
|
|
|
|
- options.canvasData = frameData.canvasData;
|
|
|
|
|
- options.stylesheetContents = frameData.stylesheetContents;
|
|
|
|
|
- options.currentSrcImages = frameData.currentSrcImages;
|
|
|
|
|
- options.fontsData = frameData.fontsData;
|
|
|
|
|
- options.imageData = frameData.imageData;
|
|
|
|
|
- options.responsiveImageData = frameData.responsiveImageData;
|
|
|
|
|
- frameData.processor = new PageProcessor(options);
|
|
|
|
|
- frameData.frameElement = frameElement;
|
|
|
|
|
- await frameData.processor.loadPage();
|
|
|
|
|
- await frameData.processor.initialize();
|
|
|
|
|
- frameData.maxResources = this.batchRequest.getMaxResources();
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const options = Object.create(this.options);
|
|
|
|
|
+ options.insertSingleFileComment = false;
|
|
|
|
|
+ options.insertFaviconLink = false;
|
|
|
|
|
+ options.doc = null;
|
|
|
|
|
+ options.win = null;
|
|
|
|
|
+ options.url = frameData.baseURI;
|
|
|
|
|
+ options.windowId = frameWindowId;
|
|
|
|
|
+ if (frameData.content) {
|
|
|
|
|
+ options.content = frameData.content;
|
|
|
|
|
+ options.canvasData = frameData.canvasData;
|
|
|
|
|
+ options.stylesheetContents = frameData.stylesheetContents;
|
|
|
|
|
+ options.currentSrcImages = frameData.currentSrcImages;
|
|
|
|
|
+ options.fontsData = frameData.fontsData;
|
|
|
|
|
+ options.imageData = frameData.imageData;
|
|
|
|
|
+ options.responsiveImageData = frameData.responsiveImageData;
|
|
|
|
|
+ frameData.processor = new PageProcessor(options);
|
|
|
|
|
+ frameData.frameElement = frameElement;
|
|
|
|
|
+ await frameData.processor.loadPage();
|
|
|
|
|
+ await frameData.processor.initialize();
|
|
|
|
|
+ frameData.maxResources = this.batchRequest.getMaxResources();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async processFrames() {
|
|
|
|
|
+ if (this.options.framesData) {
|
|
|
|
|
+ const frameElements = Array.from(this.doc.querySelectorAll("iframe, frame, object[type=\"text/html\"][data]"));
|
|
|
|
|
+ await Promise.all(frameElements.map(async frameElement => {
|
|
|
|
|
+ const frameWindowId = frameElement.getAttribute(DOM.windowIdAttributeName(this.options.sessionId));
|
|
|
|
|
+ if (frameWindowId) {
|
|
|
|
|
+ const frameData = this.options.framesData.find(frame => frame.windowId == frameWindowId);
|
|
|
|
|
+ if (frameData) {
|
|
|
|
|
+ if (frameData.processor) {
|
|
|
|
|
+ this.stats.add("processed", "frames", 1);
|
|
|
|
|
+ await frameData.processor.preparePageData();
|
|
|
|
|
+ const pageData = await frameData.processor.getPageData();
|
|
|
|
|
+ frameElement.removeAttribute(DOM.windowIdAttributeName(this.options.sessionId));
|
|
|
|
|
+ DomProcessorHelper.setFrameContent(frameElement, pageData.content);
|
|
|
|
|
+ this.stats.addAll(pageData);
|
|
|
} else {
|
|
} else {
|
|
|
- if (frameData.processor) {
|
|
|
|
|
- this.stats.add("processed", "frames", 1);
|
|
|
|
|
- await frameData.processor.preparePageData();
|
|
|
|
|
- const pageData = await frameData.processor.getPageData();
|
|
|
|
|
- frameElement.removeAttribute(DOM.windowIdAttributeName(this.options.sessionId));
|
|
|
|
|
- DomProcessorHelper.setFrameContent(frameElement, pageData.content);
|
|
|
|
|
- this.stats.addAll(pageData);
|
|
|
|
|
- } else {
|
|
|
|
|
- this.stats.add("discarded", "frames", 1);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ this.stats.add("discarded", "frames", 1);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -793,57 +800,56 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async htmlImports(initialization) {
|
|
|
|
|
|
|
+ async resolveHtmlImportURLs() {
|
|
|
const linkElements = Array.from(this.doc.querySelectorAll("link[rel=import][href]"));
|
|
const linkElements = Array.from(this.doc.querySelectorAll("link[rel=import][href]"));
|
|
|
if (!this.relImportProcessors) {
|
|
if (!this.relImportProcessors) {
|
|
|
this.relImportProcessors = new Map();
|
|
this.relImportProcessors = new Map();
|
|
|
}
|
|
}
|
|
|
await Promise.all(linkElements.map(async linkElement => {
|
|
await Promise.all(linkElements.map(async linkElement => {
|
|
|
- if (initialization) {
|
|
|
|
|
- const resourceURL = linkElement.href;
|
|
|
|
|
- const options = Object.create(this.options);
|
|
|
|
|
- options.insertSingleFileComment = false;
|
|
|
|
|
- options.insertFaviconLink = false;
|
|
|
|
|
- options.doc = null;
|
|
|
|
|
- options.win = null;
|
|
|
|
|
- options.url = resourceURL;
|
|
|
|
|
- if (resourceURL) {
|
|
|
|
|
- if (resourceURL && resourceURL != this.baseURI && DomUtil.testValidPath(resourceURL)) {
|
|
|
|
|
- const processor = new PageProcessor(options);
|
|
|
|
|
- this.relImportProcessors.set(linkElement, processor);
|
|
|
|
|
- await processor.loadPage();
|
|
|
|
|
- return processor.initialize();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- linkElement.setAttribute("href", EMPTY_DATA_URI);
|
|
|
|
|
- const processor = this.relImportProcessors.get(linkElement);
|
|
|
|
|
- if (processor) {
|
|
|
|
|
- this.stats.add("processed", "HTML imports", 1);
|
|
|
|
|
- this.relImportProcessors.delete(linkElement);
|
|
|
|
|
- const pageData = await processor.getPageData();
|
|
|
|
|
- linkElement.setAttribute("href", "data:text/html," + pageData.content);
|
|
|
|
|
- this.stats.addAll(pageData);
|
|
|
|
|
- } else {
|
|
|
|
|
- this.stats.add("discarded", "HTML imports", 1);
|
|
|
|
|
|
|
+ const resourceURL = linkElement.href;
|
|
|
|
|
+ linkElement.setAttribute("href", EMPTY_DATA_URI);
|
|
|
|
|
+ const options = Object.create(this.options);
|
|
|
|
|
+ options.insertSingleFileComment = false;
|
|
|
|
|
+ options.insertFaviconLink = false;
|
|
|
|
|
+ options.doc = null;
|
|
|
|
|
+ options.win = null;
|
|
|
|
|
+ options.url = resourceURL;
|
|
|
|
|
+ if (resourceURL) {
|
|
|
|
|
+ if (resourceURL && resourceURL != this.baseURI && DomUtil.testValidPath(resourceURL)) {
|
|
|
|
|
+ const processor = new PageProcessor(options);
|
|
|
|
|
+ this.relImportProcessors.set(linkElement, processor);
|
|
|
|
|
+ await processor.loadPage();
|
|
|
|
|
+ return processor.initialize();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}));
|
|
}));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async attributeStyles(initialization) {
|
|
|
|
|
- await Promise.all(Array.from(this.doc.querySelectorAll("[style]")).map(async element => {
|
|
|
|
|
- let stylesheetContent = element.getAttribute("style");
|
|
|
|
|
- if (initialization) {
|
|
|
|
|
- stylesheetContent = DomProcessorHelper.resolveStylesheetURLs(stylesheetContent, this.baseURI);
|
|
|
|
|
|
|
+ async processHtmlImports() {
|
|
|
|
|
+ const linkElements = Array.from(this.doc.querySelectorAll("link[rel=import][href]"));
|
|
|
|
|
+ await Promise.all(linkElements.map(async linkElement => {
|
|
|
|
|
+ const processor = this.relImportProcessors.get(linkElement);
|
|
|
|
|
+ if (processor) {
|
|
|
|
|
+ this.stats.add("processed", "HTML imports", 1);
|
|
|
|
|
+ this.relImportProcessors.delete(linkElement);
|
|
|
|
|
+ const pageData = await processor.getPageData();
|
|
|
|
|
+ linkElement.setAttribute("href", "data:text/html," + pageData.content);
|
|
|
|
|
+ this.stats.addAll(pageData);
|
|
|
} else {
|
|
} else {
|
|
|
- stylesheetContent = await DomProcessorHelper.processStylesheet(element.getAttribute("style"), this.baseURI, this.options, true, 0, this.batchRequest);
|
|
|
|
|
|
|
+ this.stats.add("discarded", "HTML imports", 1);
|
|
|
}
|
|
}
|
|
|
- element.setAttribute("style", stylesheetContent);
|
|
|
|
|
}));
|
|
}));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async linkStylesheets() {
|
|
|
|
|
|
|
+ async resolveStyleAttributeURLs() {
|
|
|
|
|
+ await Promise.all(Array.from(this.doc.querySelectorAll("[style]")).map(async element => element.setAttribute("style", DomProcessorHelper.resolveStylesheetURLs(element.getAttribute("style"), this.baseURI))));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async processStyleAttributes() {
|
|
|
|
|
+ await Promise.all(Array.from(this.doc.querySelectorAll("[style]")).map(async element => element.setAttribute("style", await DomProcessorHelper.processStylesheet(element.getAttribute("style"), this.baseURI, this.options, true, 0, this.batchRequest))));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async resolveLinkedStylesheetURLs() {
|
|
|
await Promise.all(Array.from(this.doc.querySelectorAll("link[rel*=stylesheet]")).map(async linkElement => {
|
|
await Promise.all(Array.from(this.doc.querySelectorAll("link[rel*=stylesheet]")).map(async linkElement => {
|
|
|
const stylesheetContent = await DomProcessorHelper.resolveLinkStylesheetURLs(linkElement.href, this.baseURI, linkElement.media, { maxResourceSize: this.options.maxResourceSize, maxResourceSizeEnabled: this.options.maxResourceSizeEnabled });
|
|
const stylesheetContent = await DomProcessorHelper.resolveLinkStylesheetURLs(linkElement.href, this.baseURI, linkElement.media, { maxResourceSize: this.options.maxResourceSize, maxResourceSizeEnabled: this.options.maxResourceSizeEnabled });
|
|
|
const styleElement = this.doc.createElement("style");
|
|
const styleElement = this.doc.createElement("style");
|