single-file-core 1.5.71 → 1.5.73
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/index.js
CHANGED
|
@@ -1223,17 +1223,20 @@ class Processor {
|
|
|
1223
1223
|
}
|
|
1224
1224
|
|
|
1225
1225
|
async resolveStylesheetsURLs() {
|
|
1226
|
-
const
|
|
1226
|
+
const stylesContents = [];
|
|
1227
1227
|
this.options.inlineStylesheets = new Map();
|
|
1228
1228
|
this.options.inlineStylesheetsRefs = new Map();
|
|
1229
|
-
this.doc.querySelectorAll("style").forEach(
|
|
1230
|
-
if (
|
|
1231
|
-
const indexContent =
|
|
1229
|
+
this.doc.querySelectorAll("style").forEach(styleElement => {
|
|
1230
|
+
if (styleElement.textContent) {
|
|
1231
|
+
const indexContent = stylesContents.indexOf(styleElement.textContent);
|
|
1232
1232
|
if (indexContent == -1) {
|
|
1233
|
-
this.options.inlineStylesheets.set(
|
|
1234
|
-
|
|
1233
|
+
this.options.inlineStylesheets.set(stylesContents.length, {
|
|
1234
|
+
styleElement,
|
|
1235
|
+
content: styleElement.textContent
|
|
1236
|
+
});
|
|
1237
|
+
stylesContents.push(styleElement.textContent);
|
|
1235
1238
|
} else {
|
|
1236
|
-
this.options.inlineStylesheetsRefs.set(
|
|
1239
|
+
this.options.inlineStylesheetsRefs.set(styleElement, indexContent);
|
|
1237
1240
|
}
|
|
1238
1241
|
}
|
|
1239
1242
|
});
|
|
@@ -61,6 +61,8 @@ const FONT_STRETCHES = {
|
|
|
61
61
|
};
|
|
62
62
|
const Blob = globalThis.Blob;
|
|
63
63
|
const FileReader = globalThis.FileReader;
|
|
64
|
+
const Image = globalThis.Image;
|
|
65
|
+
const OffscreenCanvas = globalThis.OffscreenCanvas;
|
|
64
66
|
|
|
65
67
|
let util, cssTree;
|
|
66
68
|
|
|
@@ -77,6 +79,7 @@ export {
|
|
|
77
79
|
testIgnoredPath,
|
|
78
80
|
testValidPath,
|
|
79
81
|
testValidURL,
|
|
82
|
+
resizeImage,
|
|
80
83
|
toDataURI
|
|
81
84
|
};
|
|
82
85
|
|
|
@@ -105,7 +108,8 @@ class ProcessorHelperCommon {
|
|
|
105
108
|
this.processAttribute(doc.querySelectorAll(selector), attributeName, baseURI, options, "image", resources, removeElementIfMissing, batchRequest, styles, processDuplicates)
|
|
106
109
|
);
|
|
107
110
|
resourcePromises = resourcePromises.concat([
|
|
108
|
-
this.processXLinks(doc.querySelectorAll("use"), doc, baseURI, options, batchRequest),
|
|
111
|
+
this.processXLinks(doc.querySelectorAll("use"), doc, baseURI, options, batchRequest, "xlink:href"),
|
|
112
|
+
this.processXLinks(doc.querySelectorAll("use"), doc, baseURI, options, batchRequest, "href"),
|
|
109
113
|
this.processSrcset(doc.querySelectorAll("img[srcset], source[srcset]"), baseURI, options, resources, batchRequest)
|
|
110
114
|
]);
|
|
111
115
|
resourcePromises.push(this.processAttribute(doc.querySelectorAll("object[data*=\".pdf\"]"), "data", baseURI, options, null, resources, false, batchRequest, styles));
|
|
@@ -120,8 +124,7 @@ class ProcessorHelperCommon {
|
|
|
120
124
|
}
|
|
121
125
|
}
|
|
122
126
|
|
|
123
|
-
async processXLinks(resourceElements, doc, baseURI, options, batchRequest) {
|
|
124
|
-
let attributeName = "xlink:href";
|
|
127
|
+
async processXLinks(resourceElements, doc, baseURI, options, batchRequest, attributeName) {
|
|
125
128
|
await Promise.all(Array.from(resourceElements).map(async resourceElement => {
|
|
126
129
|
let originalResourceURL = resourceElement.getAttribute(attributeName);
|
|
127
130
|
if (originalResourceURL == null) {
|
|
@@ -330,7 +333,7 @@ class ProcessorHelperCommon {
|
|
|
330
333
|
|
|
331
334
|
replacePseudoClassDefined(stylesheet) {
|
|
332
335
|
cssTree.walk(stylesheet, {
|
|
333
|
-
enter: function(node, item, list) {
|
|
336
|
+
enter: function (node, item, list) {
|
|
334
337
|
if (node.type == "PseudoClassSelector" && node.name == "defined") {
|
|
335
338
|
if (item.prev == null || item.prev.data.type == "Combinator" || item.prev.data.type == "WhiteSpace") {
|
|
336
339
|
list.replace(item, cssTree.parse("*", { context: "selector" }).children.head);
|
|
@@ -659,11 +662,42 @@ function getFontStretch(stretch) {
|
|
|
659
662
|
return FONT_STRETCHES[stretch] || stretch;
|
|
660
663
|
}
|
|
661
664
|
|
|
665
|
+
async function resizeImage(dataURI, { imageReductionFactor }) {
|
|
666
|
+
if (dataURI) {
|
|
667
|
+
const contentType = dataURI.substring(5, dataURI.indexOf(";"));
|
|
668
|
+
if (contentType == "image/jpeg" ||
|
|
669
|
+
contentType == "image/png" ||
|
|
670
|
+
contentType == "image/webp") {
|
|
671
|
+
try {
|
|
672
|
+
const image = new Image();
|
|
673
|
+
image.src = dataURI;
|
|
674
|
+
await new Promise((resolve, reject) => {
|
|
675
|
+
image.onload = resolve;
|
|
676
|
+
image.onerror = reject;
|
|
677
|
+
});
|
|
678
|
+
const width = image.naturalWidth / imageReductionFactor;
|
|
679
|
+
const height = image.naturalHeight / imageReductionFactor;
|
|
680
|
+
const canvas = new OffscreenCanvas(width, height);
|
|
681
|
+
const context = canvas.getContext("2d");
|
|
682
|
+
context.drawImage(image, 0, 0, width, height);
|
|
683
|
+
const blob = await canvas.convertToBlob({ type: contentType });
|
|
684
|
+
if (blob.type == contentType) {
|
|
685
|
+
dataURI = await toDataURI(blob, contentType);
|
|
686
|
+
}
|
|
687
|
+
} catch {
|
|
688
|
+
// ignored
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return dataURI;
|
|
693
|
+
}
|
|
694
|
+
|
|
662
695
|
function toDataURI(content, contentType, charset) {
|
|
696
|
+
const blob = content instanceof Blob ? content : new Blob([content], { type: (contentType || "") + (charset ? ";charset=" + charset : "") });
|
|
663
697
|
return new Promise((resolve, reject) => {
|
|
664
698
|
const reader = new FileReader();
|
|
665
699
|
reader.onload = () => resolve(reader.result);
|
|
666
700
|
reader.onerror = () => reject(new Error(reader.error));
|
|
667
|
-
reader.readAsDataURL(
|
|
701
|
+
reader.readAsDataURL(blob);
|
|
668
702
|
});
|
|
669
703
|
}
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
testIgnoredPath,
|
|
60
60
|
testValidPath,
|
|
61
61
|
testValidURL,
|
|
62
|
+
resizeImage,
|
|
62
63
|
toDataURI
|
|
63
64
|
} from "./processor-helper-common.js";
|
|
64
65
|
|
|
@@ -99,9 +100,12 @@ function getProcessorHelperClass(utilInstance) {
|
|
|
99
100
|
this.removeSingleLineCssComments(stylesheet);
|
|
100
101
|
}
|
|
101
102
|
this.replacePseudoClassDefined(stylesheet);
|
|
102
|
-
options.inlineStylesheets.forEach((content, index) => {
|
|
103
|
+
options.inlineStylesheets.forEach(({ content, styleElement }, index) => {
|
|
103
104
|
if (content === element.textContent) {
|
|
104
|
-
options.inlineStylesheets.set(index,
|
|
105
|
+
options.inlineStylesheets.set(index, {
|
|
106
|
+
styleElement,
|
|
107
|
+
content: this.generateStylesheetContent(stylesheet, options)
|
|
108
|
+
});
|
|
105
109
|
}
|
|
106
110
|
});
|
|
107
111
|
stylesheetInfo.stylesheet = stylesheet;
|
|
@@ -112,31 +116,39 @@ function getProcessorHelperClass(utilInstance) {
|
|
|
112
116
|
}
|
|
113
117
|
|
|
114
118
|
replaceStylesheets(doc, stylesheets, options) {
|
|
115
|
-
doc.querySelectorAll("style").forEach(
|
|
116
|
-
const stylesheetInfo = stylesheets.get(
|
|
119
|
+
doc.querySelectorAll("style").forEach(element => {
|
|
120
|
+
const stylesheetInfo = stylesheets.get(element);
|
|
117
121
|
if (stylesheetInfo) {
|
|
118
|
-
stylesheets.delete(
|
|
119
|
-
const stylesheetRefIndex = options.inlineStylesheetsRefs.get(
|
|
122
|
+
stylesheets.delete(element);
|
|
123
|
+
const stylesheetRefIndex = options.inlineStylesheetsRefs.get(element);
|
|
120
124
|
if (stylesheetRefIndex === undefined) {
|
|
121
|
-
|
|
125
|
+
element.textContent = this.generateStylesheetContent(stylesheetInfo.stylesheet, options);
|
|
126
|
+
options.inlineStylesheets.forEach(({ styleElement }, index) => {
|
|
127
|
+
if (styleElement === element) {
|
|
128
|
+
options.inlineStylesheets.set(index, {
|
|
129
|
+
styleElement,
|
|
130
|
+
content: element.textContent
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
});
|
|
122
134
|
} else if (options.groupDuplicateStylesheets) {
|
|
123
135
|
if (!doc.querySelector("style[" + DUPLICATE_STYLESHEET_ATTRIBUTE_NAME + "=\"" + stylesheetRefIndex + "\"]")) {
|
|
124
136
|
const styleElement = doc.createElement("style");
|
|
125
|
-
styleElement.textContent = options.inlineStylesheets.get(stylesheetRefIndex);
|
|
137
|
+
styleElement.textContent = options.inlineStylesheets.get(stylesheetRefIndex).content;
|
|
126
138
|
styleElement.setAttribute("media", "not all");
|
|
127
139
|
styleElement.setAttribute(DUPLICATE_STYLESHEET_ATTRIBUTE_NAME, stylesheetRefIndex);
|
|
128
140
|
doc.head.appendChild(styleElement);
|
|
129
141
|
}
|
|
130
|
-
|
|
131
|
-
|
|
142
|
+
element.textContent = "/* */";
|
|
143
|
+
element.setAttribute("onload", "this.textContent=document.querySelector('style[" + DUPLICATE_STYLESHEET_ATTRIBUTE_NAME + "=\"" + stylesheetRefIndex + "\"]')?.textContent;this.removeAttribute(\"onload\")");
|
|
132
144
|
} else {
|
|
133
|
-
|
|
145
|
+
element.textContent = options.inlineStylesheets.get(stylesheetRefIndex).content;
|
|
134
146
|
}
|
|
135
147
|
if (stylesheetInfo.mediaText) {
|
|
136
|
-
|
|
148
|
+
element.media = stylesheetInfo.mediaText;
|
|
137
149
|
}
|
|
138
150
|
} else {
|
|
139
|
-
|
|
151
|
+
element.remove();
|
|
140
152
|
}
|
|
141
153
|
});
|
|
142
154
|
if (options.groupDuplicateStylesheets && doc.querySelector("style[" + DUPLICATE_STYLESHEET_ATTRIBUTE_NAME + "]")) {
|
|
@@ -377,6 +389,9 @@ function getProcessorHelperClass(utilInstance) {
|
|
|
377
389
|
}
|
|
378
390
|
}
|
|
379
391
|
}
|
|
392
|
+
if (options.imageReductionFactor > 1) {
|
|
393
|
+
content = await resizeImage(content, options);
|
|
394
|
+
}
|
|
380
395
|
if (removeElementIfMissing && this.testEmptyResource(content)) {
|
|
381
396
|
resourceElement.remove();
|
|
382
397
|
} else if (!this.testEmptyResource(content)) {
|
|
@@ -25,6 +25,7 @@ import * as cssTree from "./../../vendor/css-tree.js";
|
|
|
25
25
|
|
|
26
26
|
const JSON = globalThis.JSON;
|
|
27
27
|
const FontFace = globalThis.FontFace;
|
|
28
|
+
const Blob = globalThis.Blob;
|
|
28
29
|
|
|
29
30
|
const ABOUT_BLANK_URI = "about:blank";
|
|
30
31
|
const UTF8_CHARSET = "utf-8";
|
|
@@ -49,7 +50,9 @@ import {
|
|
|
49
50
|
replaceOriginalURLs,
|
|
50
51
|
testIgnoredPath,
|
|
51
52
|
testValidPath,
|
|
52
|
-
testValidURL
|
|
53
|
+
testValidURL,
|
|
54
|
+
resizeImage,
|
|
55
|
+
toDataURI
|
|
53
56
|
} from "./processor-helper-common.js";
|
|
54
57
|
|
|
55
58
|
export {
|
|
@@ -102,7 +105,7 @@ function getProcessorHelperClass(utilInstance) {
|
|
|
102
105
|
linkElement.setAttribute("type", "text/css");
|
|
103
106
|
const name = "stylesheet_" + resources.stylesheets.size + ".css";
|
|
104
107
|
linkElement.setAttribute("href", name);
|
|
105
|
-
let content = options.inlineStylesheets.get(stylesheetRefIndex);
|
|
108
|
+
let { content } = options.inlineStylesheets.get(stylesheetRefIndex);
|
|
106
109
|
const stylesheet = cssTree.parse(content, { context: "stylesheet", parseCustomProperty: true });
|
|
107
110
|
this.replacePseudoClassDefined(stylesheet);
|
|
108
111
|
content = this.generateStylesheetContent(stylesheet, options);
|
|
@@ -324,7 +327,7 @@ function getProcessorHelperClass(utilInstance) {
|
|
|
324
327
|
}
|
|
325
328
|
if (testValidURL(resourceURL)) {
|
|
326
329
|
const declaredContentType = ["OBJECT", "EMBED"].includes(resourceElement.tagName.toUpperCase()) ? resourceElement.getAttribute("type") : "";
|
|
327
|
-
let { content, indexResource, extension, contentType } = await batchRequest.addURL(resourceURL,
|
|
330
|
+
let { content, indexResource, extension, contentType, charset } = await batchRequest.addURL(resourceURL,
|
|
328
331
|
{ asBinary: true, expectedType, contentType: declaredContentType });
|
|
329
332
|
if (originURL) {
|
|
330
333
|
if (this.testEmptyResource(content)) {
|
|
@@ -353,6 +356,10 @@ function getProcessorHelperClass(utilInstance) {
|
|
|
353
356
|
}
|
|
354
357
|
}
|
|
355
358
|
}
|
|
359
|
+
if (options.imageReductionFactor > 1) {
|
|
360
|
+
const dataURI = await resizeImage(await toDataURI(new Blob([content], { type: contentType }), charset), options);
|
|
361
|
+
content = (await util.getContent(dataURI, { asBinary: true })).data;
|
|
362
|
+
}
|
|
356
363
|
if (removeElementIfMissing && this.testEmptyResource(content)) {
|
|
357
364
|
resourceElement.remove();
|
|
358
365
|
} else if (!this.testEmptyResource(content)) {
|
|
@@ -294,11 +294,12 @@ function processSelectors(ruleData, processingContext, docContext) {
|
|
|
294
294
|
scopeRelative
|
|
295
295
|
} = analyzeSelector(selector.data);
|
|
296
296
|
registerSelector(selector, ruleData, scopeRelative, processingContext, docContext);
|
|
297
|
-
if (!
|
|
298
|
-
(!startsWithCombinator || !ancestorsSelectors || !ancestorsSelectors.length)) {
|
|
297
|
+
if (!startsWithCombinator || !ancestorsSelectors || !ancestorsSelectors.length) {
|
|
299
298
|
const matchedElements = matchElements(selector, ancestorsSelectors, docContext);
|
|
300
299
|
if (matchedElements.length) {
|
|
301
|
-
|
|
300
|
+
if (!hasPseudoElement && !hasDynamicStatePseudoClass) {
|
|
301
|
+
updateMatchingSelectors(matchedElements, selector, docContext);
|
|
302
|
+
}
|
|
302
303
|
} else {
|
|
303
304
|
removedSelectors.push(selector);
|
|
304
305
|
}
|
|
@@ -46,6 +46,8 @@ const UNMATCHABLE_PSEUDO_CLASSES = [
|
|
|
46
46
|
"seeking",
|
|
47
47
|
"stalled",
|
|
48
48
|
"volume-locked",
|
|
49
|
+
"after",
|
|
50
|
+
"before"
|
|
49
51
|
];
|
|
50
52
|
|
|
51
53
|
export {
|
|
@@ -57,7 +59,9 @@ export {
|
|
|
57
59
|
* Optional `ancestors` array may be provided to expand nesting selectors (`&`).
|
|
58
60
|
*/
|
|
59
61
|
function sanitizeSelector(selector, ancestors, docContext) {
|
|
60
|
-
if (!docContext.normalizedSelectorText)
|
|
62
|
+
if (!docContext.normalizedSelectorText) {
|
|
63
|
+
docContext.normalizedSelectorText = new WeakMap();
|
|
64
|
+
}
|
|
61
65
|
if (docContext.normalizedSelectorText.has(selector)) {
|
|
62
66
|
return docContext.normalizedSelectorText.get(selector);
|
|
63
67
|
}
|