single-file-core 1.0.53 → 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 -24
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "single-file-core",
3
- "version": "1.0.53",
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,28 +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
- const element = doc.createElement(resourceElement.tagName);
1806
- element.setAttribute(attributeName, content);
1807
- element.onload = () => resolve();
1808
- element.onerror = () => resolve(true);
1809
- });
1810
- }
1811
- if (!forbiddenPrefixFound) {
1812
- const isSVG = content.startsWith(PREFIX_DATA_URI_IMAGE_SVG);
1813
- const maxSizeDuplicateImages = options.maxSizeDuplicateImages || SINGLE_FILE_VARIABLE_MAX_SIZE;
1814
- if (expectedType == "image" && processDuplicates && duplicate && !isSVG && util.getContentSize(content) < maxSizeDuplicateImages) {
1815
- if (ProcessorHelper.replaceImageSource(resourceElement, SINGLE_FILE_VARIABLE_NAME_PREFIX + indexResource, options)) {
1816
- cssVariables.set(indexResource, { content, url: originURL });
1817
- const declarationList = cssTree.parse(resourceElement.getAttribute("style"), { context: "declarationList", parseCustomProperty: true });
1818
- 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
+ }
1819
1834
  } else {
1820
1835
  resourceElement.setAttribute(attributeName, content);
1821
1836
  }
1822
- } else {
1823
- resourceElement.setAttribute(attributeName, content);
1824
1837
  }
1838
+ } else {
1839
+ resourceElement.setAttribute(attributeName, content);
1825
1840
  }
1826
1841
  }
1827
1842
  }