|
|
@@ -653,21 +653,21 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
|
|
|
async pageResources() {
|
|
|
const resourcePromises = [
|
|
|
- DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("link[href][rel*=\"icon\"]"), "href", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest, this.options, false, true),
|
|
|
- DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("object[type=\"image/svg+xml\"], object[type=\"image/svg-xml\"]"), "data", PREFIX_DATA_URI_IMAGE_SVG, this.baseURI, this.batchRequest, this.options),
|
|
|
- DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("img[src], input[src][type=image]"), "src", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest, this.options, true),
|
|
|
- DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("embed[src*=\".svg\"]"), "src", PREFIX_DATA_URI_IMAGE_SVG, this.baseURI, this.batchRequest, this.options),
|
|
|
- DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("video[poster]"), "poster", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest, this.options),
|
|
|
- DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("*[background]"), "background", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest, this.options),
|
|
|
- DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("image"), "xlink:href", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest, this.options),
|
|
|
- DomProcessorHelper.processXLinks(this.doc, this.doc.querySelectorAll("use"), this.baseURI, this.batchRequest),
|
|
|
- DomProcessorHelper.processSrcset(this.doc, this.doc.querySelectorAll("img[srcset], source[srcset]"), "srcset", PREFIX_DATA_URI_IMAGE, this.baseURI, this.batchRequest)
|
|
|
+ DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("link[href][rel*=\"icon\"]"), "href", PREFIX_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest, false, true),
|
|
|
+ DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("object[type=\"image/svg+xml\"], object[type=\"image/svg-xml\"]"), "data", PREFIX_DATA_URI_IMAGE_SVG, this.baseURI, this.options, this.batchRequest),
|
|
|
+ DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("img[src], input[src][type=image]"), "src", PREFIX_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest, true),
|
|
|
+ DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("embed[src*=\".svg\"]"), "src", PREFIX_DATA_URI_IMAGE_SVG, this.baseURI, this.options, this.batchRequest),
|
|
|
+ DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("video[poster]"), "poster", PREFIX_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest),
|
|
|
+ DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("*[background]"), "background", PREFIX_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest),
|
|
|
+ DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("image"), "xlink:href", PREFIX_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest),
|
|
|
+ DomProcessorHelper.processXLinks(this.doc.querySelectorAll("use"), this.baseURI, this.options, this.batchRequest),
|
|
|
+ DomProcessorHelper.processSrcset(this.doc.querySelectorAll("img[srcset], source[srcset]"), "srcset", PREFIX_DATA_URI_IMAGE, this.baseURI, this.options, this.batchRequest)
|
|
|
];
|
|
|
if (!this.options.removeAudioSrc) {
|
|
|
- resourcePromises.push(DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("audio[src], audio > source[src]"), "src", PREFIX_DATA_URI_AUDIO, this.baseURI, this.batchRequest, this.options));
|
|
|
+ resourcePromises.push(DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("audio[src], audio > source[src]"), "src", PREFIX_DATA_URI_AUDIO, this.baseURI, this.options, this.batchRequest));
|
|
|
}
|
|
|
if (!this.options.removeVideoSrc) {
|
|
|
- resourcePromises.push(DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("video[src], video > source[src]"), "src", PREFIX_DATA_URI_VIDEO, this.baseURI, this.batchRequest, this.options));
|
|
|
+ resourcePromises.push(DomProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("video[src], video > source[src]"), "src", PREFIX_DATA_URI_VIDEO, this.baseURI, this.options, this.batchRequest));
|
|
|
}
|
|
|
await resourcePromises;
|
|
|
if (this.options.removeAlternativeImages) {
|
|
|
@@ -685,7 +685,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
|
|
|
|
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 })));
|
|
|
+ await Promise.all(Array.from(this.doc.querySelectorAll("style")).map(async styleElement => styleElement.textContent = await DomProcessorHelper.resolveImportURLs(styleElement.textContent, this.baseURI, { url: this.options.url, maxResourceSize: this.options.maxResourceSize, maxResourceSizeEnabled: this.options.maxResourceSizeEnabled })));
|
|
|
}
|
|
|
|
|
|
async processStylesheets() {
|
|
|
@@ -781,7 +781,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
options.doc = null;
|
|
|
options.win = null;
|
|
|
options.url = resourceURL;
|
|
|
- if (!DomUtil.testIgnoredPath(resourceURL) && DomUtil.testValidPath(resourceURL, this.baseURI)) {
|
|
|
+ if (!DomUtil.testIgnoredPath(resourceURL) && DomUtil.testValidPath(resourceURL, this.baseURI, this.options.url)) {
|
|
|
const processor = new PageProcessor(options);
|
|
|
this.relImportProcessors.set(linkElement, processor);
|
|
|
await processor.loadPage();
|
|
|
@@ -807,7 +807,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
|
|
|
|
resolveStyleAttributeURLs() {
|
|
|
- Array.from(this.doc.querySelectorAll("[style]")).map(element => element.setAttribute("style", DomProcessorHelper.resolveStylesheetURLs(element.getAttribute("style"), this.baseURI)));
|
|
|
+ Array.from(this.doc.querySelectorAll("[style]")).map(element => element.setAttribute("style", DomProcessorHelper.resolveStylesheetURLs(element.getAttribute("style"), this.baseURI, this.options)));
|
|
|
}
|
|
|
|
|
|
async processStyleAttributes() {
|
|
|
@@ -965,16 +965,16 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
|
|
|
|
static async resolveImportURLs(stylesheetContent, baseURI, options) {
|
|
|
- stylesheetContent = DomProcessorHelper.resolveStylesheetURLs(stylesheetContent, baseURI);
|
|
|
+ stylesheetContent = DomProcessorHelper.resolveStylesheetURLs(stylesheetContent, baseURI, options);
|
|
|
stylesheetContent = DomUtil.removeCssComments(stylesheetContent);
|
|
|
const imports = DomUtil.getImportFunctions(stylesheetContent);
|
|
|
await Promise.all(imports.map(async cssImport => {
|
|
|
const match = DomUtil.matchImport(cssImport);
|
|
|
if (match) {
|
|
|
let resourceURL = DomUtil.normalizeURL(match.resourceURL);
|
|
|
- if (!DomUtil.testIgnoredPath(resourceURL) && DomUtil.testValidPath(resourceURL)) {
|
|
|
+ if (!DomUtil.testIgnoredPath(resourceURL) && DomUtil.testValidPath(resourceURL, baseURI, options.url)) {
|
|
|
resourceURL = new URL(match.resourceURL, baseURI).href;
|
|
|
- if (DomUtil.testValidURL(resourceURL, baseURI)) {
|
|
|
+ if (DomUtil.testValidURL(resourceURL, baseURI, options.url)) {
|
|
|
let importedStylesheetContent = await Download.getContent(resourceURL, { asDataURI: false, maxResourceSize: options.maxResourceSize, maxResourceSizeEnabled: options.maxResourceSizeEnabled });
|
|
|
importedStylesheetContent = DomUtil.wrapMediaQuery(importedStylesheetContent, match.media);
|
|
|
if (stylesheetContent.includes(cssImport)) {
|
|
|
@@ -988,15 +988,15 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
return stylesheetContent;
|
|
|
}
|
|
|
|
|
|
- static resolveStylesheetURLs(stylesheetContent, baseURI) {
|
|
|
+ static resolveStylesheetURLs(stylesheetContent, baseURI, options) {
|
|
|
const urlFunctions = DomUtil.getUrlFunctions(stylesheetContent);
|
|
|
urlFunctions.map(urlFunction => {
|
|
|
const originalResourceURL = DomUtil.matchURL(urlFunction);
|
|
|
const resourceURL = DomUtil.normalizeURL(originalResourceURL);
|
|
|
if (!DomUtil.testIgnoredPath(resourceURL)) {
|
|
|
- if (DomUtil.testValidPath(resourceURL, baseURI)) {
|
|
|
+ if (DomUtil.testValidPath(resourceURL, baseURI, options.url)) {
|
|
|
const resolvedURL = new URL(resourceURL, baseURI).href;
|
|
|
- if (DomUtil.testValidURL(resolvedURL, baseURI) && resourceURL != resolvedURL && stylesheetContent.includes(urlFunction)) {
|
|
|
+ if (DomUtil.testValidURL(resolvedURL, baseURI, options.url) && resourceURL != resolvedURL && stylesheetContent.includes(urlFunction)) {
|
|
|
stylesheetContent = stylesheetContent.replace(DomUtil.getRegExp(urlFunction), urlFunction.replace(originalResourceURL, resolvedURL));
|
|
|
}
|
|
|
}
|
|
|
@@ -1029,7 +1029,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
const originalResourceURL = DomUtil.matchURL(urlFunction);
|
|
|
const resourceURL = DomUtil.normalizeURL(originalResourceURL);
|
|
|
if (!DomUtil.testIgnoredPath(resourceURL)) {
|
|
|
- if (DomUtil.testValidURL(resourceURL, baseURI) && stylesheetContent.includes(urlFunction)) {
|
|
|
+ if (DomUtil.testValidURL(resourceURL, baseURI, options.url) && stylesheetContent.includes(urlFunction)) {
|
|
|
const { content, indexResource, duplicate } = await batchRequest.addURL(resourceURL);
|
|
|
urlFunction = "url(" + JSON.stringify(resourceURL) + ")";
|
|
|
const regExpUrlFunction = DomUtil.getRegExp(urlFunction);
|
|
|
@@ -1069,7 +1069,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
const originalResourceURL = DomUtil.matchURL(urlFunction);
|
|
|
const resourceURL = DomUtil.normalizeURL(originalResourceURL);
|
|
|
if (!DomUtil.testIgnoredPath(resourceURL)) {
|
|
|
- if (DomUtil.testValidURL(resourceURL, baseURI) && cssText.includes(urlFunction)) {
|
|
|
+ if (DomUtil.testValidURL(resourceURL, baseURI, options.url) && cssText.includes(urlFunction)) {
|
|
|
const resourceInfo = resourceInfos.get(resourceURL);
|
|
|
if (options.groupDuplicateImages && resourceInfo.variableName && !preventGrouping) {
|
|
|
cssText = cssText.replace(resourceInfo.regExpUrlFunction, resourceInfo.variableName);
|
|
|
@@ -1084,15 +1084,15 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- static async processAttribute(doc, resourceElements, attributeName, prefixDataURI, baseURI, batchRequest, options, processDuplicates, removeElementIfMissing) {
|
|
|
+ static async processAttribute(doc, resourceElements, attributeName, prefixDataURI, baseURI, options, batchRequest, processDuplicates, removeElementIfMissing) {
|
|
|
await Promise.all(Array.from(resourceElements).map(async resourceElement => {
|
|
|
let resourceURL = resourceElement.getAttribute(attributeName);
|
|
|
resourceURL = DomUtil.normalizeURL(resourceURL);
|
|
|
if (!DomUtil.testIgnoredPath(resourceURL)) {
|
|
|
resourceElement.setAttribute(attributeName, EMPTY_IMAGE);
|
|
|
- if (DomUtil.testValidPath(resourceURL, baseURI)) {
|
|
|
+ if (DomUtil.testValidPath(resourceURL, baseURI, options.url)) {
|
|
|
resourceURL = new URL(resourceURL, baseURI).href;
|
|
|
- if (DomUtil.testValidURL(resourceURL, baseURI)) {
|
|
|
+ if (DomUtil.testValidURL(resourceURL, baseURI, options.url)) {
|
|
|
const { content, indexResource, duplicate } = await batchRequest.addURL(resourceURL);
|
|
|
if (removeElementIfMissing && content == EMPTY_DATA_URI) {
|
|
|
resourceElement.remove();
|
|
|
@@ -1111,20 +1111,20 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}));
|
|
|
}
|
|
|
|
|
|
- static async processXLinks(doc, resourceElements, baseURI, batchRequest) {
|
|
|
+ static async processXLinks(resourceElements, baseURI, options, batchRequest) {
|
|
|
const attributeName = "xlink:href";
|
|
|
await Promise.all(Array.from(resourceElements).map(async resourceElement => {
|
|
|
const originalResourceURL = resourceElement.getAttribute(attributeName);
|
|
|
let resourceURL = DomUtil.normalizeURL(originalResourceURL);
|
|
|
- if (DomUtil.testValidPath(resourceURL) && !DomUtil.testIgnoredPath(resourceURL)) {
|
|
|
+ if (DomUtil.testValidPath(resourceURL, baseURI, options.url) && !DomUtil.testIgnoredPath(resourceURL)) {
|
|
|
resourceElement.setAttribute(attributeName, EMPTY_IMAGE);
|
|
|
resourceURL = new URL(resourceURL, baseURI).href;
|
|
|
- if (DomUtil.testValidURL(resourceURL, baseURI)) {
|
|
|
+ if (DomUtil.testValidURL(resourceURL, baseURI, options.url)) {
|
|
|
try {
|
|
|
const { content } = await batchRequest.addURL(resourceURL, false);
|
|
|
const DOMParser = DOM.getParser();
|
|
|
if (DOMParser) {
|
|
|
- const svgDoc = new DOMParser().parseFromString(content, "image/svg+xml");
|
|
|
+ let svgDoc = new DOMParser().parseFromString(content, "image/svg+xml");
|
|
|
const hashMatch = originalResourceURL.match(REGEXP_URL_HASH);
|
|
|
if (hashMatch && hashMatch[0]) {
|
|
|
const symbolElement = svgDoc.querySelector(hashMatch[0]);
|
|
|
@@ -1142,19 +1142,21 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
/* ignored */
|
|
|
}
|
|
|
}
|
|
|
+ } else if (resourceURL == options.url) {
|
|
|
+ resourceElement.setAttribute(attributeName, originalResourceURL.substring(resourceURL.length));
|
|
|
}
|
|
|
}));
|
|
|
}
|
|
|
|
|
|
- static async processSrcset(doc, resourceElements, attributeName, prefixDataURI, baseURI, batchRequest) {
|
|
|
+ static async processSrcset(resourceElements, attributeName, prefixDataURI, baseURI, options, batchRequest) {
|
|
|
await Promise.all(Array.from(resourceElements).map(async resourceElement => {
|
|
|
const srcset = DOM.parseSrcset(resourceElement.getAttribute(attributeName));
|
|
|
const srcsetValues = await Promise.all(srcset.map(async srcsetValue => {
|
|
|
let resourceURL = DomUtil.normalizeURL(srcsetValue.url);
|
|
|
if (!DomUtil.testIgnoredPath(resourceURL)) {
|
|
|
- if (DomUtil.testValidPath(resourceURL)) {
|
|
|
+ if (DomUtil.testValidPath(resourceURL, baseURI, options.url)) {
|
|
|
resourceURL = new URL(resourceURL, baseURI).href;
|
|
|
- if (DomUtil.testValidURL(resourceURL, baseURI)) {
|
|
|
+ if (DomUtil.testValidURL(resourceURL, baseURI, options.url)) {
|
|
|
const { content } = await batchRequest.addURL(resourceURL);
|
|
|
if (!content.startsWith(prefixDataURI) && !content.startsWith(PREFIX_DATA_URI_NO_MIMETYPE) && !content.startsWith(PREFIX_DATA_URI_OCTET_STREAM)) {
|
|
|
resourceElement.setAttribute(attributeName, EMPTY_IMAGE);
|
|
|
@@ -1258,12 +1260,12 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
return resourceURL && (resourceURL.startsWith(DATA_URI_PREFIX) || resourceURL.startsWith(BLOB_URI_PREFIX) || resourceURL == ABOUT_BLANK_URI);
|
|
|
}
|
|
|
|
|
|
- static testValidPath(resourceURL, baseURI) {
|
|
|
- return resourceURL && resourceURL != baseURI && !resourceURL.match(EMPTY_URL);
|
|
|
+ static testValidPath(resourceURL, baseURI, docURL) {
|
|
|
+ return resourceURL && resourceURL != baseURI && resourceURL != docURL && !resourceURL.match(EMPTY_URL);
|
|
|
}
|
|
|
|
|
|
- static testValidURL(resourceURL, baseURI) {
|
|
|
- return DomUtil.testValidPath(resourceURL, baseURI) && (resourceURL.match(HTTP_URI_PREFIX) || resourceURL.match(FILE_URI_PREFIX)) && resourceURL.match(NOT_EMPTY_URL);
|
|
|
+ static testValidURL(resourceURL, baseURI, docURL) {
|
|
|
+ return DomUtil.testValidPath(resourceURL, baseURI, docURL) && (resourceURL.match(HTTP_URI_PREFIX) || resourceURL.match(FILE_URI_PREFIX)) && resourceURL.match(NOT_EMPTY_URL);
|
|
|
}
|
|
|
|
|
|
static matchImport(stylesheetContent) {
|