single-file-core 1.0.69 → 1.0.71

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.
package/common/infobar.js CHANGED
@@ -143,7 +143,12 @@ export { displayIcon, appendInfobar, refreshInfobarInfo, extractInfobarData, INF
143
143
 
144
144
  function appendInfobar(doc, options, useShadowRoot) {
145
145
  if (!doc.querySelector(INFOBAR_TAGNAME)) {
146
- let infoData = options.infobarContent ? options.infobarContent : options.saveDate;
146
+ let infoData;
147
+ if (options.infobarContent) {
148
+ infoData = options.infobarContent.replace(/\\n/g, "\n").replace(/\\t/g, "\t");
149
+ } else if (options.saveDate) {
150
+ infoData = options.saveDate;
151
+ }
147
152
  infoData = infoData || "No info";
148
153
  const infobarElement = createElement(doc, INFOBAR_TAGNAME, doc.body);
149
154
  let infobarContainer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "single-file-core",
3
- "version": "1.0.69",
3
+ "version": "1.0.71",
4
4
  "description": "SingleFile Core",
5
5
  "author": "Gildas Lormeau",
6
6
  "license": "AGPL-3.0-or-later",
@@ -238,6 +238,7 @@ function initResponse(message) {
238
238
  frameData.processed = messageFrameData.processed;
239
239
  frameData.scrollPosition = messageFrameData.scrollPosition;
240
240
  frameData.scrolling = messageFrameData.scrolling;
241
+ frameData.adoptedStyleSheets = messageFrameData.adoptedStyleSheets;
241
242
  }
242
243
  });
243
244
  const remainingFrames = windowData.frames.filter(frameData => !frameData.processed).length;
@@ -407,6 +408,7 @@ function getFrameData(document, globalThis, windowId, options, scrolling) {
407
408
  shadowRoots: docData.shadowRoots,
408
409
  scrollPosition: docData.scrollPosition,
409
410
  scrolling,
411
+ adoptedStyleSheets: docData.adoptedStyleSheets,
410
412
  processed: true
411
413
  };
412
414
  }
@@ -44,6 +44,7 @@
44
44
  const FETCH_ACK_EVENT = "single-file-ack-fetch";
45
45
  const FETCH_RESPONSE_EVENT = "single-file-response-fetch";
46
46
  const GET_ADOPTED_STYLESHEETS_REQUEST_EVENT = "single-file-request-get-adopted-stylesheets";
47
+ const UNREGISTER_GET_ADOPTED_STYLESHEETS_REQUEST_EVENT = "single-file-unregister-request-get-adopted-stylesheets";
47
48
  const GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT = "single-file-response-get-adopted-stylesheets";
48
49
  const NEW_FONT_FACE_EVENT = "single-file-new-font-face";
49
50
  const DELETE_FONT_EVENT = "single-file-delete-font";
@@ -312,15 +313,7 @@
312
313
  dispatchEvent(new CustomEvent(FETCH_RESPONSE_EVENT, { detail }));
313
314
  });
314
315
 
315
- addEventListener(GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, event => {
316
- const shadowRoot = event.target.shadowRoot;
317
- if (shadowRoot) {
318
- const adoptedStyleSheets = Array.from(shadowRoot.adoptedStyleSheets).map(stylesheet => Array.from(stylesheet.cssRules).map(cssRule => cssRule.cssText).join("\n"));
319
- if (adoptedStyleSheets.length) {
320
- event.target.dispatchEvent(new CustomEvent(GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT, { detail: { adoptedStyleSheets } }));
321
- }
322
- }
323
- }, { capture: true });
316
+ addEventListener(GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, getAdoptedStylesheetsListener);
324
317
 
325
318
  if (globalThis.FontFace) {
326
319
  const FontFace = globalThis.FontFace;
@@ -385,6 +378,19 @@
385
378
  globalThis.IntersectionObserver.toString = function () { return "function IntersectionObserver() { [native code] }"; };
386
379
  }
387
380
 
