single-file-core 1.3.12 → 1.3.14

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/core/helper.js CHANGED
@@ -256,9 +256,12 @@ function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map
256
256
  shadowRootInfo.adoptedStyleSheets = getStylesheetsContent(shadowRoot.adoptedStyleSheets);
257
257
  } else if (shadowRoot.adoptedStyleSheets.length === undefined) {
258
258
  const listener = event => shadowRootInfo.adoptedStyleSheets = event.detail.adoptedStyleSheets;
259
- element.addEventListener(GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT, listener);
260
- element.dispatchEvent(new CustomEvent(GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, { bubbles: true }));
261
- element.removeEventListener(GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT, listener);
259
+ shadowRoot.addEventListener(GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT, listener);
260
+ shadowRoot.dispatchEvent(new CustomEvent(GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, { bubbles: true }));
261
+ if (!shadowRootInfo.adoptedStyleSheets) {
262
+ element.dispatchEvent(new CustomEvent(GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, { bubbles: true }));
263
+ }
264
+ shadowRoot.removeEventListener(GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT, listener);
262
265
  }
263
266
  }
264
267
  } catch (error) {
@@ -269,7 +272,7 @@ function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map
269
272
  shadowRootInfo.mode = shadowRoot.mode;
270
273
  try {
271
274
  if (shadowRoot.adoptedStyleSheets && shadowRoot.adoptedStyleSheets.length === undefined) {
272
- element.dispatchEvent(new CustomEvent(UNREGISTER_GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, { bubbles: true }));
275
+ shadowRoot.dispatchEvent(new CustomEvent(UNREGISTER_GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, { bubbles: true }));
273
276
  }
274
277
  } catch (error) {
275
278
  // ignored
package/core/index.js CHANGED
@@ -569,6 +569,7 @@ class Processor {
569
569
  const styleElement = this.doc.createElement("style");
570
570
  styleElement.textContent = "img[src=\"data:,\"],source[src=\"data:,\"]{display:none!important}";
571
571
  this.doc.head.appendChild(styleElement);
572
+ this.doc.head.querySelectorAll("noscript").forEach(element => element.parentElement.appendChild(element));
572
573
  let size;
573
574
  if (this.options.displayStats) {
574
575
  size = util.getContentSize(this.doc.documentElement.outerHTML);
@@ -1221,6 +1222,7 @@ class Processor {
1221
1222
  options.saveFavicon = false;
1222
1223
  options.includeInfobar = false;
1223
1224
  options.saveFilenameTemplateData = false;
1225
+ options.selected = false;
1224
1226
  options.url = frameData.baseURI;
1225
1227
  options.windowId = frameWindowId;
1226
1228
  if (frameData.content) {
@@ -187,6 +187,8 @@ class ProcessorHelperCommon {
187
187
  promises.push(processorHelper.processStyle(ruleData, options, resources, batchRequest));
188
188
  } else if (ruleData.type == "Atrule" && (ruleData.name == "media" || ruleData.name == "supports")) {
189
189
  promises.push(processorHelper.processStylesheet(ruleData.block.children, baseURI, options, resources, batchRequest));
190
+ } else if (ruleData.type == "Atrule" && (ruleData.name == "media" || ruleData.name == "layer")) {
191
+ promises.push(processorHelper.processStylesheet(ruleData.block.children, baseURI, options, resources, batchRequest));
190
192
  } else if (ruleData.type == "Atrule" && ruleData.name == "font-face") {
191
193
  promises.push(processFontFaceRule(ruleData));
192
194
  }
@@ -396,7 +398,8 @@ class ProcessorHelperCommon {
396
398
  const fontsDetails = {
397
399
  fonts: new Map(),
398
400
  medias: new Map(),
399
- supports: new Map()
401
+ supports: new Map(),
402
+ layers: new Map()
400
403
  };
401
404
  const stats = { rules: { processed: 0, discarded: 0 }, fonts: { processed: 0, discarded: 0 } };
402
405
  let sheetIndex = 0;
@@ -433,7 +436,7 @@ class ProcessorHelperCommon {
433
436
 
434
437
  async processFontFaceRules(cssRules, sheetIndex, fontsDetails, fonts, fontTests, stats) {
435
438
  const removedRules = [];
436
- let mediaIndex = 0, supportsIndex = 0;
439
+ let mediaIndex = 0, supportsIndex = 0, layerIndex = 0;
437
440
  for (let cssRule = cssRules.head; cssRule; cssRule = cssRule.next) {
438
441
  const ruleData = cssRule.data;
439
442
  if (ruleData.type == "Atrule" && ruleData.name == "media" && ruleData.block && ruleData.block.children && ruleData.prelude) {
@@ -444,6 +447,10 @@ class ProcessorHelperCommon {
444
447
  const supportsText = cssTree.generate(ruleData.prelude);
445
448
  await this.processFontFaceRules(ruleData.block.children, sheetIndex, fontsDetails.supports.get("supports-" + sheetIndex + "-" + supportsIndex + "-" + supportsText), fonts, fontTests, stats);
446
449
  supportsIndex++;
450
+ } else if (ruleData.type == "Atrule" && ruleData.name == "layer" && ruleData.block && ruleData.block.children && ruleData.prelude) {
451
+ const layerText = cssTree.generate(ruleData.prelude);
452
+ await this.processFontFaceRules(ruleData.block.children, sheetIndex, fontsDetails.layers.get("layer-" + sheetIndex + "-" + layerIndex + "-" + layerText), fonts, fontTests, stats);
453
+ layerIndex++;
447
454
  } else if (ruleData.type == "Atrule" && ruleData.name == "font-face") {
448
455
  const key = this.getFontKey(ruleData);
449
456
  const fontInfo = fontsDetails.fonts.get(key);
@@ -458,7 +465,7 @@ class ProcessorHelperCommon {
458
465
  }
459
466
 
460
467
  getFontsDetails(doc, cssRules, sheetIndex, mediaFontsDetails) {
461
- let mediaIndex = 0, supportsIndex = 0;
468
+ let mediaIndex = 0, supportsIndex = 0, layerIndex = 0;
462
469
  cssRules.forEach(ruleData => {
463
470
  if (ruleData.type == "Atrule" && ruleData.name == "media" && ruleData.block && ruleData.block.children && ruleData.prelude) {
464
471
  const mediaText = cssTree.generate(ruleData.prelude);
@@ -472,6 +479,12 @@ class ProcessorHelperCommon {
472
479
  mediaFontsDetails.supports.set("supports-" + sheetIndex + "-" + supportsIndex + "-" + supportsText, fontsDetails);
473
480
  supportsIndex++;
474
481
  this.getFontsDetails(doc, ruleData.block.children, sheetIndex, fontsDetails);
482
+ } else if (ruleData.type == "Atrule" && ruleData.name == "layer" && ruleData.block && ruleData.block.children && ruleData.prelude) {
483
+ const layerText = cssTree.generate(ruleData.prelude);
484
+ const fontsDetails = this.createFontsDetailsInfo();
485
+ mediaFontsDetails.layers.set("layer-" + sheetIndex + "-" + layerIndex + "-" + layerText, fontsDetails);
486
+ layerIndex++;
487
+ this.getFontsDetails(doc, ruleData.block.children, sheetIndex, fontsDetails);
475
488
  } else if (ruleData.type == "Atrule" && ruleData.name == "font-face" && ruleData.block && ruleData.block.children) {
476
489
  const fontKey = this.getFontKey(ruleData);
477
490
  let fontInfo = mediaFontsDetails.fonts.get(fontKey);
@@ -499,7 +512,8 @@ class ProcessorHelperCommon {
499
512
  return {
500
513
  fonts: new Map(),
501
514
  medias: new Map(),
502
- supports: new Map()
515
+ supports: new Map(),
516
+ layers: new Map()
503
517
  };
504
518
  }
505
519
 
@@ -574,9 +588,11 @@ function processFontDetails(fontsDetails, fontResources) {
574
588
  if (fontResources) {
575
589
  fontsDetails.medias.forEach(mediaFontsDetails => processFontDetails(mediaFontsDetails, fontResources));
576
590
  fontsDetails.supports.forEach(supportsFontsDetails => processFontDetails(supportsFontsDetails, fontResources));
591
+ fontsDetails.layers.forEach(layerFontsDetails => processFontDetails(layerFontsDetails, fontResources));
577
592
  } else {
578
593
  fontsDetails.medias.forEach(mediaFontsDetails => processFontDetails(mediaFontsDetails));
579
594
  fontsDetails.supports.forEach(supportsFontsDetails => processFontDetails(supportsFontsDetails));
595
+ fontsDetails.layers.forEach(layerFontsDetails => processFontDetails(layerFontsDetails));
580
596
  }
581
597
  }
582
598
 
@@ -533,7 +533,7 @@ function getProcessorHelperClass(utilInstance) {
533
533
  fontTests.set(source.src, source.valid);
534
534
  }
535
535
  }));
536
- const findSourceByFormat = (fontFormat, testValidity) => fontInfo.findLast(source => !source.src.match(EMPTY_URL_SOURCE) && source.format == fontFormat && (!testValidity || source.valid));
536
+ const findSourceByFormat = (fontFormat, testValidity) => util.findLast(fontInfo, source => !source.src.match(EMPTY_URL_SOURCE) && source.format == fontFormat && (!testValidity || source.valid));
537
537
  const filterSources = fontSource => fontInfo.filter(source => source == fontSource || source.src.startsWith(LOCAL_SOURCE));
538
538
  stats.fonts.processed += fontInfo.length;
539
539
  stats.fonts.discarded += fontInfo.length;
@@ -437,8 +437,8 @@ function getProcessorHelperClass(utilInstance) {
437
437
  fontTests.set(source.src, source.valid);
438
438
  }
439
439
  }));
440
- const findSourceByFormat = (fontFormat, testValidity) => fontInfo.findLast(source => !source.src.match(EMPTY_URL_SOURCE) && source.format == fontFormat && (!testValidity || source.valid));
441
- const findSourceByContentType = (contentType, testValidity) => fontInfo.findLast(source => !source.src.match(EMPTY_URL_SOURCE) && source.contentType == contentType && (!testValidity || source.valid));
440
+ const findSourceByFormat = (fontFormat, testValidity) => util.findLast(fontInfo, source => !source.src.match(EMPTY_URL_SOURCE) && source.format == fontFormat && (!testValidity || source.valid));
441
+ const findSourceByContentType = (contentType, testValidity) => util.findLast(fontInfo, source => !source.src.match(EMPTY_URL_SOURCE) && source.contentType == contentType && (!testValidity || source.valid));
442
442
  const filterSources = fontSource => fontInfo.filter(source => source == fontSource || source.src.startsWith(LOCAL_SOURCE));
443
443
  stats.fonts.processed += fontInfo.length;
444
444
  stats.fonts.discarded += fontInfo.length;
package/core/util.js CHANGED
@@ -196,6 +196,18 @@ function getInstance(utilOptions) {
196
196
  appendInfobar(doc, options) {
197
197
  return helper.appendInfobar(doc, options);
198
198
  },
199
+ findLast(array, callback) {
200
+ if (array.findLast && typeof array.findLast == "function") {
201
+ return array.findLast(callback);
202
+ } else {
203
+ let index = array.length;
204
+ while (index--) {
205
+ if (callback(array[index], index, array)) {
206
+ return array[index];
207
+ }
208
+ }
209
+ }
210
+ },
199
211
  ON_BEFORE_CAPTURE_EVENT_NAME: helper.ON_BEFORE_CAPTURE_EVENT_NAME,
200
212
  ON_AFTER_CAPTURE_EVENT_NAME: helper.ON_AFTER_CAPTURE_EVENT_NAME,
201
213
  WIN_ID_ATTRIBUTE_NAME: helper.WIN_ID_ATTRIBUTE_NAME,
@@ -127,8 +127,7 @@ const modules = [
127
127
  removeComments,
128
128
  removeEmptyAttributes,
129
129
  removeRedundantAttributes,
130
- compressJSONLD,
131
- node => mergeElements(node, "style", (node, previousSibling) => node.parentElement && getTagName(node.parentElement) == "HEAD" && node.media == previousSibling.media && node.title == previousSibling.title)
130
+ compressJSONLD
132
131
  ];
133
132
 
134
133
  export {
@@ -168,22 +167,6 @@ function mergeTextNodes(node) {
168
167
  }
169
168
  }
170
169
 
171
- function mergeElements(node, tagName, acceptMerge) {
172
- if (node.nodeType == Node_ELEMENT_NODE && getTagName(node) == tagName.toUpperCase()) {
173
- let previousSibling = node.previousSibling;
174
- const previousSiblings = [];
175
- while (previousSibling && previousSibling.nodeType == Node_TEXT_NODE && !previousSibling.textContent.trim()) {
176
- previousSiblings.push(previousSibling);
177
- previousSibling = previousSibling.previousSibling;
178
- }
179
- if (previousSibling && previousSibling.nodeType == Node_ELEMENT_NODE && previousSibling.tagName == node.tagName && acceptMerge(node, previousSibling)) {
180
- node.textContent = previousSibling.textContent + node.textContent;
181
- previousSiblings.forEach(node => node.remove());
182
- previousSibling.remove();
183
- }
184
- }
185
- }
186
-
187
170
  function collapseWhitespace(node, options) {
188
171
  if (node.nodeType == Node_TEXT_NODE) {
189
172
  let element = node.parentElement;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "single-file-core",
3
- "version": "1.3.12",
3
+ "version": "1.3.14",
4
4
  "description": "SingleFile Core",
5
5
  "author": "Gildas Lormeau",
6
6
  "license": "AGPL-3.0-or-later",
@@ -28,12 +28,9 @@ export {
28
28
  };
29
29
 
30
30
  async function display(document, docContent, { disableFramePointerEvents } = {}) {
31
- const DISABLED_NOSCRIPT_ATTRIBUTE_NAME = "data-single-file-disabled-noscript";
31
+ docContent = docContent.replace(/<noscript/gi, "<template disabled-noscript");
32
+ docContent = docContent.replaceAll(/<\/noscript/gi, "</template");
32
33
  const doc = (new DOMParser()).parseFromString(docContent, "text/html");
33
- doc.querySelectorAll("noscript:not([" + DISABLED_NOSCRIPT_ATTRIBUTE_NAME + "])").forEach(element => {
34
- element.setAttribute(DISABLED_NOSCRIPT_ATTRIBUTE_NAME, element.innerHTML);
35
- element.textContent = "";
36
- });
37
34
  if (doc.doctype) {
38
35
  if (document.doctype) {
39
36
  document.replaceChild(doc.doctype, document.doctype);
@@ -51,9 +48,12 @@ async function display(document, docContent, { disableFramePointerEvents } = {})
51
48
  });
52
49
  }
53
50
  document.replaceChild(document.importNode(doc.documentElement, true), document.documentElement);
54
- document.querySelectorAll("[" + DISABLED_NOSCRIPT_ATTRIBUTE_NAME + "]").forEach(element => {
55
- element.textContent = element.getAttribute(DISABLED_NOSCRIPT_ATTRIBUTE_NAME);
56
- element.removeAttribute(DISABLED_NOSCRIPT_ATTRIBUTE_NAME);
51
+ document.querySelectorAll("template[disabled-noscript]").forEach(element => {
52
+ const noscriptElement = document.createElement("noscript");
53
+ element.removeAttribute("disabled-noscript");
54
+ Array.from(element.attributes).forEach(attribute => noscriptElement.setAttribute(attribute.name, attribute.value));
55
+ noscriptElement.textContent = element.innerHTML;
56
+ element.parentElement.replaceChild(noscriptElement, element);
57
57
  });
58
58
  document.documentElement.setAttribute("data-sfz", "");
59
59
  document.querySelectorAll("link[rel*=icon]").forEach(element => element.parentElement.replaceChild(element, element));
@@ -154,7 +154,7 @@ async function extract(content, { password, prompt = () => { }, shadowRootScript
154
154
  }
155
155
  if (!filename.match(REGEXP_MATCH_SCRIPT)) {
156
156
  const resourceFilename = filename;
157
- await Promise.all(resources.map(async innerResource => {
157
+ resources.forEach(innerResource => {
158
158
  const { filename, parentResources, content } = innerResource;
159
159
  if (filename.startsWith(prefixPath) && filename != resourceFilename) {
160
160
  const relativeFilename = filename.substring(prefixPath.length);
@@ -166,7 +166,7 @@ async function extract(content, { password, prompt = () => { }, shadowRootScript
166
166
  }
167
167
  }
168
168
  }
169
- }));
169
+ });
170
170
  resource.textContent = textContent;
171
171
  }
172
172
  if (filename.match(REGEXP_MATCH_INDEX)) {
@@ -382,11 +382,11 @@
382
382
  const shadowRoot = event.target.shadowRoot;
383
383
  event.stopPropagation();
384
384
  if (shadowRoot) {
385
- shadowRoot.addEventListener(GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, getAdoptedStylesheetsListener, {});
385
+ shadowRoot.addEventListener(GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, getAdoptedStylesheetsListener, { capture: true });
386
386
  shadowRoot.addEventListener(UNREGISTER_GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, () => shadowRoot.removeEventListener(GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, getAdoptedStylesheetsListener), { once: true });
387
387
  const adoptedStyleSheets = Array.from(shadowRoot.adoptedStyleSheets).map(stylesheet => Array.from(stylesheet.cssRules).map(cssRule => cssRule.cssText).join("\n"));
388
388
  if (adoptedStyleSheets.length) {
389
- event.target.dispatchEvent(new CustomEvent(GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT, { detail: { adoptedStyleSheets } }));
389
+ shadowRoot.dispatchEvent(new CustomEvent(GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT, { detail: { adoptedStyleSheets } }));
390
390
  }
391
391
  }
392
392
  }
@@ -28,6 +28,7 @@ import {
28
28
  COMMENT_HEADER_LEGACY,
29
29
  ON_BEFORE_CAPTURE_EVENT_NAME,
30
30
  ON_AFTER_CAPTURE_EVENT_NAME,
31
+ WAIT_FOR_USERSCRIPT_PROPERTY_NAME,
31
32
  initUserScriptHandler,
32
33
  preProcessDoc,
33
34
  postProcessDoc,
@@ -40,6 +41,7 @@ const helper = {
40
41
  COMMENT_HEADER_LEGACY,
41
42
  ON_BEFORE_CAPTURE_EVENT_NAME,
42
43
  ON_AFTER_CAPTURE_EVENT_NAME,
44
+ WAIT_FOR_USERSCRIPT_PROPERTY_NAME,
43
45
  preProcessDoc,
44
46
  postProcessDoc,
45
47
  serialize(doc, compressHTML) {