single-file-core 1.0.54 → 1.0.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/single-file-core.js +39 -26
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "single-file-core",
3
- "version": "1.0.54",
3
+ "version": "1.0.55",
4
4
  "description": "SingleFile Core",
5
5
  "author": "Gildas Lormeau",
6
6
  "license": "AGPL-3.0-or-later",
@@ -28,6 +28,9 @@ const DEBUG = false;
28
28
  const Set = globalThis.Set;
29
29
  const Map = globalThis.Map;
30
30
  const JSON = globalThis.JSON;
31
+ const setTimeout = globalThis.setTimeout;
32
+ const clearTimeout = globalThis.clearTimeout;
33
+ const Image = globalThis.Image;
31
34
 
32
35
  let util, cssTree;
33
36
 
@@ -1218,9 +1221,9 @@ class Processor {
1218
1221
  async processPageResources() {
1219
1222
  const processAttributeArgs = [
1220
1223
  ["link[href][rel*=\"icon\"]", "href", false, true],
1221
- ["object[type=\"image/svg+xml\"], object[type=\"image/svg-xml\"], object[data*=\".svg\"], object[data*=\".pdf\"]", "data"],
1224
+ ["object[type=\"image/svg+xml\"], object[type=\"image/svg-xml\"], object[data*=\".svg\"]", "data"],
1222
1225
  ["img[src], input[src][type=image]", "src", true],
1223
- ["embed[src*=\".svg\"], embed[src*=\".pdf\"]", "src"],
1226
+ ["embed[src*=\".svg\"]", "src"],
1224
1227
  ["video[poster]", "poster"],
1225
1228
  ["*[background]", "background"],
1226
1229
  ["image", "xlink:href"],
@@ -1230,11 +1233,13 @@ class Processor {
1230
1233
  this.doc.querySelectorAll("svg").forEach(element => element.remove());
1231
1234
  }
1232
1235
  let resourcePromises = processAttributeArgs.map(([selector, attributeName, processDuplicates, removeElementIfMissing]) =>
1233
- ProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll(selector), attributeName, this.baseURI, this.options, "image", this.cssVariables, this.styles, this.batchRequest, processDuplicates, removeElementIfMissing)
1236
+ ProcessorHelper.processAttribute(this.doc.querySelectorAll(selector), attributeName, this.baseURI, this.options, "image", this.cssVariables, this.styles, this.batchRequest, processDuplicates, removeElementIfMissing)
1234
1237
  );
1238
+ resourcePromises.push(ProcessorHelper.processAttribute(this.doc.querySelectorAll("object[data*=\".pdf\"]"), "data", this.baseURI, this.options, null, this.cssVariables, this.styles, this.batchRequest));
1239
+ resourcePromises.push(ProcessorHelper.processAttribute(this.doc.querySelectorAll("embed[src*=\".pdf\"]"), "src", this.baseURI, this.options, null, this.cssVariables, this.styles, this.batchRequest));
1235
1240
  resourcePromises = resourcePromises.concat([ProcessorHelper.processXLinks(this.doc.querySelectorAll("use"), this.doc, this.baseURI, this.options, this.batchRequest), ProcessorHelper.processSrcset(this.doc.querySelectorAll("img[srcset], source[srcset]"), this.baseURI, this.options, this.batchRequest)]);
1236
- resourcePromises.push(ProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("audio[src], audio > source[src]"), "src", this.baseURI, this.options, "audio", this.cssVariables, this.styles, this.batchRequest));
1237
- resourcePromises.push(ProcessorHelper.processAttribute(this.doc, this.doc.querySelectorAll("video[src], video > source[src]"), "src", this.baseURI, this.options, "video", this.cssVariables, this.styles, this.batchRequest));
1241
+ resourcePromises.push(ProcessorHelper.processAttribute(this.doc.querySelectorAll("audio[src], audio > source[src]"), "src", this.baseURI, this.options, "audio", this.cssVariables, this.styles, this.batchRequest));
1242
+ resourcePromises.push(ProcessorHelper.processAttribute(this.doc.querySelectorAll("video[src], video > source[src]"), "src", this.baseURI, this.options, "video", this.cssVariables, this.styles, this.batchRequest));
1238
1243
  await Promise.all(resourcePromises);
1239
1244
  if (this.options.saveFavicon) {
1240
1245
  ProcessorHelper.processShortcutIcons(this.doc);
@@ -1747,7 +1752,7 @@ class ProcessorHelper {
1747
1752
  }));
