single-file-core 1.1.77 → 1.1.78

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.
@@ -0,0 +1,13 @@
1
+ const SINGLE_FILE_PREFIX = "single-file-";
2
+ const COMMENT_HEADER = "Page saved with SingleFile";
3
+ const SINGLE_FILE_SIGNATURE = "SingleFile";
4
+ const WAIT_FOR_USERSCRIPT_PROPERTY_NAME = "_singleFile_waitForUserScript";
5
+ const MESSAGE_PREFIX = "__frameTree__::";
6
+
7
+ export {
8
+ SINGLE_FILE_PREFIX,
9
+ COMMENT_HEADER,
10
+ SINGLE_FILE_SIGNATURE,
11
+ WAIT_FOR_USERSCRIPT_PROPERTY_NAME,
12
+ MESSAGE_PREFIX
13
+ };
package/core/helper.js CHANGED
@@ -26,31 +26,38 @@
26
26
  import * as cssUnescape from "./../vendor/css-unescape.js";
27
27
  import * as hooksFrames from "./../processors/hooks/content/content-hooks-frames.js";
28
28
  import * as infobar from "./infobar.js";
29
+ import {
30
+ SINGLE_FILE_PREFIX,
31
+ COMMENT_HEADER,
32
+ WAIT_FOR_USERSCRIPT_PROPERTY_NAME,
33
+ MESSAGE_PREFIX
34
+ } from "./constants.js";
29
35
 
30
- const ON_BEFORE_CAPTURE_EVENT_NAME = "single-file-on-before-capture";
31
- const ON_AFTER_CAPTURE_EVENT_NAME = "single-file-on-after-capture";
32
- const GET_ADOPTED_STYLESHEETS_REQUEST_EVENT = "single-file-request-get-adopted-stylesheets";
33
- const UNREGISTER_GET_ADOPTED_STYLESHEETS_REQUEST_EVENT = "single-file-unregister-request-get-adopted-stylesheets";
34
- const GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT = "single-file-response-get-adopted-stylesheets";
35
- const REMOVED_CONTENT_ATTRIBUTE_NAME = "data-single-file-removed-content";
36
- const HIDDEN_CONTENT_ATTRIBUTE_NAME = "data-single-file-hidden-content";
37
- const KEPT_CONTENT_ATTRIBUTE_NAME = "data-single-file-kept-content";
38
- const HIDDEN_FRAME_ATTRIBUTE_NAME = "data-single-file-hidden-frame";
39
- const PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME = "data-single-file-preserved-space-element";
40
- const SHADOW_ROOT_ATTRIBUTE_NAME = "data-single-file-shadow-root-element";
41
- const WIN_ID_ATTRIBUTE_NAME = "data-single-file-win-id";
42
- const IMAGE_ATTRIBUTE_NAME = "data-single-file-image";
43
- const POSTER_ATTRIBUTE_NAME = "data-single-file-poster";
44
- const VIDEO_ATTRIBUTE_NAME = "data-single-file-video";
45
- const CANVAS_ATTRIBUTE_NAME = "data-single-file-canvas";
46
- const STYLE_ATTRIBUTE_NAME = "data-single-file-movable-style";
47
- const INPUT_VALUE_ATTRIBUTE_NAME = "data-single-file-input-value";
48
- const LAZY_SRC_ATTRIBUTE_NAME = "data-single-file-lazy-loaded-src";
49
- const STYLESHEET_ATTRIBUTE_NAME = "data-single-file-stylesheet";
50
- const DISABLED_NOSCRIPT_ATTRIBUTE_NAME = "data-single-file-disabled-noscript";
51
- const SELECTED_CONTENT_ATTRIBUTE_NAME = "data-single-file-selected-content";
52
- const INVALID_ELEMENT_ATTRIBUTE_NAME = "data-single-file-invalid-element";
53
- const ASYNC_SCRIPT_ATTRIBUTE_NAME = "data-single-file-async-script";
36
+ const ON_BEFORE_CAPTURE_EVENT_NAME = SINGLE_FILE_PREFIX + "on-before-capture";
37
+ const ON_AFTER_CAPTURE_EVENT_NAME = SINGLE_FILE_PREFIX + "on-after-capture";
38
+ const GET_ADOPTED_STYLESHEETS_REQUEST_EVENT = SINGLE_FILE_PREFIX + "request-get-adopted-stylesheets";
39
+ const GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT = SINGLE_FILE_PREFIX + "response-get-adopted-stylesheets";
40
+ const UNREGISTER_GET_ADOPTED_STYLESHEETS_REQUEST_EVENT = SINGLE_FILE_PREFIX + "unregister-request-get-adopted-stylesheets";
41
+ const ON_INIT_USERSCRIPT_EVENT = SINGLE_FILE_PREFIX + "user-script-init";
42
+ const REMOVED_CONTENT_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "removed-content";
43
+ const HIDDEN_CONTENT_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "hidden-content";
44
+ const KEPT_CONTENT_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "kept-content";
45
+ const HIDDEN_FRAME_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "hidden-frame";
46
+ const PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "preserved-space-element";
47
+ const SHADOW_ROOT_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "shadow-root-element";
48
+ const WIN_ID_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "win-id";
49
+ const IMAGE_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "image";
50
+ const POSTER_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "poster";
51
+ const VIDEO_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "video";
52
+ const CANVAS_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "canvas";
53
+ const STYLE_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "movable-style";
54
+ const INPUT_VALUE_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "input-value";
55
+ const LAZY_SRC_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "lazy-loaded-src";
56
+ const STYLESHEET_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "stylesheet";
57
+ const DISABLED_NOSCRIPT_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "disabled-noscript";
58
+ const SELECTED_CONTENT_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "selected-content";
59
+ const INVALID_ELEMENT_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "invalid-element";
60
+ const ASYNC_SCRIPT_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "async-script";
54
61
  const FLOW_ELEMENTS_SELECTOR = "*:not(base):not(link):not(meta):not(noscript):not(script):not(style):not(template):not(title)";
