single-file-core 1.5.14 → 1.5.16

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
@@ -53,6 +53,7 @@ const VIDEO_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "video";
53
53
  const CANVAS_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "canvas";
54
54
  const STYLE_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "movable-style";
55
55
  const INPUT_VALUE_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "input-value";
56
+ const INPUT_CHECKED_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "input-checked";
56
57
  const LAZY_SRC_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "lazy-loaded-src";
57
58
  const STYLESHEET_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "stylesheet";
58
59
  const DISABLED_NOSCRIPT_ATTRIBUTE_NAME = "data-" + SINGLE_FILE_PREFIX + "disabled-noscript";
@@ -83,6 +84,7 @@ const TextEncoder = globalThis.TextEncoder;
83
84
  const Blob = globalThis.Blob;
84
85
  const CustomEvent = globalThis.CustomEvent;
85
86
  const MutationObserver = globalThis.MutationObserver;
87
+ const URL = globalThis.URL;
86
88
 
87
89
  export {
88
90
  initUserScriptHandler,
@@ -110,6 +112,7 @@ export {
110
112
  VIDEO_ATTRIBUTE_NAME,
111
113
  CANVAS_ATTRIBUTE_NAME,
112
114
  INPUT_VALUE_ATTRIBUTE_NAME,
115
+ INPUT_CHECKED_ATTRIBUTE_NAME,
113
116
  SHADOW_ROOT_ATTRIBUTE_NAME,
114
117
  STYLE_ATTRIBUTE_NAME,
115
118
  LAZY_SRC_ATTRIBUTE_NAME,
@@ -203,7 +206,7 @@ function preProcessDoc(doc, win, options) {
203
206
  videos: elementsInfo.videos,
204
207
  usedFonts: Array.from(elementsInfo.usedFonts.values()),
205
208
  shadowRoots: elementsInfo.shadowRoots,
206
- referrer: doc.referrer,
209
+ referrer: doc.referrer ? new URL("/", new URL(doc.referrer).origin).href : "",
207
210
  markedElements: elementsInfo.markedElements,
208
211
  invalidElements,
209
212
  scrollPosition: { x: win.scrollX, y: win.scrollY },
@@ -273,6 +276,9 @@ function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map
273
276
  getElementsInfo(win, doc, shadowRoot, options, data, elementHidden);
274
277
  shadowRootInfo.content = shadowRoot.innerHTML;
275
278
  shadowRootInfo.mode = shadowRoot.mode;
279
+ shadowRootInfo.delegateFocus = shadowRoot.delegatesFocus;
280
+ shadowRootInfo.clonable = shadowRoot.clonable;
281
+ shadowRootInfo.serializable = shadowRoot.serializable;
276
282
  try {
277
283
  if (shadowRoot.adoptedStyleSheets && shadowRoot.adoptedStyleSheets.length === undefined) {
278
284
  shadowRoot.dispatchEvent(new CustomEvent(UNREGISTER_GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, { bubbles: true }));
@@ -384,7 +390,7 @@ function getResourcesInfo(win, doc, element, options, data, elementHidden, compu
384
390
  data.markedElements.push(element);
385
391
  }
386
392
  if (element.type == "radio" || element.type == "checkbox") {
387
- element.setAttribute(INPUT_VALUE_ATTRIBUTE_NAME, element.checked);
393
+ element.setAttribute(INPUT_CHECKED_ATTRIBUTE_NAME, element.checked);
388
394
  data.markedElements.push(element);
389
395
  }
390
396
  }
@@ -475,7 +481,7 @@ function postProcessDoc(doc, markedElements, invalidElements) {
475
481
  doc.head.querySelectorAll("*:not(base):not(link):not(meta):not(noscript):not(script):not(style):not(template):not(title)").forEach(element => element.removeAttribute("hidden"));
476
482
  }
477
483
  if (!markedElements) {
478
- const singleFileAttributes = [REMOVED_CONTENT_ATTRIBUTE_NAME, HIDDEN_FRAME_ATTRIBUTE_NAME, HIDDEN_CONTENT_ATTRIBUTE_NAME, PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME, IMAGE_ATTRIBUTE_NAME, POSTER_ATTRIBUTE_NAME, VIDEO_ATTRIBUTE_NAME, CANVAS_ATTRIBUTE_NAME, INPUT_VALUE_ATTRIBUTE_NAME, SHADOW_ROOT_ATTRIBUTE_NAME, STYLESHEET_ATTRIBUTE_NAME, ASYNC_SCRIPT_ATTRIBUTE_NAME];
484
+ const singleFileAttributes = [REMOVED_CONTENT_ATTRIBUTE_NAME, HIDDEN_FRAME_ATTRIBUTE_NAME, HIDDEN_CONTENT_ATTRIBUTE_NAME, PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME, IMAGE_ATTRIBUTE_NAME, POSTER_ATTRIBUTE_NAME, VIDEO_ATTRIBUTE_NAME, CANVAS_ATTRIBUTE_NAME, INPUT_VALUE_ATTRIBUTE_NAME, INPUT_CHECKED_ATTRIBUTE_NAME, SHADOW_ROOT_ATTRIBUTE_NAME, STYLESHEET_ATTRIBUTE_NAME, ASYNC_SCRIPT_ATTRIBUTE_NAME];
479
485
  markedElements = doc.querySelectorAll(singleFileAttributes.map(name => "[" + name + "]").join(","));
480
486
  }
481
487
  markedElements.forEach(element => {
@@ -489,6 +495,7 @@ function postProcessDoc(doc, markedElements, invalidElements) {
489
495
  element.removeAttribute(VIDEO_ATTRIBUTE_NAME);
490
496
  element.removeAttribute(CANVAS_ATTRIBUTE_NAME);
491
497
  element.removeAttribute(INPUT_VALUE_ATTRIBUTE_NAME);
498
+ element.removeAttribute(INPUT_CHECKED_ATTRIBUTE_NAME);
492
499
  element.removeAttribute(SHADOW_ROOT_ATTRIBUTE_NAME);
493
500
  element.removeAttribute(STYLESHEET_ATTRIBUTE_NAME);
494
501
  element.removeAttribute(ASYNC_SCRIPT_ATTRIBUTE_NAME);
package/core/index.js CHANGED
@@ -201,8 +201,8 @@ class Runner {
201
201
  this.markedElements = docData.markedElements;
202
202
  this.invalidElements = docData.invalidElements;
203
203
  }
204
- if (this.options.saveRawPage) {
205
- this.options.removeFrames = true;
204
+ if (this.options.saveRawPage && !this.options.removeFrames) {
205
+ this.options.frames = [];
206
206
  }
207
207
  this.options.content = this.options.content || (rootDocDefined ? util.serialize(this.options.doc) : null);
208
208
  this.onprogress = options.onprogress || (() => { });
@@ -414,6 +414,9 @@ class BatchRequest {
414
414
  // Processor
415
415
  // ---------
416
416
  const SHADOWROOT_ATTRIBUTE_NAME = "shadowrootmode";
417
+ const SHADOWROOT_DELEGATES_FOCUS = "shadowrootdelegatesfocus";
418
+ const SHADOWROOT_CLONABLE = "shadowrootclonable";
419
+ const SHADOWROOT_SERIALIZABLE = "shadowrootserializable";
417
420
  const SCRIPT_TEMPLATE_SHADOW_ROOT = "data-template-shadow-root";
418
421
  const SCRIPT_OPTIONS = "data-single-file-options";
419
422
  const UTF8_CHARSET = "utf-8";
@@ -446,7 +449,7 @@ class Processor {
446
449
  this.maffMetaDataPromise = this.batchRequest.addURL(util.resolveURL("index.rdf", this.options.baseURI || this.options.url), { expectedType: "document" });
447
450
  }
448
451
  this.maxResources = this.batchRequest.getMaxResources();
449
- if (!this.options.saveRawPage && !this.options.removeFrames && this.options.frames) {
452
+ if (!this.options.removeFrames && this.options.frames) {
450
453
  this.options.frames.forEach(frameData => this.maxResources += frameData.maxResources || 0);
451
454
  }
452
455
  this.stats.set("processed", "resources", this.maxResources);
@@ -542,7 +545,7 @@ class Processor {
542
545
  }
543
546
  const scriptElement = this.doc.createElement("script");
544
547
  scriptElement.setAttribute(SCRIPT_TEMPLATE_SHADOW_ROOT, "");
545
- scriptElement.textContent = `(()=>{document.currentScript.remove();processNode(document);function processNode(node){node.querySelectorAll("template[${SHADOWROOT_ATTRIBUTE_NAME}]").forEach(element=>{let shadowRoot = element.parentElement.shadowRoot;if (!shadowRoot) {try {shadowRoot=element.parentElement.attachShadow({mode:element.getAttribute("${SHADOWROOT_ATTRIBUTE_NAME}")});shadowRoot.innerHTML=element.innerHTML;element.remove()} catch (error) {} if (shadowRoot) {processNode(shadowRoot)}}})}})()`;
548
+ scriptElement.textContent = `(()=>{document.currentScript.remove();processNode(document);function processNode(node){node.querySelectorAll("template[${SHADOWROOT_ATTRIBUTE_NAME}]").forEach(element=>{let shadowRoot = element.parentElement.shadowRoot;if (!shadowRoot) {try {shadowRoot=element.parentElement.attachShadow({mode:element.getAttribute("${SHADOWROOT_ATTRIBUTE_NAME}"),delegatesFocus:element.getAttribute("${SHADOWROOT_DELEGATES_FOCUS}")!=null,clonable:element.getAttribute("${SHADOWROOT_CLONABLE}")!=null,serializable:element.getAttribute("${SHADOWROOT_SERIALIZABLE})!=null});shadowRoot.innerHTML=element.innerHTML;element.remove()} catch (error) {} if (shadowRoot) {processNode(shadowRoot)}}})}})()`;
546
549
  this.doc.body.appendChild(scriptElement);
547
550
  }
548
551
  if (this.options.insertCanonicalLink && this.options.saveUrl.match(HTTP_URI_PREFIX)) {
@@ -941,32 +944,34 @@ class Processor {
941
944
  }
942
945
 
943
946
  setInputValues() {
944
- this.doc.querySelectorAll("input:not([type=radio]):not([type=checkbox])").forEach(input => {
945
- const value = input.getAttribute(util.INPUT_VALUE_ATTRIBUTE_NAME);
946
- if (value != null) {
947
- input.setAttribute("value", value);
948
- }
949
- });
950
- this.doc.querySelectorAll("input[type=radio], input[type=checkbox]").forEach(input => {
951
- const value = input.getAttribute(util.INPUT_VALUE_ATTRIBUTE_NAME);
952
- if (value == "true") {
953
- input.setAttribute("checked", "");
954
- }
955
- });
956
- this.doc.querySelectorAll("textarea").forEach(textarea => {
957
- const value = textarea.getAttribute(util.INPUT_VALUE_ATTRIBUTE_NAME);
958
- if (value != null) {
959
- textarea.textContent = value;
960
- }
961
- });
962
- this.doc.querySelectorAll("select").forEach(select => {
963
- select.querySelectorAll("option").forEach(option => {
964
- const selected = option.getAttribute(util.INPUT_VALUE_ATTRIBUTE_NAME) != null;
965
- if (selected) {
966
- option.setAttribute("selected", "");
947
+ if (!this.options.saveRawPage) {
948
+ this.doc.querySelectorAll("input, textarea").forEach(input => {
949
+ const value = input.getAttribute(util.INPUT_VALUE_ATTRIBUTE_NAME);
950
+ if (value != null) {
951
+ input.setAttribute("value", value);
952
+ } else {
953
+ input.removeAttribute("value");
967
954
  }
968
955
  });
969
- });
956
+ this.doc.querySelectorAll("input[type=radio], input[type=checkbox]").forEach(input => {
957
+ const value = input.getAttribute(util.INPUT_CHECKED_ATTRIBUTE_NAME);
958
+ if (value == "true") {
959
+ input.setAttribute("checked", "");
960
+ } else {
961
+ input.removeAttribute("checked");
962
+ }
963
+ });
964
+ this.doc.querySelectorAll("select").forEach(select => {
965
+ select.querySelectorAll("option").forEach(option => {
966
+ const selected = option.getAttribute(util.INPUT_VALUE_ATTRIBUTE_NAME) != null;
967
+ if (selected) {
968
+ option.setAttribute("selected", "");
969
+ } else {
970
+ option.removeAttribute("selected");
971
+ }
972
+ });
973
+ });
974
+ }
970
975
  }
971
976
 
972
977
  moveStylesInHead() {
@@ -1182,7 +1187,7 @@ class Processor {
1182
1187
  mediaText,
1183
1188
  scoped
1184
1189
  };
1185
- await this.processorHelper.processLinkElement(element, stylesheetInfo, this.stylesheets, this.baseURI, options, this.workStyleElement, this.resources);
1190
+ await this.processorHelper.resolveStylesheets(element, stylesheetInfo, this.stylesheets, this.baseURI, options, this.workStyleElement, this.resources);
1186
1191
  }));
1187
1192
  if (this.options.rootDocument) {
1188
1193
  const newResources = Object.keys(this.options.updatedResources)
@@ -1195,7 +1200,7 @@ class Processor {
1195
1200
  const element = this.doc.createElement("style");
1196
1201
  this.doc.body.appendChild(element);
1197
1202
  element.textContent = resource.content;
1198
- await this.processorHelper.processStylesheetElement(element, stylesheetInfo, this.stylesheets, this.baseURI, this.options, this.workStyleElement, this.resources);
1203
+ await this.processorHelper.resolveStylesheetElement(element, stylesheetInfo, this.stylesheets, this.baseURI, this.options, this.workStyleElement, this.resources);
1199
1204
  }
1200
1205
  }));
1201
1206
  }
@@ -1203,29 +1208,54 @@ class Processor {
1203
1208
 
1204
1209
  async resolveFrameURLs() {
1205
1210
  const processorHelper = this.processorHelper;
1206
- if (!this.options.saveRawPage) {
1207
- const frameElements = Array.from(this.doc.querySelectorAll("iframe, frame, object[type=\"text/html\"][data]"));
1208
- await Promise.all(frameElements.map(async frameElement => {
1209
- if (frameElement.tagName.toUpperCase() == "OBJECT") {
1210
- frameElement.setAttribute("data", "data:text/html,");
1211
- } else {
1212
- const src = frameElement.getAttribute("src");
1213
- if (this.options.saveOriginalURLs && src && !isDataURL(src)) {
1214
- frameElement.setAttribute("data-sf-original-src", src);
1215
- }
1216
- frameElement.removeAttribute("src");
1217
- frameElement.removeAttribute("srcdoc");
1211
+ const frameElements = Array.from(this.doc.querySelectorAll("iframe, frame, object[type=\"text/html\"][data]"));
1212
+ await Promise.all(frameElements.map(async frameElement => {
1213
+ const src = frameElement.getAttribute("src");
1214
+ let url;
1215
+ if (frameElement.tagName.toUpperCase() == "OBJECT") {
1216
+ frameElement.setAttribute("data", "data:text/html,");
1217
+ } else {
1218
+ frameElement.removeAttribute("src");
1219
+ frameElement.removeAttribute("srcdoc");
1220
+ }
1221
+ Array.from(frameElement.childNodes).forEach(node => node.remove());
1222
+ if (src && !testIgnoredPath(src)) {
1223
+ url = util.resolveURL(src, this.baseURI);
1224
+ if (this.options.saveOriginalURLs && src && !isDataURL(src)) {
1225
+ frameElement.setAttribute("data-sf-original-src", url);
1218
1226
  }
1219
- Array.from(frameElement.childNodes).forEach(node => node.remove());
1227
+
1228
+ }
1229
+ if (this.options.saveRawPage && url && testValidURL(url)) {
1230
+ const frameData = {
1231
+ adoptedStyleSheets: [],
1232
+ baseURI: url,
1233
+ canvases: [],
1234
+ fonts: [],
1235
+ images: [],
1236
+ posters: [],
1237
+ scrollPosition: { x: 0, y: 0 },
1238
+ shadowRoots: [],
1239
+ stylesheets: [],
1240
+ url,
1241
+ usedFonts: [],
1242
+ videos: [],
1243
+ worklets: []
1244
+ };
1245
+ this.options.frames.push(frameData);
1246
+ frameData.windowId = (this.options.windowId || "0") + "." + this.options.frames.length;
1247
+ frameElement.setAttribute(util.WIN_ID_ATTRIBUTE_NAME, frameData.windowId);
1248
+ await initializeProcessor(frameData, frameElement, null, this.batchRequest, Object.create(this.options));
1249
+ } else {
1220
1250
  const frameWindowId = frameElement.getAttribute(util.WIN_ID_ATTRIBUTE_NAME);
1221
1251
  if (this.options.frames && frameWindowId) {
1222
1252
  const frameData = this.options.frames.find(frame => frame.windowId == frameWindowId);
1223
- if (frameData) {
1253
+ if (frameData && frameData.content) {
1224
1254
  await initializeProcessor(frameData, frameElement, frameWindowId, this.batchRequest, Object.create(this.options));
1225
1255
  }
1226
1256
  }
1227
- }));
1228
- }
1257
+ }
1258
+ }));
1229
1259
 
1230
1260
  async function initializeProcessor(frameData, frameElement, frameWindowId, batchRequest, options) {
1231
1261
  options.insertSingleFileComment = false;
@@ -1238,26 +1268,24 @@ class Processor {
1238
1268
  options.embeddedImage = null;
1239
1269
  options.url = frameData.baseURI;
1240
1270
  options.windowId = frameWindowId;
1241
- if (frameData.content) {
1242
- options.content = frameData.content;
1243
- options.canvases = frameData.canvases;
1244
- options.fonts = frameData.fonts;
1245
- options.worklets = frameData.worklets;
1246
- options.stylesheets = frameData.stylesheets;
1247
- options.images = frameData.images;
1248
- options.posters = frameData.posters;
1249
- options.videos = frameData.videos;
1250
- options.usedFonts = frameData.usedFonts;
1251
- options.shadowRoots = frameData.shadowRoots;
1252
- options.scrollPosition = frameData.scrollPosition;
1253
- options.scrolling = frameData.scrolling;
1254
- options.adoptedStyleSheets = frameData.adoptedStyleSheets;
1255
- frameData.runner = new Runner(options, processorHelper);
1256
- frameData.frameElement = frameElement;
1257
- await frameData.runner.loadPage();
1258
- await frameData.runner.initialize();
1259
- frameData.maxResources = batchRequest.getMaxResources();
1260
- }
1271
+ options.content = frameData.content;
1272
+ options.canvases = frameData.canvases;
1273
+ options.fonts = frameData.fonts;
1274
+ options.worklets = frameData.worklets;
1275
+ options.stylesheets = frameData.stylesheets;
1276
+ options.images = frameData.images;
1277
+ options.posters = frameData.posters;
1278
+ options.videos = frameData.videos;
1279
+ options.usedFonts = frameData.usedFonts;
1280
+ options.shadowRoots = frameData.shadowRoots;
1281
+ options.scrollPosition = frameData.scrollPosition;
1282
+ options.scrolling = frameData.scrolling;
1283
+ options.adoptedStyleSheets = frameData.adoptedStyleSheets;
1284
+ frameData.runner = new Runner(options, processorHelper);
1285
+ frameData.frameElement = frameElement;
1286
+ await frameData.runner.loadPage();
1287
+ await frameData.runner.initialize();
1288
+ frameData.maxResources = batchRequest.getMaxResources();
1261
1289
  }
1262
1290
  }
1263
1291
 
@@ -1277,6 +1305,15 @@ class Processor {
1277
1305
  if (shadowRootData) {
1278
1306
  const templateElement = doc.createElement("template");
1279
1307
  templateElement.setAttribute(SHADOWROOT_ATTRIBUTE_NAME, shadowRootData.mode);
1308
+ if (shadowRootData.delegatesFocus) {
1309
+ templateElement.setAttribute(SHADOWROOT_DELEGATES_FOCUS, shadowRootData.delegatesFocus);
1310
+ }
1311
+ if (shadowRootData.clonable) {
1312
+ templateElement.setAttribute(SHADOWROOT_CLONABLE, shadowRootData.clonable);
1313
+ }
1314
+ if (shadowRootData.serializable) {
1315
+ templateElement.setAttribute(SHADOWROOT_SERIALIZABLE, shadowRootData.serializable);
1316
+ }
1280
1317
  if (shadowRootData.adoptedStyleSheets && shadowRootData.adoptedStyleSheets.length) {
1281
1318
  shadowRootData.adoptedStyleSheets.forEach(stylesheetContent => {
1282
1319
  const styleElement = doc.createElement("style");
@@ -1406,7 +1443,7 @@ class Processor {
1406
1443
  await frameData.runner.run();
1407
1444
  const pageData = await frameData.runner.getPageData();
1408
1445
  frameElement.removeAttribute(util.WIN_ID_ATTRIBUTE_NAME);
1409
- this.processorHelper.processFrame(frameElement, pageData, this.resources, frameWindowId, frameData);
1446
+ this.processorHelper.processFrame(frameElement, pageData, this.options, this.resources, frameWindowId, frameData);
1410
1447
  this.stats.addAll(pageData);
1411
1448
  } else {
1412
1449
  frameElement.removeAttribute(util.WIN_ID_ATTRIBUTE_NAME);
@@ -73,14 +73,14 @@ function getProcessorHelperClass(utilInstance) {
73
73
  const ProcessorHelperCommon = getProcessorHelperCommonClass(util, cssTree);
74
74
 
75
75
  return class ProcessorHelper extends ProcessorHelperCommon {
76
- async processLinkElement(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement) {
76
+ async resolveStylesheets(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement) {
77
77
  if (element.tagName.toUpperCase() == "LINK" && element.charset) {
78
78
  options.charset = element.charset;
79
79
  }
80
- await this.processStylesheetElement(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement);
80
+ await this.resolveStylesheetElement(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement);
81
81
  }
82
82
 
83
- async processStylesheetElement(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement) {
83
+ async resolveStylesheetElement(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement) {
84
84
  let stylesheet;
85
85
  stylesheets.set(element, stylesheetInfo);
86
86
  if (!options.blockStylesheets) {
@@ -215,10 +215,10 @@ function getProcessorHelperClass(utilInstance) {
215
215
  }
216
216
  }
217
217
 
218
- async processFrame(frameElement, pageData) {
218
+ async processFrame(frameElement, pageData, options) {
219
219
  let sandbox = "allow-popups allow-top-navigation allow-top-navigation-by-user-activation";
220
- if (pageData.content.match(NOSCRIPT_TAG_FOUND) || pageData.content.match(CANVAS_TAG_FOUND) || pageData.content.match(SCRIPT_TAG_FOUND)) {
221
- sandbox += " allow-scripts allow-same-origin";
220
+ if (pageData.content.match(NOSCRIPT_TAG_FOUND) || pageData.content.match(CANVAS_TAG_FOUND) || pageData.content.match(SCRIPT_TAG_FOUND) || options.saveRawPage) {
221
+ sandbox += " allow-scripts allow-same-origin allow-modals allow-popups allow-downloads allow-pointer-lock allow-presentation";
222
222
  }
223
223
  frameElement.setAttribute("sandbox", sandbox);
224
224
  if (frameElement.tagName.toUpperCase() == "OBJECT") {
@@ -30,6 +30,9 @@ const FontFace = globalThis.FontFace;
30
30
 
31
31
  const ABOUT_BLANK_URI = "about:blank";
32
32
  const UTF8_CHARSET = "utf-8";
33
+ const SCRIPT_TAG_FOUND = /<script/gi;
34
+ const NOSCRIPT_TAG_FOUND = /<noscript/gi;
35
+ const CANVAS_TAG_FOUND = /<canvas/gi;
33
36
  const EMPTY_URL_SOURCE = /^url\(["']?data:[^,]*,?["']?\)/;
34
37
  const LOCAL_SOURCE = "local(";
35
38
  const FONT_MAX_LOAD_DELAY = 5000;
@@ -61,7 +64,7 @@ function getProcessorHelperClass(utilInstance) {
61
64
  const ProcessorHelperCommon = getProcessorHelperCommonClass(util, cssTree);
62
65
 
63
66
  return class ProcessorHelper extends ProcessorHelperCommon {
64
- async processLinkElement(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement, resources) {
67
+ async resolveStylesheets(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement, resources) {
65
68
  if (element.tagName.toUpperCase() == "LINK") {
66
69
  element.removeAttribute("integrity");
67
70
  if (element.charset) {
@@ -69,10 +72,10 @@ function getProcessorHelperClass(utilInstance) {
69
72
  }
70
73
  stylesheetInfo.url = element.href;
71
74
  }
72
- await this.processStylesheetElement(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement, resources);
75
+ await this.resolveStylesheetElement(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement, resources);
73
76
  }
74
77
 
75
- async processStylesheetElement(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement, resources) {
78
+ async resolveStylesheetElement(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement, resources) {
76
79
  if (!options.blockStylesheets) {
77
80
  stylesheets.set({ element }, stylesheetInfo);
78
81
  if (element.tagName.toUpperCase() == "LINK") {
@@ -207,8 +210,13 @@ function getProcessorHelperClass(utilInstance) {
207
210
  }
208
211
  }
209
212
 
210
- async processFrame(frameElement, pageData, resources, frameWindowId, frameData) {
213
+ async processFrame(frameElement, pageData, options, resources, frameWindowId, frameData) {
211
214
  const name = "frames/" + resources.frames.size + "/";
215
+ let sandbox = "allow-popups allow-top-navigation allow-top-navigation-by-user-activation";
216
+ if (pageData.content.match(NOSCRIPT_TAG_FOUND) || pageData.content.match(CANVAS_TAG_FOUND) || pageData.content.match(SCRIPT_TAG_FOUND) || options.saveRawPage) {
217
+ sandbox += " allow-scripts allow-same-origin allow-modals allow-popups allow-downloads allow-pointer-lock allow-presentation";
218
+ }
219
+ frameElement.setAttribute("sandbox", sandbox);
212
220
  if (frameElement.tagName.toUpperCase() == "OBJECT") {
213
221
  frameElement.setAttribute("data", name + "index.html");
214
222
  } else {
package/core/util.js CHANGED
@@ -232,6 +232,7 @@ function getInstance(utilOptions) {
232
232
  CANVAS_ATTRIBUTE_NAME: helper.CANVAS_ATTRIBUTE_NAME,
233
233
  STYLE_ATTRIBUTE_NAME: helper.STYLE_ATTRIBUTE_NAME,
234
234
  INPUT_VALUE_ATTRIBUTE_NAME: helper.INPUT_VALUE_ATTRIBUTE_NAME,
235
+ INPUT_CHECKED_ATTRIBUTE_NAME: helper.INPUT_CHECKED_ATTRIBUTE_NAME,
235
236
  SHADOW_ROOT_ATTRIBUTE_NAME: helper.SHADOW_ROOT_ATTRIBUTE_NAME,
236
237
  PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME: helper.PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME,
237
238
  STYLESHEET_ATTRIBUTE_NAME: helper.STYLESHEET_ATTRIBUTE_NAME,
@@ -17052,10 +17052,10 @@ async function evalTemplate(template = "", options, content, doc, context = {})
17052
17052
  }
17053
17053
  }
17054
17054
  };
17055
- functions["date-locale"].dontReplaceSlash = false;
17056
- functions["time-locale"].dontReplaceSlash = false;
17057
- functions["datetime-locale"].dontReplaceSlash = false;
17058
- functions["datetime-custom"].dontReplaceSlash = false;
17055
+ functions["date-locale"].dontReplaceSlash = true;
17056
+ functions["time-locale"].dontReplaceSlash = true;
17057
+ functions["datetime-locale"].dontReplaceSlash = true;
17058
+ functions["datetime-custom"].dontReplaceSlash = true;
17059
17059
  if (doc) {
17060
17060
  functions["page-element-text"] = (selector) => {
17061
17061
  const element = doc.querySelector(selector);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "single-file-core",
3
- "version": "1.5.14",
3
+ "version": "1.5.16",
4
4
  "description": "SingleFile Core",
5
5
  "author": "Gildas Lormeau",
6
6
  "license": "AGPL-3.0-or-later",