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 +7 -4
- package/core/index.js +2 -0
- package/core/lib/processor-helper-common.js +20 -4
- package/core/lib/processor-helper-inline.js +1 -1
- package/core/lib/processor-helper.js +2 -2
- package/core/util.js +12 -0
- package/modules/html-minifier.js +1 -18
- package/package.json +1 -1
- package/processors/compression/compression-display.js +8 -8
- package/processors/compression/compression-extract.js +2 -2
- package/processors/hooks/content/content-hooks-frames-web.js +2 -2
- package/single-file-bootstrap.js +2 -0
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
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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
|
-
|
|
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) =>
|
|
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) =>
|
|
441
|
-
const findSourceByContentType = (contentType, testValidity) =>
|
|
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,
|
package/modules/html-minifier.js
CHANGED
|
@@ -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
|
@@ -28,12 +28,9 @@ export {
|
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
async function display(document, docContent, { disableFramePointerEvents } = {}) {
|
|
31
|
-
|
|
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("[
|
|
55
|
-
|
|
56
|
-
element.removeAttribute(
|
|
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
|
-
|
|
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
|
-
|
|
389
|
+
shadowRoot.dispatchEvent(new CustomEvent(GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT, { detail: { adoptedStyleSheets } }));
|
|
390
390
|
}
|
|
391
391
|
}
|
|
392
392
|
}
|
package/single-file-bootstrap.js
CHANGED
|
@@ -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) {
|