381
+ function getAdoptedStylesheetsListener(event) {
382
+ const shadowRoot = event.target.shadowRoot;
383
+ event.stopPropagation();
384
+ if (shadowRoot) {
385
+ shadowRoot.addEventListener(GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, getAdoptedStylesheetsListener, {});
386
+ shadowRoot.addEventListener(UNREGISTER_GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, () => shadowRoot.removeEventListener(getAdoptedStylesheetsListener), { once: true });
387
+ const adoptedStyleSheets = Array.from(shadowRoot.adoptedStyleSheets).map(stylesheet => Array.from(stylesheet.cssRules).map(cssRule => cssRule.cssText).join("\n"));
388
+ if (adoptedStyleSheets.length) {
389
+ event.target.dispatchEvent(new CustomEvent(GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT, { detail: { adoptedStyleSheets } }));
390
+ }
391
+ }
392
+ }
393
+
388
394
  async function getDetailObject(fontFamily, src, descriptors) {
389
395
  const detail = {};
390
396
  detail["font-family"] = fontFamily;
@@ -182,6 +182,7 @@ class Runner {
182
182
  this.options.usedFonts = docData.usedFonts;
183
183
  this.options.shadowRoots = docData.shadowRoots;
184
184
  this.options.referrer = docData.referrer;
185
+ this.options.adoptedStyleSheets = docData.adoptedStyleSheets;
185
186
  this.markedElements = docData.markedElements;
186
187
  this.invalidElements = docData.invalidElements;
187
188
  }
@@ -499,6 +500,10 @@ class Processor {
499
500
  if (legacyInfobarElement) {
500
501
  legacyInfobarElement.remove();
501
502
  }
503
+ const infobarElement = this.doc.querySelector(util.INFOBAR_TAGNAME);
504
+ if (infobarElement) {
505
+ infobarElement.remove();
506
+ }
502
507
  if (this.options.includeInfobar) {
503
508
  util.appendInfobar(this.doc, this.options);
504
509
  }
@@ -621,6 +626,11 @@ class Processor {
621
626
  }
622
627
  });
623
628
  }
629
+ if (this.options.adoptedStyleSheets.length) {
630
+ const styleElement = this.doc.createElement("style");
631
+ styleElement.textContent = this.options.adoptedStyleSheets.join("\n");
632
+ this.doc.body.appendChild(styleElement);
633
+ }
624
634
  }
625
635
 