55
62
  const KEPT_TAG_NAMES = ["NOSCRIPT", "DISABLED-NOSCRIPT", "META", "LINK", "STYLE", "TITLE", "TEMPLATE", "SOURCE", "OBJECT", "SCRIPT", "HEAD", "BODY"];
56
63
  const REGEXP_SIMPLE_QUOTES_STRING = /^'(.*?)'$/;
@@ -62,7 +69,6 @@ const FONT_WEIGHTS = {
62
69
  bolder: "700",
63
70
  lighter: "100"
64
71
  };
65
- const COMMENT_HEADER = "Page saved with SingleFile";
66
72
  const COMMENT_HEADER_LEGACY = "Archive processed by SingleFile";
67
73
  const SINGLE_FILE_UI_ELEMENT_CLASS = "single-file-ui-element";
68
74
  const INFOBAR_TAGNAME = infobar.INFOBAR_TAGNAME;
@@ -106,11 +112,13 @@ export {
106
112
  COMMENT_HEADER_LEGACY,
107
113
  SINGLE_FILE_UI_ELEMENT_CLASS,
108
114
  EMPTY_RESOURCE,
109
- INFOBAR_TAGNAME
115
+ INFOBAR_TAGNAME,
116
+ WAIT_FOR_USERSCRIPT_PROPERTY_NAME,
117
+ MESSAGE_PREFIX
110
118
  };
111
119
 