1748
1753
  }
1749
1754
 
1750
- static async processAttribute(doc, resourceElements, attributeName, baseURI, options, expectedType, cssVariables, styles, batchRequest, processDuplicates, removeElementIfMissing) {
1755
+ static async processAttribute(resourceElements, attributeName, baseURI, options, expectedType, cssVariables, styles, batchRequest, processDuplicates, removeElementIfMissing) {
1751
1756
  await Promise.all(Array.from(resourceElements).map(async resourceElement => {
1752
1757
  let resourceURL = resourceElement.getAttribute(attributeName);
1753
1758
  if (resourceURL != null) {
@@ -1800,30 +1805,38 @@ class ProcessorHelper {
1800
1805
  resourceElement.remove();
1801
1806
  } else if (content !== util.EMPTY_RESOURCE) {
1802
1807
  let forbiddenPrefixFound = PREFIXES_FORBIDDEN_DATA_URI.filter(prefixDataURI => content.startsWith(prefixDataURI)).length;
1803
- if (forbiddenPrefixFound) {
1804
- forbiddenPrefixFound = await new Promise((resolve) => {
1805
- // eslint-disable-next-line no-undef
1806
- globalThis,setTimeout(() => resolve(), 2000);
1807
- const element = doc.createElement(resourceElement.tagName);
1808
- element.setAttribute(attributeName, content);
1809
- element.onload = () => resolve();
1810
- element.onerror = () => resolve(true);
1811
- });
1812
- }
1813
- if (!forbiddenPrefixFound) {
1814
- const isSVG = content.startsWith(PREFIX_DATA_URI_IMAGE_SVG);
1815
- const maxSizeDuplicateImages = options.maxSizeDuplicateImages || SINGLE_FILE_VARIABLE_MAX_SIZE;
1816
- if (expectedType == "image" && processDuplicates && duplicate && !isSVG && util.getContentSize(content) < maxSizeDuplicateImages) {
1817
- if (ProcessorHelper.replaceImageSource(resourceElement, SINGLE_FILE_VARIABLE_NAME_PREFIX + indexResource, options)) {
1818
- cssVariables.set(indexResource, { content, url: originURL });
1819
- const declarationList = cssTree.parse(resourceElement.getAttribute("style"), { context: "declarationList", parseCustomProperty: true });
1820
- styles.set(resourceElement, declarationList);
1808
+ if (expectedType == "image") {
1809
+ if (forbiddenPrefixFound && Image) {
1810
+ forbiddenPrefixFound = await new Promise((resolve) => {
1811
+ const image = new Image();
1812
+ const timeoutId = setTimeout(() => resolve(true), 100);
1813
+ image.src = content;
1814
+ image.onload = () => cleanupAndResolve();
1815
+ image.onerror = () => cleanupAndResolve(true);
1816
+
1817
+ function cleanupAndResolve(value) {
1818
+ clearTimeout(timeoutId);
1819
+ resolve(value);
1820
+ }
1821
+ });
1822
+ }
1823
+ if (!forbiddenPrefixFound) {
1824
+ const isSVG = content.startsWith(PREFIX_DATA_URI_IMAGE_SVG);
1825
+ const maxSizeDuplicateImages = options.maxSizeDuplicateImages || SINGLE_FILE_VARIABLE_MAX_SIZE;
1826
+ if (processDuplicates && duplicate && !isSVG && util.getContentSize(content) < maxSizeDuplicateImages) {
1827
+ if (ProcessorHelper.replaceImageSource(resourceElement, SINGLE_FILE_VARIABLE_NAME_PREFIX + indexResource, options)) {
1828
+ cssVariables.set(indexResource, { content, url: originURL });
1829
+ const declarationList = cssTree.parse(resourceElement.getAttribute("style"), { context: "declarationList", parseCustomProperty: true });
1830
+ styles.set(resourceElement, declarationList);
1831
+ } else {
1832
+ resourceElement.setAttribute(attributeName, content);
1833
+ }
1821
1834
  } else {
1822
1835
  resourceElement.setAttribute(attributeName, content);
1823
1836
  }
1824
- } else {
1825
- resourceElement.setAttribute(attributeName, content);
1826
1837
  }
1838
+ } else {
1839
+ resourceElement.setAttribute(attributeName, content);
1827
1840
  }
1828
1841
  }
1829
1842
  }