626
636
  removeUnselectedElements() {
@@ -1158,6 +1168,7 @@ class Processor {
1158
1168
  options.shadowRoots = frameData.shadowRoots;
1159
1169
  options.scrollPosition = frameData.scrollPosition;
1160
1170
  options.scrolling = frameData.scrolling;
1171
+ options.adoptedStyleSheets = frameData.adoptedStyleSheets;
1161
1172
  frameData.runner = new Runner(options);
1162
1173
  frameData.frameElement = frameElement;
1163
1174
  await frameData.runner.loadPage();
@@ -30,6 +30,7 @@ import * as infobar from "./common/infobar.js";
30
30
  const ON_BEFORE_CAPTURE_EVENT_NAME = "single-file-on-before-capture";
31
31
  const ON_AFTER_CAPTURE_EVENT_NAME = "single-file-on-after-capture";
32
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";
33
34
  const GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT = "single-file-response-get-adopted-stylesheets";
34
35
  const REMOVED_CONTENT_ATTRIBUTE_NAME = "data-single-file-removed-content";
35
36
  const HIDDEN_CONTENT_ATTRIBUTE_NAME = "data-single-file-hidden-content";
@@ -64,6 +65,7 @@ const FONT_WEIGHTS = {
64
65
  const COMMENT_HEADER = "Page saved with SingleFile";
65
66
  const COMMENT_HEADER_LEGACY = "Archive processed by SingleFile";
66
67
  const SINGLE_FILE_UI_ELEMENT_CLASS = "single-file-ui-element";
68
+ const INFOBAR_TAGNAME = infobar.INFOBAR_TAGNAME;
67
69
  const EMPTY_RESOURCE = "data:,";
68
70
  const addEventListener = (type, listener, options) => globalThis.addEventListener(type, listener, options);
69
71
  const dispatchEvent = event => { try { globalThis.dispatchEvent(event); } catch (error) { /* ignored */ } };
@@ -103,7 +105,8 @@ export {
103
105
  COMMENT_HEADER,
104
106
  COMMENT_HEADER_LEGACY,
105
107
  SINGLE_FILE_UI_ELEMENT_CLASS,
106
- EMPTY_RESOURCE
108
+ EMPTY_RESOURCE,
109
+ INFOBAR_TAGNAME
107
110
  };
108
111
 
109
112
  function initUserScriptHandler() {
@@ -183,7 +186,8 @@ function preProcessDoc(doc, win, options) {
183
186
  referrer: doc.referrer,
184
187
  markedElements: elementsInfo.markedElements,
185
188
  invalidElements,
186
- scrollPosition: { x: win.scrollX, y: win.scrollY }
189
+ scrollPosition: { x: win.scrollX, y: win.scrollY },
190
+ adoptedStyleSheets: getStylesheetsContent(doc.adoptedStyleSheets)
187
191
  };
188
192
  }
189
193
 
@@ -229,23 +233,30 @@ function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map
229
233
  element.setAttribute(SHADOW_ROOT_ATTRIBUTE_NAME, data.shadowRoots.length);
230
234
  data.markedElements.push(element);
231
235
  data.shadowRoots.push(shadowRootInfo);
232
- getElementsInfo(win, doc, shadowRoot, options, data, elementHidden);
233
- shadowRootInfo.content = shadowRoot.innerHTML;
234
- shadowRootInfo.mode = shadowRoot.mode;
235
236
  try {
236
237
  if (shadowRoot.adoptedStyleSheets) {
237
238
  if (shadowRoot.adoptedStyleSheets.length) {
238
- shadowRootInfo.adoptedStyleSheets = Array.from(shadowRoot.adoptedStyleSheets).map(stylesheet => Array.from(stylesheet.cssRules).map(cssRule => cssRule.cssText).join("\n"));
239
+ shadowRootInfo.adoptedStyleSheets = getStylesheetsContent(shadowRoot.adoptedStyleSheets);
239
240
  } else if (shadowRoot.adoptedStyleSheets.length === undefined) {
240
241
  const listener = event => shadowRootInfo.adoptedStyleSheets = event.detail.adoptedStyleSheets;
241
242
  element.addEventListener(GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT, listener);
242
- element.dispatchEvent(new CustomEvent(GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, { options: { bubbles: true, composed: true }}));
243
+ element.dispatchEvent(new CustomEvent(GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, { bubbles: true }));
243
244
  element.removeEventListener(GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT, listener);
244
245
  }
245
246
  }
246
247
  } catch (error) {
247
248
  // ignored
248
249
  }
250
+ getElementsInfo(win, doc, shadowRoot, options, data, elementHidden);
251
+ shadowRootInfo.content = shadowRoot.innerHTML;
252
+ shadowRootInfo.mode = shadowRoot.mode;
253
+ try {
254
+ if (shadowRoot.adoptedStyleSheets && shadowRoot.adoptedStyleSheets.length === undefined) {
255
+ element.dispatchEvent(new CustomEvent(UNREGISTER_GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, { bubbles: true }));
256
+ }
257
+ } catch (error) {
258
+ // ignored
259
+ }
249
260
  }
250
261
  getElementsInfo(win, doc, element, options, data, elementHidden);
251
262
  if (!options.autoSaveExternalSave && options.removeHiddenElements && ascendantHidden) {
@@ -264,6 +275,10 @@ function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map
264
275
  return data;
265
276
  }
266
277
 
278
+ function getStylesheetsContent(styleSheets) {
279
+ return Array.from(styleSheets).map(stylesheet => Array.from(stylesheet.cssRules).map(cssRule => cssRule.cssText).join("\n"));
280
+ }
281
+
267
282
  function getResourcesInfo(win, doc, element, options, data, elementHidden, computedStyle) {
268
283
  const tagName = element.tagName && element.tagName.toUpperCase();
269
284
  if (tagName == "CANVAS") {
@@ -183,7 +183,8 @@ function getInstance(utilOptions) {
183
183
  COMMENT_HEADER: helper.COMMENT_HEADER,
184
184
  COMMENT_HEADER_LEGACY: helper.COMMENT_HEADER_LEGACY,
185
185
  SINGLE_FILE_UI_ELEMENT_CLASS: helper.SINGLE_FILE_UI_ELEMENT_CLASS,
186
- EMPTY_RESOURCE: helper.EMPTY_RESOURCE
186
+ EMPTY_RESOURCE: helper.EMPTY_RESOURCE,
187
+ INFOBAR_TAGNAME: helper.INFOBAR_TAGNAME
187
188
  };
188
189
 
189
190
  async function getContent(resourceURL, options) {