112
120
  function initUserScriptHandler() {
113
- addEventListener("single-file-user-script-init", () => globalThis._singleFile_waitForUserScript = async eventPrefixName => {
121
+ addEventListener(ON_INIT_USERSCRIPT_EVENT, () => globalThis[WAIT_FOR_USERSCRIPT_PROPERTY_NAME] = async eventPrefixName => {
114
122
  const event = new CustomEvent(eventPrefixName + "-request", { cancelable: true });
115
123
  const promiseResponse = new Promise(resolve => addEventListener(eventPrefixName + "-response", resolve));
116
124
  dispatchEvent(event);
@@ -283,9 +291,9 @@ function getResourcesInfo(win, doc, element, options, data, elementHidden, compu
283
291
  const tagName = element.tagName && element.tagName.toUpperCase();
284
292
  if (tagName == "CANVAS") {
285
293
  try {
286
- data.canvases.push({
287
- dataURI: element.toDataURL("image/png", ""),
288
- backgroundColor: computedStyle.getPropertyValue("background-color")
294
+ data.canvases.push({
295
+ dataURI: element.toDataURL("image/png", ""),
296
+ backgroundColor: computedStyle.getPropertyValue("background-color")
289
297
  });
290
298
  element.setAttribute(CANVAS_ATTRIBUTE_NAME, data.canvases.length - 1);
291
299
  data.markedElements.push(element);
package/core/index.js CHANGED
@@ -34,7 +34,7 @@ const Image = globalThis.Image;
34
34
 
35
35
  let util, cssTree;
36
36
 
37
- export {
37
+ export {
38
38
  getClass
39
39
  };
40
40
 
@@ -48,7 +48,7 @@ class SingleFileClass {
48
48
  this.options = options;
49
49
  }
50
50
  async run() {
51
- const waitForUserScript = globalThis._singleFile_waitForUserScript;
51
+ const waitForUserScript = globalThis[util.WAIT_FOR_USERSCRIPT_PROPERTY_NAME];
52
52
  if (this.options.userScriptEnabled && waitForUserScript) {
53
53
  await waitForUserScript(util.ON_BEFORE_CAPTURE_EVENT_NAME);
54
54
  }
@@ -430,7 +430,7 @@ class Processor {
430
430
  }
431
431
  this.maxResources = this.batchRequest.getMaxResources();
432
432
  if (!this.options.saveRawPage && !this.options.removeFrames && this.options.frames) {
433
- this.options.frames.forEach(frameData => (this.maxResources += frameData.maxResources || 0));
433
+ this.options.frames.forEach(frameData => this.maxResources += frameData.maxResources || 0);
434
434
  }
435
435
  this.stats.set("processed", "resources", this.maxResources);
436
436
  }
@@ -448,7 +448,7 @@ class Processor {
448
448
  acceptHeaders: this.options.acceptHeaders,
449
449
  networkTimeout: this.options.networkTimeout
450
450
  });
451
- pageContent = content.data;
451
+ pageContent = content.data || "";
452
452
  }
453
453
  this.doc = util.parseDocContent(pageContent, this.baseURI);
454
454
  if (this.options.saveRawPage) {
@@ -1277,9 +1277,12 @@ class Processor {
1277
1277
  let resourcePromises = processAttributeArgs.map(([selector, attributeName, processDuplicates, removeElementIfMissing]) =>
1278
1278
  ProcessorHelper.processAttribute(this.doc.querySelectorAll(selector), attributeName, this.baseURI, this.options, "image", this.cssVariables, this.styles, this.batchRequest, processDuplicates, removeElementIfMissing)
1279
1279
  );
1280
+ resourcePromises = resourcePromises.concat([
1281
+ ProcessorHelper.processXLinks(this.doc.querySelectorAll("use"), this.doc, this.baseURI, this.options, this.batchRequest),
1282
+ ProcessorHelper.processSrcset(this.doc.querySelectorAll("img[srcset], source[srcset]"), this.baseURI, this.options, this.batchRequest)
1283
+ ]);
1280
1284
  resourcePromises.push(ProcessorHelper.processAttribute(this.doc.querySelectorAll("object[data*=\".pdf\"]"), "data", this.baseURI, this.options, null, this.cssVariables, this.styles, this.batchRequest));
1281
1285
  resourcePromises.push(ProcessorHelper.processAttribute(this.doc.querySelectorAll("embed[src*=\".pdf\"]"), "src", this.baseURI, this.options, null, this.cssVariables, this.styles, this.batchRequest));
1282
- 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)]);
1283
1286
  resourcePromises.push(ProcessorHelper.processAttribute(this.doc.querySelectorAll("audio[src], audio > source[src]"), "src", this.baseURI, this.options, "audio", this.cssVariables, this.styles, this.batchRequest));
1284
1287
  resourcePromises.push(ProcessorHelper.processAttribute(this.doc.querySelectorAll("video[src], video > source[src]"), "src", this.baseURI, this.options, "video", this.cssVariables, this.styles, this.batchRequest));
1285
1288
  await Promise.all(resourcePromises);
@@ -2087,7 +2090,7 @@ function normalizeURL(url) {
2087
2090
  }
2088
2091
  }
2089
2092
 
2090
- function matchCharsetEquals(stylesheetContent, charset = UTF8_CHARSET) {
2093
+ function matchCharsetEquals(stylesheetContent = "", charset = UTF8_CHARSET) {
2091
2094
  const stylesheetCharset = getCharset(stylesheetContent);
2092
2095
  if (stylesheetCharset) {
2093
2096
  return stylesheetCharset == charset.toLowerCase();
@@ -2096,7 +2099,7 @@ function matchCharsetEquals(stylesheetContent, charset = UTF8_CHARSET) {
2096
2099
  }
2097
2100
  }
2098
2101
 
2099
- function getCharset(stylesheetContent) {
2102
+ function getCharset(stylesheetContent = "") {
2100
2103
  const match = stylesheetContent.match(/^@charset\s+"([^"]*)";/i);
2101
2104
  if (match && match[1]) {
2102
2105
  return match[1].toLowerCase().trim();
package/core/infobar.js CHANGED
@@ -23,6 +23,10 @@
23
23
 
24
24
  /* global getComputedStyle, XPathResult, Node */
25
25
 
26
+ import {
27
+ SINGLE_FILE_SIGNATURE,
28
+ } from "./constants.js";
29
+
26
30
  const INFOBAR_TAGNAME = "single-file-infobar";
27
31
  const INFOBAR_STYLES = `
28
32
  .infobar,
@@ -213,7 +217,7 @@ function appendInfobar(doc, options, useShadowRoot) {
213
217
  function extractInfobarData(doc) {
214
218
  const result = doc.evaluate("//comment()", doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
215
219
  let singleFileComment = result && result.singleNodeValue;
216
- if (singleFileComment && singleFileComment.nodeType == Node.COMMENT_NODE && singleFileComment.textContent.includes("SingleFile")) {
220
+ if (singleFileComment && singleFileComment.nodeType == Node.COMMENT_NODE && singleFileComment.textContent.includes(SINGLE_FILE_SIGNATURE)) {
217
221
  const info = singleFileComment.textContent.split("\n");
218
222
  const [, , urlData, ...optionalData] = info;
219
223
  const urlMatch = urlData.match(/^ url: (.*) ?$/);
package/core/util.js CHANGED
@@ -184,7 +184,8 @@ function getInstance(utilOptions) {
184
184
  COMMENT_HEADER_LEGACY: helper.COMMENT_HEADER_LEGACY,
185
185
  SINGLE_FILE_UI_ELEMENT_CLASS: helper.SINGLE_FILE_UI_ELEMENT_CLASS,
186
186
  EMPTY_RESOURCE: helper.EMPTY_RESOURCE,
187
- INFOBAR_TAGNAME: helper.INFOBAR_TAGNAME
187
+ INFOBAR_TAGNAME: helper.INFOBAR_TAGNAME,
188
+ WAIT_FOR_USERSCRIPT_PROPERTY_NAME: helper.WAIT_FOR_USERSCRIPT_PROPERTY_NAME
188
189
  };
189
190
 
190
191
  async function getContent(resourceURL, options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "single-file-core",
3
- "version": "1.1.77",
3
+ "version": "1.1.78",
4
4
  "description": "SingleFile Core",
5
5
  "author": "Gildas Lormeau",
6
6
  "license": "AGPL-3.0-or-later",
@@ -28,6 +28,8 @@ import {
28
28
  ON_BEFORE_CAPTURE_EVENT_NAME,
29
29
  ON_AFTER_CAPTURE_EVENT_NAME,
30
30
  WIN_ID_ATTRIBUTE_NAME,
31
+ WAIT_FOR_USERSCRIPT_PROPERTY_NAME,
32
+ MESSAGE_PREFIX,
31
33
  preProcessDoc,
32
34
  serialize,
33
35
  postProcessDoc,
@@ -38,13 +40,13 @@ const helper = {
38
40
  ON_BEFORE_CAPTURE_EVENT_NAME,
39
41
  ON_AFTER_CAPTURE_EVENT_NAME,
40
42
  WIN_ID_ATTRIBUTE_NAME,
43
+ WAIT_FOR_USERSCRIPT_PROPERTY_NAME,
41
44
  preProcessDoc,
42
45
  serialize,
43
46
  postProcessDoc,
44
47
  getShadowRoot
45
48
  };
46
49
 
47
- const MESSAGE_PREFIX = "__frameTree__::";
48
50
  const FRAMES_CSS_SELECTOR = "iframe, frame, object[type=\"text/html\"][data]";
49
51
  const ALL_ELEMENTS_CSS_SELECTOR = "*";
50
52
  const INIT_REQUEST_MESSAGE = "singlefile.frameTree.initRequest";
@@ -163,7 +165,7 @@ function getNewSessionId() {
163
165
 
164
166
  function initRequestSync(message) {
165
167
  const sessionId = message.sessionId;
166
- const waitForUserScript = globalThis._singleFile_waitForUserScript;
168
+ const waitForUserScript = globalThis[helper.WAIT_FOR_USERSCRIPT_PROPERTY_NAME];
167
169
  delete globalThis._singleFile_cleaningUp;
168
170
  if (!TOP_WINDOW) {
169
171
  windowId = globalThis.frameId = message.windowId;
@@ -183,7 +185,7 @@ function initRequestSync(message) {
183
185
 
184
186
  async function initRequestAsync(message) {
185
187
  const sessionId = message.sessionId;
186
- const waitForUserScript = globalThis._singleFile_waitForUserScript;
188
+ const waitForUserScript = globalThis[helper.WAIT_FOR_USERSCRIPT_PROPERTY_NAME];
187
189
  delete globalThis._singleFile_cleaningUp;
188
190
  if (!TOP_WINDOW) {
189
191
  windowId = globalThis.frameId = message.windowId;