single-file-core 1.3.14 → 1.3.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 +2 -0
- package/core/index.js +14 -6
- package/core/lib/processor-helper.js +1 -1
- package/modules/template-formatter.js +8 -1
- package/package.json +1 -1
- package/processors/compression/compression-display.js +22 -28
- package/processors/compression/compression.js +115 -30
- package/processors/frame-tree/content/content-frame-tree.js +33 -28
- package/processors/hooks/content/content-hooks-frames-web.js +81 -89
- package/processors/hooks/content/content-hooks-frames.js +32 -28
- package/processors/lazy/content/content-lazy-loader.js +4 -6
- package/single-file-infobar.js +16 -11
- package/single-file.js +1 -0
package/core/helper.js
CHANGED
|
@@ -82,6 +82,7 @@ const crypto = globalThis.crypto;
|
|
|
82
82
|
const TextEncoder = globalThis.TextEncoder;
|
|
83
83
|
const Blob = globalThis.Blob;
|
|
84
84
|
const CustomEvent = globalThis.CustomEvent;
|
|
85
|
+
const MutationObserver = globalThis.MutationObserver;
|
|
85
86
|
|
|
86
87
|
export {
|
|
87
88
|
initUserScriptHandler,
|
|
@@ -135,6 +136,7 @@ function initUserScriptHandler() {
|
|
|
135
136
|
await promiseResponse;
|
|
136
137
|
}
|
|
137
138
|
});
|
|
139
|
+
new MutationObserver(initUserScriptHandler).observe(globalThis.document, { childList: true });
|
|
138
140
|
}
|
|
139
141
|
|
|
140
142
|
function initDoc(doc) {
|
package/core/index.js
CHANGED
|
@@ -473,13 +473,20 @@ class Processor {
|
|
|
473
473
|
this.doc = util.parseDocContent(pageContent, this.baseURI);
|
|
474
474
|
if (this.options.saveRawPage) {
|
|
475
475
|
let charset;
|
|
476
|
-
this.doc.querySelectorAll("meta[charset]
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
charset = charsetDeclaration.split("=")[1].trim().toLowerCase();
|
|
476
|
+
this.doc.querySelectorAll("meta[charset]").forEach(element => {
|
|
477
|
+
if (!charset) {
|
|
478
|
+
charset = element.getAttribute("charset").trim().toLowerCase();
|
|
480
479
|
}
|
|
481
480
|
});
|
|
482
|
-
if (charset
|
|
481
|
+
if (!charset) {
|
|
482
|
+
this.doc.querySelectorAll("meta[http-equiv=\"content-type\"]").forEach(element => {
|
|
483
|
+
const charsetDeclaration = element.content.split(";")[1];
|
|
484
|
+
if (charsetDeclaration && !charset) {
|
|
485
|
+
charset = charsetDeclaration.split("=")[1].trim().toLowerCase();
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
if (charset && content.charset && charset != content.charset.toLowerCase()) {
|
|
483
490
|
return this.loadPage(pageContent, charset);
|
|
484
491
|
}
|
|
485
492
|
}
|
|
@@ -857,7 +864,7 @@ class Processor {
|
|
|
857
864
|
this.stats.set("discarded", "objects", objectElements.length);
|
|
858
865
|
this.stats.set("processed", "objects", objectElements.length);
|
|
859
866
|
objectElements.forEach(element => element.remove());
|
|
860
|
-
const replacedAttributeValue = this.doc.querySelectorAll("link[rel~=preconnect], link[rel~=prerender], link[rel~=dns-prefetch], link[rel~=preload], link[rel~=manifest], link[rel~=prefetch]");
|
|
867
|
+
const replacedAttributeValue = this.doc.querySelectorAll("link[rel~=preconnect], link[rel~=prerender], link[rel~=dns-prefetch], link[rel~=preload], link[rel~=manifest], link[rel~=prefetch], link[rel~=modulepreload]");
|
|
861
868
|
replacedAttributeValue.forEach(element => {
|
|
862
869
|
const relValue = element
|
|
863
870
|
.getAttribute("rel")
|
|
@@ -1223,6 +1230,7 @@ class Processor {
|
|
|
1223
1230
|
options.includeInfobar = false;
|
|
1224
1231
|
options.saveFilenameTemplateData = false;
|
|
1225
1232
|
options.selected = false;
|
|
1233
|
+
options.embeddedImage = null;
|
|
1226
1234
|
options.url = frameData.baseURI;
|
|
1227
1235
|
options.windowId = frameWindowId;
|
|
1228
1236
|
if (frameData.content) {
|
|
@@ -394,7 +394,7 @@ function getProcessorHelperClass(utilInstance) {
|
|
|
394
394
|
}
|
|
395
395
|
|
|
396
396
|
setMetaCSP(metaElement) {
|
|
397
|
-
metaElement.content = "default-src 'none'; font-src 'self' data: blob:; img-src 'self' data: blob:; style-src 'self' 'unsafe-inline' data: blob:; frame-src 'self' data: blob:; media-src 'self' data: blob:; script-src 'self' 'unsafe-inline' data: blob:; object-src 'self' data: blob:;";
|
|
397
|
+
metaElement.content = "default-src 'none'; connect-src 'self'; font-src 'self' data: blob:; img-src 'self' data: blob:; style-src 'self' 'unsafe-inline' data: blob:; frame-src 'self' data: blob:; media-src 'self' data: blob:; script-src 'self' 'unsafe-inline' data: blob:; object-src 'self' data: blob:;";
|
|
398
398
|
}
|
|
399
399
|
|
|
400
400
|
removeUnusedStylesheets() {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
import { parse } from "./template-parser.js";
|
|
27
27
|
import { getContentSize, digest } from "./../core/helper.js";
|
|
28
28
|
|
|
29
|
-
const Blob = globalThis.Blob;
|
|
29
|
+
const Blob = globalThis.Blob;
|
|
30
30
|
const FileReader = globalThis.FileReader;
|
|
31
31
|
const URL = globalThis.URL;
|
|
32
32
|
const URLSearchParams = globalThis.URLSearchParams;
|
|
@@ -16991,6 +16991,10 @@ async function evalTemplate(template = "", options, content, doc, dontReplaceSla
|
|
|
16991
16991
|
"length": value => value.length,
|
|
16992
16992
|
"url-search-name": (index = 0) => params[index] && params[index][0],
|
|
16993
16993
|
"url-search-value": (index = 0) => params[index] && params[index][1],
|
|
16994
|
+
"url-search-named-value": name => {
|
|
16995
|
+
const param = params.find(param => param[0] == name);
|
|
16996
|
+
return (param && param[1]);
|
|
16997
|
+
},
|
|
16994
16998
|
"url-search": name => {
|
|
16995
16999
|
const param = params.find(param => param[0] == name);
|
|
16996
17000
|
return (param && param[1]);
|
|
@@ -17030,6 +17034,9 @@ async function evalTemplate(template = "", options, content, doc, dontReplaceSla
|
|
|
17030
17034
|
const fn = functions[name];
|
|
17031
17035
|
if (fn) {
|
|
17032
17036
|
argument = argument.replace(/\\\\(.)/g, "$1");
|
|
17037
|
+
if (!optionalArguments) {
|
|
17038
|
+
optionalArguments = [];
|
|
17039
|
+
}
|
|
17033
17040
|
optionalArguments = optionalArguments
|
|
17034
17041
|
.map(argument => argument.replace(/\\\\(.)/g, "$1"))
|
|
17035
17042
|
.filter(argument => argument != undefined && argument != null && argument != "");
|
package/package.json
CHANGED
|
@@ -31,15 +31,6 @@ async function display(document, docContent, { disableFramePointerEvents } = {})
|
|
|
31
31
|
docContent = docContent.replace(/<noscript/gi, "<template disabled-noscript");
|
|
32
32
|
docContent = docContent.replaceAll(/<\/noscript/gi, "</template");
|
|
33
33
|
const doc = (new DOMParser()).parseFromString(docContent, "text/html");
|
|
34
|
-
if (doc.doctype) {
|
|
35
|
-
if (document.doctype) {
|
|
36
|
-
document.replaceChild(doc.doctype, document.doctype);
|
|
37
|
-
} else {
|
|
38
|
-
document.insertBefore(doc.doctype, document.documentElement);
|
|
39
|
-
}
|
|
40
|
-
} else if (document.doctype) {
|
|
41
|
-
document.doctype.remove();
|
|
42
|
-
}
|
|
43
34
|
if (disableFramePointerEvents) {
|
|
44
35
|
doc.querySelectorAll("iframe").forEach(element => {
|
|
45
36
|
const pointerEvents = "pointer-events";
|
|
@@ -47,7 +38,10 @@ async function display(document, docContent, { disableFramePointerEvents } = {})
|
|
|
47
38
|
element.style.setProperty(pointerEvents, "none", "important");
|
|
48
39
|
});
|
|
49
40
|
}
|
|
50
|
-
document.
|
|
41
|
+
document.open();
|
|
42
|
+
document.write(getDoctypeString(doc));
|
|
43
|
+
document.write(doc.documentElement.outerHTML);
|
|
44
|
+
document.close();
|
|
51
45
|
document.querySelectorAll("template[disabled-noscript]").forEach(element => {
|
|
52
46
|
const noscriptElement = document.createElement("noscript");
|
|
53
47
|
element.removeAttribute("disabled-noscript");
|
|
@@ -57,22 +51,22 @@ async function display(document, docContent, { disableFramePointerEvents } = {})
|
|
|
57
51
|
});
|
|
58
52
|
document.documentElement.setAttribute("data-sfz", "");
|
|
59
53
|
document.querySelectorAll("link[rel*=icon]").forEach(element => element.parentElement.replaceChild(element, element));
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
54
|
+
|
|
55
|
+
function getDoctypeString(doc) {
|
|
56
|
+
const docType = doc.doctype;
|
|
57
|
+
let docTypeString = "";
|
|
58
|
+
if (docType) {
|
|
59
|
+
docTypeString = "<!DOCTYPE " + docType.nodeName;
|
|
60
|
+
if (docType.publicId) {
|
|
61
|
+
docTypeString += " PUBLIC \"" + docType.publicId + "\"";
|
|
62
|
+
if (docType.systemId)
|
|
63
|
+
docTypeString += " \"" + docType.systemId + "\"";
|
|
64
|
+
} else if (docType.systemId)
|
|
65
|
+
docTypeString += " SYSTEM \"" + docType.systemId + "\"";
|
|
66
|
+
if (docType.internalSubset)
|
|
67
|
+
docTypeString += " [" + docType.internalSubset + "]";
|
|
68
|
+
docTypeString += "> ";
|
|
69
|
+
}
|
|
70
|
+
return docTypeString;
|
|
77
71
|
}
|
|
78
|
-
}
|
|
72
|
+
}
|
|
@@ -47,12 +47,30 @@ const EXTRA_DATA_TAGS = [
|
|
|
47
47
|
["<xmp>", "</xmp>"],
|
|
48
48
|
["<plaintext>", "</plaintext>"]
|
|
49
49
|
];
|
|
50
|
+
const EMBEDDED_IMAGE_DATA_TAGS = [
|
|
51
|
+
["<!--", "-->"],
|
|
52
|
+
...EXTRA_DATA_TAGS,
|
|
53
|
+
];
|
|
50
54
|
const EXTRA_DATA_REGEXPS = [
|
|
51
55
|
[/<\/noscript>/i],
|
|
52
56
|
[/<\/script>/i],
|
|
53
57
|
[/<\/xmp>/i],
|
|
54
58
|
[/<\/plaintext>/i]
|
|
55
59
|
];
|
|
60
|
+
const EMBEDDED_IMAGE_DATA_REGEXPS = [
|
|
61
|
+
/-->/i,
|
|
62
|
+
...EXTRA_DATA_REGEXPS,
|
|
63
|
+
];
|
|
64
|
+
const CRC32_TABLE = new Uint32Array(256).map((_, indexTable) => {
|
|
65
|
+
let crc = indexTable;
|
|
66
|
+
for (let indexBits = 0; indexBits < 8; indexBits++) {
|
|
67
|
+
crc = crc & 1 ? 0xEDB88320 ^ (crc >>> 1) : crc >>> 1;
|
|
68
|
+
}
|
|
69
|
+
return crc;
|
|
70
|
+
});
|
|
71
|
+
const PNG_IEND_LENGTH = 12;
|
|
72
|
+
const PNG_SIGNATURE_LENGTH = 8;
|
|
73
|
+
const PNG_IHDR_LENGTH = 25;
|
|
56
74
|
|
|
57
75
|
const browser = globalThis.browser;
|
|
58
76
|
|
|
@@ -70,7 +88,29 @@ async function process(pageData, options, lastModDate = new Date()) {
|
|
|
70
88
|
}
|
|
71
89
|
const zipDataWriter = new Uint8ArrayWriter();
|
|
72
90
|
zipDataWriter.init();
|
|
73
|
-
|
|
91
|
+
zipDataWriter.writable.size = 0;
|
|
92
|
+
let extraDataOffset, extraData, embeddedImageDataOffset, endTag;
|
|
93
|
+
if (options.embeddedImage) {
|
|
94
|
+
const embeddedImageData = options.embeddedImage.slice(PNG_SIGNATURE_LENGTH + PNG_IHDR_LENGTH, options.embeddedImage.length - PNG_IEND_LENGTH);
|
|
95
|
+
await writeData(zipDataWriter.writable, options.embeddedImage.slice(0, PNG_SIGNATURE_LENGTH + PNG_IHDR_LENGTH));
|
|
96
|
+
if (options.selfExtractingArchive) {
|
|
97
|
+
const embeddedImageText = embeddedImageData.reduce((text, charCode) => text + String.fromCharCode(charCode), "");
|
|
98
|
+
const tagIndex = EMBEDDED_IMAGE_DATA_REGEXPS.findIndex(test => !embeddedImageText.match(test));
|
|
99
|
+
let startTag;
|
|
100
|
+
[startTag, endTag] = tagIndex == -1 ? ["", ""] : EMBEDDED_IMAGE_DATA_TAGS[tagIndex];
|
|
101
|
+
const html = getHTMLStartData(pageData, options) + startTag;
|
|
102
|
+
const hmtlData = new Uint8Array([...getLength(html.length + 4), ...new Uint8Array([0x74, 0x54, 0x58, 0x74, 0x50, 0x4e, 0x47, 0]), ...new TextEncoder().encode(html)]);
|
|
103
|
+
await writeData(zipDataWriter.writable, hmtlData);
|
|
104
|
+
await writeData(zipDataWriter.writable, getCRC32(hmtlData, 4));
|
|
105
|
+
}
|
|
106
|
+
await writeData(zipDataWriter.writable, embeddedImageData);
|
|
107
|
+
await writeData(zipDataWriter.writable, new Uint8Array(4));
|
|
108
|
+
embeddedImageDataOffset = zipDataWriter.offset;
|
|
109
|
+
await writeData(zipDataWriter.writable, new Uint8Array([0x74, 0x54, 0x58, 0x74, 0x5a, 0x49, 0x50, 0]));
|
|
110
|
+
if (options.selfExtractingArchive) {
|
|
111
|
+
await writeData(zipDataWriter.writable, new TextEncoder().encode(endTag));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
74
114
|
if (options.selfExtractingArchive) {
|
|
75
115
|
extraDataOffset = await prependHTMLData(pageData, zipDataWriter, script, options);
|
|
76
116
|
}
|
|
@@ -92,7 +132,7 @@ async function process(pageData, options, lastModDate = new Date()) {
|
|
|
92
132
|
return findExtraDataTags(textContent, pageData, options, lastModDate);
|
|
93
133
|
}
|
|
94
134
|
}
|
|
95
|
-
for (let index =
|
|
135
|
+
for (let index = startOffset; index < data.length; index++) {
|
|
96
136
|
if (data[index] == 13) {
|
|
97
137
|
if (data[index + 1] == 10) {
|
|
98
138
|
insertionsCRLF.push(index - startOffset);
|
|
@@ -110,14 +150,14 @@ async function process(pageData, options, lastModDate = new Date()) {
|
|
|
110
150
|
pageContent += "-->";
|
|
111
151
|
}
|
|
112
152
|
}
|
|
113
|
-
const endTags = options.preventAppendedData ? "" : "</body></html>";
|
|
153
|
+
const endTags = options.preventAppendedData || options.embeddedImage ? "" : "</body></html>";
|
|
114
154
|
if (options.extractDataFromPage) {
|
|
115
155
|
const payload = await Promise.all([
|
|
116
156
|
arrayToBase64(insertionsCRLF),
|
|
117
157
|
arrayToBase64(substitutionsLF)
|
|
118
158
|
]);
|
|
119
159
|
extraData = "<sfz-extra-data>" + payload.join(",") + "</sfz-extra-data>";
|
|
120
|
-
if (options.preventAppendedData || extraData.length > 65535 - endTags.length) {
|
|
160
|
+
if (options.preventAppendedData || extraData.length > 65535 - endTags.length - (options.embeddedImage ? PNG_IEND_LENGTH : 0)) {
|
|
121
161
|
if (!options.extraDataSize) {
|
|
122
162
|
options.extraDataSize = Math.floor(extraData.length * 1.001);
|
|
123
163
|
return process(pageData, options, lastModDate);
|
|
@@ -132,9 +172,7 @@ async function process(pageData, options, lastModDate = new Date()) {
|
|
|
132
172
|
}
|
|
133
173
|
}
|
|
134
174
|
pageContent += endTags;
|
|
135
|
-
|
|
136
|
-
await writeData(zipDataWriter.writable, (new TextEncoder()).encode(pageContent));
|
|
137
|
-
}
|
|
175
|
+
await writeData(zipDataWriter.writable, (new TextEncoder()).encode(pageContent));
|
|
138
176
|
}
|
|
139
177
|
await zipDataWriter.writable.close();
|
|
140
178
|
const pageContent = await zipDataWriter.getData();
|
|
@@ -147,31 +185,49 @@ async function process(pageData, options, lastModDate = new Date()) {
|
|
|
147
185
|
return process(pageData, options, lastModDate);
|
|
148
186
|
}
|
|
149
187
|
}
|
|
150
|
-
|
|
188
|
+
if (options.embeddedImage) {
|
|
189
|
+
pageContent.set(getLength(zipDataWriter.offset - embeddedImageDataOffset - 4), embeddedImageDataOffset - 4);
|
|
190
|
+
return new Blob([
|
|
191
|
+
pageContent,
|
|
192
|
+
getCRC32(pageContent, embeddedImageDataOffset),
|
|
193
|
+
options.embeddedImage.slice(options.embeddedImage.length - PNG_IEND_LENGTH)
|
|
194
|
+
], { type: "application/octet-stream" });
|
|
195
|
+
} else {
|
|
196
|
+
return new Blob([pageContent], { type: "application/octet-stream" });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function getCRC32(data, indexData = 0) {
|
|
201
|
+
const crcArray = new Uint8Array(4);
|
|
202
|
+
let crc = -1;
|
|
203
|
+
for (; indexData < data.length; indexData++) {
|
|
204
|
+
crc = (crc >>> 8) ^ CRC32_TABLE[(crc ^ data[indexData]) & 0xff];
|
|
205
|
+
}
|
|
206
|
+
crc ^= -1;
|
|
207
|
+
setUint32(crcArray, crc);
|
|
208
|
+
return crcArray;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function getLength(length) {
|
|
212
|
+
const lengthArray = new Uint8Array(4);
|
|
213
|
+
setUint32(lengthArray, length);
|
|
214
|
+
return lengthArray;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function setUint32(data, value) {
|
|
218
|
+
data[0] = value >> 24;
|
|
219
|
+
data[1] = value >> 16;
|
|
220
|
+
data[2] = value >> 8;
|
|
221
|
+
data[3] = value;
|
|
151
222
|
}
|
|
152
223
|
|
|
153
224
|
async function prependHTMLData(pageData, zipDataWriter, script, options) {
|
|
154
225
|
let pageContent = "";
|
|
155
|
-
if (
|
|
156
|
-
pageContent +=
|
|
226
|
+
if (!options.embeddedImage) {
|
|
227
|
+
pageContent += getHTMLStartData(pageData, options);
|
|
157
228
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const title = options.extractDataFromPage ? "" : pageDataTitle;
|
|
161
|
-
pageContent += pageData.doctype + "<html data-sfz><meta charset=" + charset + "><title>" + title + "</title>";
|
|
162
|
-
if (options.insertCanonicalLink) {
|
|
163
|
-
pageContent += "<link rel=canonical href=\"" + options.url + "\">";
|
|
164
|
-
}
|
|
165
|
-
if (options.insertMetaNoIndex) {
|
|
166
|
-
pageContent += "<meta name=robots content=noindex>";
|
|
167
|
-
}
|
|
168
|
-
if (pageData.viewport) {
|
|
169
|
-
pageContent += "<meta name=\"viewport\" content=" + JSON.stringify(pageData.viewport) + ">";
|
|
170
|
-
}
|
|
171
|
-
pageContent += "<style>@keyframes display-wait-message{0%{opacity:0}100%{opacity:1}}</style>";
|
|
172
|
-
pageContent += "<body hidden>";
|
|
173
|
-
pageContent += "<div id='sfz-wait-message'>Please wait...</div>";
|
|
174
|
-
pageContent += "<div id='sfz-error-message'><strong>Error</strong>: Cannot open the page from the filesystem.";
|
|
229
|
+
pageContent += "<div id=sfz-wait-message>Please wait...</div>";
|
|
230
|
+
pageContent += "<div id=sfz-error-message><strong>Error</strong>: Cannot open the page from the filesystem.";
|
|
175
231
|
pageContent += "<ul style='line-height:20px;'>";
|
|
176
232
|
pageContent += "<li style='margin-bottom:10px'><strong>Chrome</strong>: Install <a href='https://chrome.google.com/webstore/detail/singlefile/mpiodijhokgodhhofbcjdecpffjipkle'>SingleFile</a> and enable the option \"Allow access to file URLs\" in the details page of the extension (chrome://extensions/?id=mpiodijhokgodhhofbcjdecpffjipkle).</li>";
|
|
177
233
|
pageContent += "<li style='margin-bottom:10px'><strong>Microsoft Edge</strong>: Install <a href='https://microsoftedge.microsoft.com/addons/detail/singlefile/efnbkdcfmcmnhlkaijjjmhjjgladedno'>SingleFile</a> and enable the option \"Allow access to file URLs\" in the details page of the extension (edge://extensions/?id=efnbkdcfmcmnhlkaijjjmhjjgladedno).</li>";
|
|
@@ -181,7 +237,7 @@ async function prependHTMLData(pageData, zipDataWriter, script, options) {
|
|
|
181
237
|
doc.body.querySelectorAll("style, script, noscript").forEach(element => element.remove());
|
|
182
238
|
let textBody = "";
|
|
183
239
|
if (options.extractDataFromPage) {
|
|
184
|
-
textBody +=
|
|
240
|
+
textBody += getPageTitle(pageData) + "\n\n";
|
|
185
241
|
}
|
|
186
242
|
textBody += doc.body.innerText;
|
|
187
243
|
doc.body.querySelectorAll("single-file-note").forEach(node => {
|
|
@@ -218,6 +274,32 @@ async function prependHTMLData(pageData, zipDataWriter, script, options) {
|
|
|
218
274
|
return extraDataOffset;
|
|
219
275
|
}
|
|
220
276
|
|
|
277
|
+
function getHTMLStartData(pageData, options) {
|
|
278
|
+
let pageContent = "";
|
|
279
|
+
if (options.includeBOM && !options.extractDataFromPage && !options.embeddedImage) {
|
|
280
|
+
pageContent += "\ufeff";
|
|
281
|
+
}
|
|
282
|
+
const charset = options.extractDataFromPage ? "windows-1252" : "utf-8";
|
|
283
|
+
const title = options.extractDataFromPage ? "" : getPageTitle(pageData);
|
|
284
|
+
pageContent += (options.embeddedImage ? "" : pageData.doctype) + "<html data-sfz><meta charset=" + charset + "><title>" + title + "</title>";
|
|
285
|
+
if (options.insertCanonicalLink) {
|
|
286
|
+
pageContent += "<link rel=canonical href=\"" + options.url + "\">";
|
|
287
|
+
}
|
|
288
|
+
if (options.insertMetaNoIndex) {
|
|
289
|
+
pageContent += "<meta name=robots content=noindex>";
|
|
290
|
+
}
|
|
291
|
+
if (pageData.viewport) {
|
|
292
|
+
pageContent += "<meta name=viewport content=" + JSON.stringify(pageData.viewport) + ">";
|
|
293
|
+
}
|
|
294
|
+
pageContent += "<style>@keyframes display-wait-message{0%{opacity:0}100%{opacity:1}};body{color:transparent};div{color:initial}</style>";
|
|
295
|
+
pageContent += "<body hidden>";
|
|
296
|
+
return pageContent;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function getPageTitle(pageData) {
|
|
300
|
+
return pageData.title.replace(/</g, "<").replace(/>/g, ">") || "";
|
|
301
|
+
}
|
|
302
|
+
|
|
221
303
|
function findExtraDataTags(textContent, pageData, options, lastModDate, indexExtractDataFromPageTags = 0) {
|
|
222
304
|
const matchEndTag = textContent.match(EXTRA_DATA_REGEXPS[indexExtractDataFromPageTags]);
|
|
223
305
|
if (matchEndTag) {
|
|
@@ -244,7 +326,7 @@ async function arrayToBase64(data) {
|
|
|
244
326
|
async function writeData(writable, array) {
|
|
245
327
|
const streamWriter = writable.getWriter();
|
|
246
328
|
await streamWriter.ready;
|
|
247
|
-
writable.size
|
|
329
|
+
writable.size += array.length;
|
|
248
330
|
await streamWriter.write(array);
|
|
249
331
|
streamWriter.releaseLock();
|
|
250
332
|
}
|
|
@@ -300,6 +382,7 @@ async function getContent() {
|
|
|
300
382
|
[8212, 151], [732, 152], [8482, 153], [353, 154], [8250, 155], [339, 156], [382, 158], [376, 159]
|
|
301
383
|
]);
|
|
302
384
|
const xhr = new XMLHttpRequest();
|
|
385
|
+
document.body.querySelectorAll("meta, style").forEach(element => document.head.appendChild(element));
|
|
303
386
|
xhr.responseType = "blob";
|
|
304
387
|
xhr.open("GET", "");
|
|
305
388
|
return new Promise((resolve, reject) => {
|
|
@@ -335,8 +418,10 @@ async function getContent() {
|
|
|
335
418
|
if (zipDataElement) {
|
|
336
419
|
let dataNode = zipDataElement.nextSibling;
|
|
337
420
|
if (dataNode) {
|
|
338
|
-
if (dataNode.nodeType == Node.TEXT_NODE) {
|
|
421
|
+
if (dataNode.nodeType == Node.TEXT_NODE && dataNode.nextSibling) {
|
|
339
422
|
dataNode = dataNode.nextSibling;
|
|
423
|
+
} else {
|
|
424
|
+
dataNode = zipDataElement.previousSibling;
|
|
340
425
|
}
|
|
341
426
|
} else {
|
|
342
427
|
dataNode = zipDataElement.previousSibling;
|
|
@@ -61,11 +61,11 @@ const WINDOW_ID_SEPARATOR = ".";
|
|
|
61
61
|
const TOP_WINDOW = globalThis.window == globalThis.top;
|
|
62
62
|
|
|
63
63
|
const browser = globalThis.browser;
|
|
64
|
-
const addEventListener = (type, listener, options) => globalThis.addEventListener(type, listener, options);
|
|
65
64
|
const top = globalThis.top;
|
|
66
65
|
const MessageChannel = globalThis.MessageChannel;
|
|
67
66
|
const document = globalThis.document;
|
|
68
67
|
const JSON = globalThis.JSON;
|
|
68
|
+
const MutationObserver = globalThis.MutationObserver;
|
|
69
69
|
|
|
70
70
|
let sessions = globalThis.sessions;
|
|
71
71
|
if (!sessions) {
|
|
@@ -87,33 +87,8 @@ if (TOP_WINDOW) {
|
|
|
87
87
|
});
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
event.preventDefault();
|
|
93
|
-
event.stopPropagation();
|
|
94
|
-
const message = JSON.parse(event.data.substring(MESSAGE_PREFIX.length));
|
|
95
|
-
if (message.method == INIT_REQUEST_MESSAGE) {
|
|
96
|
-
if (event.source) {
|
|
97
|
-
sendMessage(event.source, { method: ACK_INIT_REQUEST_MESSAGE, windowId: message.windowId, sessionId: message.sessionId });
|
|
98
|
-
}
|
|
99
|
-
if (!TOP_WINDOW) {
|
|
100
|
-
globalThis.stop();
|
|
101
|
-
if (message.options.loadDeferredImages) {
|
|
102
|
-
lazy.process(message.options);
|
|
103
|
-
}
|
|
104
|
-
await initRequestAsync(message);
|
|
105
|
-
}
|
|
106
|
-
} else if (message.method == ACK_INIT_REQUEST_MESSAGE) {
|
|
107
|
-
clearFrameTimeout("requestTimeouts", message.sessionId, message.windowId);
|
|
108
|
-
createFrameResponseTimeout(message.sessionId, message.windowId);
|
|
109
|
-
} else if (message.method == CLEANUP_REQUEST_MESSAGE) {
|
|
110
|
-
cleanupRequest(message);
|
|
111
|
-
} else if (message.method == INIT_RESPONSE_MESSAGE && sessions.get(message.sessionId)) {
|
|
112
|
-
const port = event.ports[0];
|
|
113
|
-
port.onmessage = event => initResponse(event.data);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}, true);
|
|
90
|
+
init();
|
|
91
|
+
new MutationObserver(init).observe(document, { childList: true });
|
|
117
92
|
|
|
118
93
|
export {
|
|
119
94
|
getAsync,
|
|
@@ -123,6 +98,36 @@ export {
|
|
|
123
98
|
TIMEOUT_INIT_REQUEST_MESSAGE
|
|
124
99
|
};
|
|
125
100
|
|
|
101
|
+
function init() {
|
|
102
|
+
globalThis.addEventListener("message", async event => {
|
|
103
|
+
if (typeof event.data == "string" && event.data.startsWith(MESSAGE_PREFIX)) {
|
|
104
|
+
event.preventDefault();
|
|
105
|
+
event.stopPropagation();
|
|
106
|
+
const message = JSON.parse(event.data.substring(MESSAGE_PREFIX.length));
|
|
107
|
+
if (message.method == INIT_REQUEST_MESSAGE) {
|
|
108
|
+
if (event.source) {
|
|
109
|
+
sendMessage(event.source, { method: ACK_INIT_REQUEST_MESSAGE, windowId: message.windowId, sessionId: message.sessionId });
|
|
110
|
+
}
|
|
111
|
+
if (!TOP_WINDOW) {
|
|
112
|
+
globalThis.stop();
|
|
113
|
+
if (message.options.loadDeferredImages) {
|
|
114
|
+
lazy.process(message.options);
|
|
115
|
+
}
|
|
116
|
+
await initRequestAsync(message);
|
|
117
|
+
}
|
|
118
|
+
} else if (message.method == ACK_INIT_REQUEST_MESSAGE) {
|
|
119
|
+
clearFrameTimeout("requestTimeouts", message.sessionId, message.windowId);
|
|
120
|
+
createFrameResponseTimeout(message.sessionId, message.windowId);
|
|
121
|
+
} else if (message.method == CLEANUP_REQUEST_MESSAGE) {
|
|
122
|
+
cleanupRequest(message);
|
|
123
|
+
} else if (message.method == INIT_RESPONSE_MESSAGE && sessions.get(message.sessionId)) {
|
|
124
|
+
const port = event.ports[0];
|
|
125
|
+
port.onmessage = event => initResponse(event.data);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}, true);
|
|
129
|
+
}
|
|
130
|
+
|
|
126
131
|
function getAsync(options) {
|
|
127
132
|
const sessionId = getNewSessionId();
|
|
128
133
|
options = JSON.parse(JSON.stringify(options));
|
|
@@ -59,8 +59,6 @@
|
|
|
59
59
|
featureSettings: "font-feature-settings"
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
const addEventListener = (type, listener, options) => globalThis.addEventListener(type, listener, options);
|
|
63
|
-
const dispatchEvent = event => { try { globalThis.dispatchEvent(event); } catch (error) { /* ignored */ } };
|
|
64
62
|
const fetch = (url, options) => globalThis.fetch(url, options);
|
|
65
63
|
const CustomEvent = globalThis.CustomEvent;
|
|
66
64
|
const document = globalThis.document;
|
|
@@ -71,13 +69,83 @@
|
|
|
71
69
|
const FileReader = globalThis.FileReader;
|
|
72
70
|
const Blob = globalThis.Blob;
|
|
73
71
|
const JSON = globalThis.JSON;
|
|
72
|
+
const MutationObserver = globalThis.MutationObserver;
|
|
74
73
|
|
|
75
74
|
const observers = new Map();
|
|
76
75
|
const observedElements = new Map();
|
|
77
76
|
|
|
78
77
|
let dispatchScrollEvent;
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
|
|
79
|
+
init();
|
|
80
|
+
new MutationObserver(init).observe(document, { childList: true });
|
|
81
|
+
|
|
82
|
+
function init() {
|
|
83
|
+
document.addEventListener(LOAD_DEFERRED_IMAGES_START_EVENT, () => loadDeferredImagesStart());
|
|
84
|
+
document.addEventListener(LOAD_DEFERRED_IMAGES_KEEP_ZOOM_LEVEL_START_EVENT, () => loadDeferredImagesStart(true));
|
|
85
|
+
document.addEventListener(LOAD_DEFERRED_IMAGES_END_EVENT, () => loadDeferredImagesEnd());
|
|
86
|
+
document.addEventListener(LOAD_DEFERRED_IMAGES_KEEP_ZOOM_LEVEL_END_EVENT, () => loadDeferredImagesEnd(true));
|
|
87
|
+
document.addEventListener(LOAD_DEFERRED_IMAGES_RESET_EVENT, resetScreenSize);
|
|
88
|
+
document.addEventListener(LOAD_DEFERRED_IMAGES_RESET_ZOOM_LEVEL_EVENT, () => {
|
|
89
|
+
const transform = document.documentElement.style.getPropertyValue("-sf-transform");
|
|
90
|
+
const transformPriority = document.documentElement.style.getPropertyPriority("-sf-transform");
|
|
91
|
+
const transformOrigin = document.documentElement.style.getPropertyValue("-sf-transform-origin");
|
|
92
|
+
const transformOriginPriority = document.documentElement.style.getPropertyPriority("-sf-transform-origin");
|
|
93
|
+
const minHeight = document.documentElement.style.getPropertyValue("-sf-min-height");
|
|
94
|
+
const minHeightPriority = document.documentElement.style.getPropertyPriority("-sf-min-height");
|
|
95
|
+
document.documentElement.style.setProperty("transform", transform, transformPriority);
|
|
96
|
+
document.documentElement.style.setProperty("transform-origin", transformOrigin, transformOriginPriority);
|
|
97
|
+
document.documentElement.style.setProperty("min-height", minHeight, minHeightPriority);
|
|
98
|
+
document.documentElement.style.removeProperty("-sf-transform");
|
|
99
|
+
document.documentElement.style.removeProperty("-sf-transform-origin");
|
|
100
|
+
document.documentElement.style.removeProperty("-sf-min-height");
|
|
101
|
+
resetScreenSize();
|
|
102
|
+
});
|
|
103
|
+
document.addEventListener(DISPATCH_SCROLL_START_EVENT, () => { dispatchScrollEvent = true; });
|
|
104
|
+
document.addEventListener(DISPATCH_SCROLL_END_EVENT, () => { dispatchScrollEvent = false; });
|
|
105
|
+
document.addEventListener(BLOCK_COOKIES_START_EVENT, () => {
|
|
106
|
+
try {
|
|
107
|
+
document.__defineGetter__("cookie", () => { throw new Error("document.cookie temporary blocked by SingleFile"); });
|
|
108
|
+
} catch (error) {
|
|
109
|
+
// ignored
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
document.addEventListener(BLOCK_COOKIES_END_EVENT, () => { delete document.cookie; });
|
|
113
|
+
document.addEventListener(BLOCK_STORAGE_START_EVENT, () => {
|
|
114
|
+
if (!globalThis._singleFile_localStorage) {
|
|
115
|
+
globalThis._singleFile_localStorage = globalThis.localStorage;
|
|
116
|
+
globalThis.__defineGetter__("localStorage", () => { throw new Error("localStorage temporary blocked by SingleFile"); });
|
|
117
|
+
}
|
|
118
|
+
if (!globalThis._singleFile_indexedDB) {
|
|
119
|
+
globalThis._singleFile_indexedDB = globalThis.indexedDB;
|
|
120
|
+
globalThis.__defineGetter__("indexedDB", () => { throw new Error("indexedDB temporary blocked by SingleFile"); });
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
document.addEventListener(BLOCK_STORAGE_END_EVENT, () => {
|
|
124
|
+
if (globalThis._singleFile_localStorage) {
|
|
125
|
+
delete globalThis.localStorage;
|
|
126
|
+
globalThis.localStorage = globalThis._singleFile_localStorage;
|
|
127
|
+
delete globalThis._singleFile_localStorage;
|
|
128
|
+
}
|
|
129
|
+
if (!globalThis._singleFile_indexedDB) {
|
|
130
|
+
delete globalThis.indexedDB;
|
|
131
|
+
globalThis.indexedDB = globalThis._singleFile_indexedDB;
|
|
132
|
+
delete globalThis._singleFile_indexedDB;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
document.addEventListener(FETCH_REQUEST_EVENT, async event => {
|
|
136
|
+
document.dispatchEvent(new CustomEvent(FETCH_ACK_EVENT));
|
|
137
|
+
const { url, options } = JSON.parse(event.detail);
|
|
138
|
+
let detail;
|
|
139
|
+
try {
|
|
140
|
+
const response = await fetch(url, options);
|
|
141
|
+
detail = { url, response: await response.arrayBuffer(), headers: [...response.headers], status: response.status };
|
|
142
|
+
} catch (error) {
|
|
143
|
+
detail = { url, error: error && error.toString() };
|
|
144
|
+
}
|
|
145
|
+
document.dispatchEvent(new CustomEvent(FETCH_RESPONSE_EVENT, { detail }));
|
|
146
|
+
});
|
|
147
|
+
document.addEventListener(GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, getAdoptedStylesheetsListener);
|
|
148
|
+
}
|
|
81
149
|
|
|
82
150
|
function loadDeferredImagesStart(keepZoomLevel) {
|
|
83
151
|
const scrollingElement = document.scrollingElement || document.documentElement;
|
|
@@ -121,11 +189,11 @@
|
|
|
121
189
|
const result = new Image(...arguments);
|
|
122
190
|
result.__defineSetter__("src", value => {
|
|
123
191
|
image.src = value;
|
|
124
|
-
dispatchEvent(new CustomEvent(LOAD_IMAGE_EVENT, { detail: image.src }));
|
|
192
|
+
document.dispatchEvent(new CustomEvent(LOAD_IMAGE_EVENT, { detail: image.src }));
|
|
125
193
|
});
|
|
126
194
|
result.__defineGetter__("src", () => image.src);
|
|
127
195
|
result.__defineSetter__("srcset", value => {
|
|
128
|
-
dispatchEvent(new CustomEvent(LOAD_IMAGE_EVENT));
|
|
196
|
+
document.dispatchEvent(new CustomEvent(LOAD_IMAGE_EVENT));
|
|
129
197
|
image.srcset = value;
|
|
130
198
|
});
|
|
131
199
|
result.__defineGetter__("srcset", () => image.srcset);
|
|
@@ -137,7 +205,7 @@
|
|
|
137
205
|
result.__defineGetter__("decode", () => () => image.decode());
|
|
138
206
|
}
|
|
139
207
|
image.onload = image.onloadend = image.onerror = event => {
|
|
140
|
-
dispatchEvent(new CustomEvent(IMAGE_LOADED_EVENT, { detail: image.src }));
|
|
208
|
+
document.dispatchEvent(new CustomEvent(IMAGE_LOADED_EVENT, { detail: image.src }));
|
|
141
209
|
result.dispatchEvent(new Event(event.type, event));
|
|
142
210
|
};
|
|
143
211
|
return result;
|
|
@@ -191,32 +259,13 @@
|
|
|
191
259
|
const time = 0;
|
|
192
260
|
return { target, intersectionRatio, boundingClientRect, intersectionRect: boundingClientRect, isIntersecting, rootBounds, time };
|
|
193
261
|
});
|
|
194
|
-
observer.callback(params, intersectionObserver);
|
|
262
|
+
observer.callback.call(intersectionObserver, params, intersectionObserver);
|
|
195
263
|
}
|
|
196
264
|
});
|
|
197
265
|
}
|
|
198
266
|
}
|
|
199
267
|
}
|
|
200
268
|
|
|
201
|
-
addEventListener(LOAD_DEFERRED_IMAGES_END_EVENT, () => loadDeferredImagesEnd());
|
|
202
|
-
addEventListener(LOAD_DEFERRED_IMAGES_KEEP_ZOOM_LEVEL_END_EVENT, () => loadDeferredImagesEnd(true));
|
|
203
|
-
addEventListener(LOAD_DEFERRED_IMAGES_RESET_EVENT, resetScreenSize);
|
|
204
|
-
addEventListener(LOAD_DEFERRED_IMAGES_RESET_ZOOM_LEVEL_EVENT, () => {
|
|
205
|
-
const transform = document.documentElement.style.getPropertyValue("-sf-transform");
|
|
206
|
-
const transformPriority = document.documentElement.style.getPropertyPriority("-sf-transform");
|
|
207
|
-
const transformOrigin = document.documentElement.style.getPropertyValue("-sf-transform-origin");
|
|
208
|
-
const transformOriginPriority = document.documentElement.style.getPropertyPriority("-sf-transform-origin");
|
|
209
|
-
const minHeight = document.documentElement.style.getPropertyValue("-sf-min-height");
|
|
210
|
-
const minHeightPriority = document.documentElement.style.getPropertyPriority("-sf-min-height");
|
|
211
|
-
document.documentElement.style.setProperty("transform", transform, transformPriority);
|
|
212
|
-
document.documentElement.style.setProperty("transform-origin", transformOrigin, transformOriginPriority);
|
|
213
|
-
document.documentElement.style.setProperty("min-height", minHeight, minHeightPriority);
|
|
214
|
-
document.documentElement.style.removeProperty("-sf-transform");
|
|
215
|
-
document.documentElement.style.removeProperty("-sf-transform-origin");
|
|
216
|
-
document.documentElement.style.removeProperty("-sf-min-height");
|
|
217
|
-
resetScreenSize();
|
|
218
|
-
});
|
|
219
|
-
|
|
220
269
|
function loadDeferredImagesEnd(keepZoomLevel) {
|
|
221
270
|
document.querySelectorAll("[" + LAZY_LOAD_ATTRIBUTE + "]").forEach(element => {
|
|
222
271
|
element.loading = "lazy";
|
|
@@ -256,82 +305,25 @@
|
|
|
256
305
|
delete screen.width;
|
|
257
306
|
}
|
|
258
307
|
|
|
259
|
-
addEventListener(DISPATCH_SCROLL_START_EVENT, () => {
|
|
260
|
-
dispatchScrollEvent = true;
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
addEventListener(DISPATCH_SCROLL_END_EVENT, () => {
|
|
264
|
-
dispatchScrollEvent = false;
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
addEventListener(BLOCK_COOKIES_START_EVENT, () => {
|
|
268
|
-
try {
|
|
269
|
-
document.__defineGetter__("cookie", () => { throw new Error("document.cookie temporary blocked by SingleFile"); });
|
|
270
|
-
} catch (error) {
|
|
271
|
-
// ignored
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
addEventListener(BLOCK_COOKIES_END_EVENT, () => {
|
|
276
|
-
delete document.cookie;
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
addEventListener(BLOCK_STORAGE_START_EVENT, () => {
|
|
280
|
-
if (!globalThis._singleFile_localStorage) {
|
|
281
|
-
globalThis._singleFile_localStorage = globalThis.localStorage;
|
|
282
|
-
globalThis.__defineGetter__("localStorage", () => { throw new Error("localStorage temporary blocked by SingleFile"); });
|
|
283
|
-
}
|
|
284
|
-
if (!globalThis._singleFile_indexedDB) {
|
|
285
|
-
globalThis._singleFile_indexedDB = globalThis.indexedDB;
|
|
286
|
-
globalThis.__defineGetter__("indexedDB", () => { throw new Error("indexedDB temporary blocked by SingleFile"); });
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
addEventListener(BLOCK_STORAGE_END_EVENT, () => {
|
|
291
|
-
if (globalThis._singleFile_localStorage) {
|
|
292
|
-
delete globalThis.localStorage;
|
|
293
|
-
globalThis.localStorage = globalThis._singleFile_localStorage;
|
|
294
|
-
delete globalThis._singleFile_localStorage;
|
|
295
|
-
}
|
|
296
|
-
if (!globalThis._singleFile_indexedDB) {
|
|
297
|
-
delete globalThis.indexedDB;
|
|
298
|
-
globalThis.indexedDB = globalThis._singleFile_indexedDB;
|
|
299
|
-
delete globalThis._singleFile_indexedDB;
|
|
300
|
-
}
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
addEventListener(FETCH_REQUEST_EVENT, async event => {
|
|
304
|
-
dispatchEvent(new CustomEvent(FETCH_ACK_EVENT));
|
|
305
|
-
const { url, options } = JSON.parse(event.detail);
|
|
306
|
-
let detail;
|
|
307
|
-
try {
|
|
308
|
-
const response = await fetch(url, options);
|
|
309
|
-
detail = { url, response: await response.arrayBuffer(), headers: [...response.headers], status: response.status };
|
|
310
|
-
} catch (error) {
|
|
311
|
-
detail = { url, error: error && error.toString() };
|
|
312
|
-
}
|
|
313
|
-
dispatchEvent(new CustomEvent(FETCH_RESPONSE_EVENT, { detail }));
|
|
314
|
-
});
|
|
315
308
|
|
|
316
|
-
addEventListener(GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, getAdoptedStylesheetsListener);
|
|
317
309
|
|
|
318
310
|
if (globalThis.FontFace) {
|
|
319
311
|
const FontFace = globalThis.FontFace;
|
|
320
312
|
globalThis.FontFace = function () {
|
|
321
|
-
getDetailObject(...arguments).then(detail => dispatchEvent(new CustomEvent(NEW_FONT_FACE_EVENT, { detail })));
|
|
313
|
+
getDetailObject(...arguments).then(detail => document.dispatchEvent(new CustomEvent(NEW_FONT_FACE_EVENT, { detail })));
|
|
322
314
|
return new FontFace(...arguments);
|
|
323
315
|
};
|
|
324
316
|
globalThis.FontFace.prototype = FontFace.prototype;
|
|
325
317
|
globalThis.FontFace.toString = function () { return "function FontFace() { [native code] }"; };
|
|
326
318
|
const deleteFont = document.fonts.delete;
|
|
327
319
|
document.fonts.delete = function (fontFace) {
|
|
328
|
-
getDetailObject(fontFace.family).then(detail => dispatchEvent(new CustomEvent(DELETE_FONT_EVENT, { detail })));
|
|
320
|
+
getDetailObject(fontFace.family).then(detail => document.dispatchEvent(new CustomEvent(DELETE_FONT_EVENT, { detail })));
|
|
329
321
|
return deleteFont.call(document.fonts, fontFace);
|
|
330
322
|
};
|
|
331
323
|
document.fonts.delete.toString = function () { return "function delete() { [native code] }"; };
|
|
332
324
|
const clearFonts = document.fonts.clear;
|
|
333
325
|
document.fonts.clear = function () {
|
|
334
|
-
dispatchEvent(new CustomEvent(CLEAR_FONTS_EVENT));
|
|
326
|
+
document.dispatchEvent(new CustomEvent(CLEAR_FONTS_EVENT));
|
|
335
327
|
return clearFonts.call(document.fonts);
|
|
336
328
|
};
|
|
337
329
|
document.fonts.clear.toString = function () { return "function clear() { [native code] }"; };
|
|
@@ -418,9 +410,9 @@
|
|
|
418
410
|
|
|
419
411
|
function dispatchResizeEvent() {
|
|
420
412
|
try {
|
|
421
|
-
dispatchEvent(new UIEvent("resize"));
|
|
413
|
+
globalThis.dispatchEvent(new UIEvent("resize"));
|
|
422
414
|
if (dispatchScrollEvent) {
|
|
423
|
-
dispatchEvent(new UIEvent("scroll"));
|
|
415
|
+
globalThis.dispatchEvent(new UIEvent("scroll"));
|
|
424
416
|
}
|
|
425
417
|
} catch (error) {
|
|
426
418
|
// ignored
|
|
@@ -42,12 +42,11 @@ const DELETE_FONT_EVENT = "single-file-delete-font";
|
|
|
42
42
|
const CLEAR_FONTS_EVENT = "single-file-clear-fonts";
|
|
43
43
|
const FONT_FACE_PROPERTY_NAME = "_singleFile_fontFaces";
|
|
44
44
|
|
|
45
|
-
const addEventListener = (type, listener, options) => globalThis.addEventListener(type, listener, options);
|
|
46
|
-
const dispatchEvent = event => { try { globalThis.dispatchEvent(event); } catch (error) { /* ignored */ } };
|
|
47
45
|
const CustomEvent = globalThis.CustomEvent;
|
|
48
46
|
const document = globalThis.document;
|
|
49
47
|
const Document = globalThis.Document;
|
|
50
48
|
const JSON = globalThis.JSON;
|
|
49
|
+
const MutationObserver = globalThis.MutationObserver;
|
|
51
50
|
|
|
52
51
|
let fontFaces;
|
|
53
52
|
if (window[FONT_FACE_PROPERTY_NAME]) {
|
|
@@ -56,20 +55,25 @@ if (window[FONT_FACE_PROPERTY_NAME]) {
|
|
|
56
55
|
fontFaces = window[FONT_FACE_PROPERTY_NAME] = new Map();
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
58
|
+
init();
|
|
59
|
+
new MutationObserver(init).observe(document, { childList: true });
|
|
60
|
+
|
|
61
|
+
function init() {
|
|
62
|
+
if (document instanceof Document) {
|
|
63
|
+
document.addEventListener(NEW_FONT_FACE_EVENT, event => {
|
|
64
|
+
const detail = event.detail;
|
|
65
|
+
const key = Object.assign({}, detail);
|
|
66
|
+
delete key.src;
|
|
67
|
+
fontFaces.set(JSON.stringify(key), detail);
|
|
68
|
+
});
|
|
69
|
+
document.addEventListener(DELETE_FONT_EVENT, event => {
|
|
70
|
+
const detail = event.detail;
|
|
71
|
+
const key = Object.assign({}, detail);
|
|
72
|
+
delete key.src;
|
|
73
|
+
fontFaces.delete(JSON.stringify(key));
|
|
74
|
+
});
|
|
75
|
+
document.addEventListener(CLEAR_FONTS_EVENT, () => fontFaces = new Map());
|
|
76
|
+
}
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
export {
|
|
@@ -87,42 +91,42 @@ function getFontsData() {
|
|
|
87
91
|
|
|
88
92
|
function loadDeferredImagesStart(options) {
|
|
89
93
|
if (options.loadDeferredImagesBlockCookies) {
|
|
90
|
-
dispatchEvent(new CustomEvent(BLOCK_COOKIES_START_EVENT));
|
|
94
|
+
document.dispatchEvent(new CustomEvent(BLOCK_COOKIES_START_EVENT));
|
|
91
95
|
}
|
|
92
96
|
if (options.loadDeferredImagesBlockStorage) {
|
|
93
|
-
dispatchEvent(new CustomEvent(BLOCK_STORAGE_START_EVENT));
|
|
97
|
+
document.dispatchEvent(new CustomEvent(BLOCK_STORAGE_START_EVENT));
|
|
94
98
|
}
|
|
95
99
|
if (options.loadDeferredImagesDispatchScrollEvent) {
|
|
96
|
-
dispatchEvent(new CustomEvent(DISPATCH_SCROLL_START_EVENT));
|
|
100
|
+
document.dispatchEvent(new CustomEvent(DISPATCH_SCROLL_START_EVENT));
|
|
97
101
|
}
|
|
98
102
|
if (options.loadDeferredImagesKeepZoomLevel) {
|
|
99
|
-
dispatchEvent(new CustomEvent(LOAD_DEFERRED_IMAGES_KEEP_ZOOM_LEVEL_START_EVENT));
|
|
103
|
+
document.dispatchEvent(new CustomEvent(LOAD_DEFERRED_IMAGES_KEEP_ZOOM_LEVEL_START_EVENT));
|
|
100
104
|
} else {
|
|
101
|
-
dispatchEvent(new CustomEvent(LOAD_DEFERRED_IMAGES_START_EVENT));
|
|
105
|
+
document.dispatchEvent(new CustomEvent(LOAD_DEFERRED_IMAGES_START_EVENT));
|
|
102
106
|
}
|
|
103
107
|
}
|
|
104
108
|
|
|
105
109
|
function loadDeferredImagesEnd(options) {
|
|
106
110
|
if (options.loadDeferredImagesBlockCookies) {
|
|
107
|
-
dispatchEvent(new CustomEvent(BLOCK_COOKIES_END_EVENT));
|
|
111
|
+
document.dispatchEvent(new CustomEvent(BLOCK_COOKIES_END_EVENT));
|
|
108
112
|
}
|
|
109
113
|
if (options.loadDeferredImagesBlockStorage) {
|
|
110
|
-
dispatchEvent(new CustomEvent(BLOCK_STORAGE_END_EVENT));
|
|
114
|
+
document.dispatchEvent(new CustomEvent(BLOCK_STORAGE_END_EVENT));
|
|
111
115
|
}
|
|
112
116
|
if (options.loadDeferredImagesDispatchScrollEvent) {
|
|
113
|
-
dispatchEvent(new CustomEvent(DISPATCH_SCROLL_END_EVENT));
|
|
117
|
+
document.dispatchEvent(new CustomEvent(DISPATCH_SCROLL_END_EVENT));
|
|
114
118
|
}
|
|
115
119
|
if (options.loadDeferredImagesKeepZoomLevel) {
|
|
116
|
-
dispatchEvent(new CustomEvent(LOAD_DEFERRED_IMAGES_KEEP_ZOOM_LEVEL_END_EVENT));
|
|
120
|
+
document.dispatchEvent(new CustomEvent(LOAD_DEFERRED_IMAGES_KEEP_ZOOM_LEVEL_END_EVENT));
|
|
117
121
|
} else {
|
|
118
|
-
dispatchEvent(new CustomEvent(LOAD_DEFERRED_IMAGES_END_EVENT));
|
|
122
|
+
document.dispatchEvent(new CustomEvent(LOAD_DEFERRED_IMAGES_END_EVENT));
|
|
119
123
|
}
|
|
120
124
|
}
|
|
121
125
|
|
|
122
126
|
function loadDeferredImagesResetZoomLevel(options) {
|
|
123
127
|
if (options.loadDeferredImagesKeepZoomLevel) {
|
|
124
|
-
dispatchEvent(new CustomEvent(LOAD_DEFERRED_IMAGES_RESET_ZOOM_LEVEL_EVENT));
|
|
128
|
+
document.dispatchEvent(new CustomEvent(LOAD_DEFERRED_IMAGES_RESET_ZOOM_LEVEL_EVENT));
|
|
125
129
|
} else {
|
|
126
|
-
dispatchEvent(new CustomEvent(LOAD_DEFERRED_IMAGES_RESET_EVENT));
|
|
130
|
+
document.dispatchEvent(new CustomEvent(LOAD_DEFERRED_IMAGES_RESET_EVENT));
|
|
127
131
|
}
|
|
128
132
|
}
|
|
@@ -39,8 +39,6 @@ const ATTRIBUTES_MUTATION_TYPE = "attributes";
|
|
|
39
39
|
const browser = globalThis.browser;
|
|
40
40
|
const document = globalThis.document;
|
|
41
41
|
const MutationObserver = globalThis.MutationObserver;
|
|
42
|
-
const addEventListener = (type, listener, options) => globalThis.addEventListener(type, listener, options);
|
|
43
|
-
const removeEventListener = (type, listener, options) => globalThis.removeEventListener(type, listener, options);
|
|
44
42
|
const timeouts = new Map();
|
|
45
43
|
|
|
46
44
|
let idleTimeoutCalls;
|
|
@@ -115,8 +113,8 @@ function triggerLazyLoading(options) {
|
|
|
115
113
|
await setIdleTimeout(options.loadDeferredImagesMaxIdleTime * 2);
|
|
116
114
|
await deferForceLazyLoadEnd(observer, options, cleanupAndResolve);
|
|
117
115
|
observer.observe(document, { subtree: true, childList: true, attributes: true });
|
|
118
|
-
addEventListener(hooksFrames.LOAD_IMAGE_EVENT, onImageLoadEvent);
|
|
119
|
-
addEventListener(hooksFrames.IMAGE_LOADED_EVENT, onImageLoadedEvent);
|
|
116
|
+
document.addEventListener(hooksFrames.LOAD_IMAGE_EVENT, onImageLoadEvent);
|
|
117
|
+
document.addEventListener(hooksFrames.IMAGE_LOADED_EVENT, onImageLoadedEvent);
|
|
120
118
|
hooksFrames.loadDeferredImagesStart(options);
|
|
121
119
|
|
|
122
120
|
async function setIdleTimeout(delay) {
|
|
@@ -159,8 +157,8 @@ function triggerLazyLoading(options) {
|
|
|
159
157
|
|
|
160
158
|
function cleanupAndResolve(value) {
|
|
161
159
|
observer.disconnect();
|
|
162
|
-
removeEventListener(hooksFrames.LOAD_IMAGE_EVENT, onImageLoadEvent);
|
|
163
|
-
removeEventListener(hooksFrames.IMAGE_LOADED_EVENT, onImageLoadedEvent);
|
|
160
|
+
document.removeEventListener(hooksFrames.LOAD_IMAGE_EVENT, onImageLoadEvent);
|
|
161
|
+
document.removeEventListener(hooksFrames.IMAGE_LOADED_EVENT, onImageLoadedEvent);
|
|
164
162
|
resolve(value);
|
|
165
163
|
}
|
|
166
164
|
});
|
package/single-file-infobar.js
CHANGED
|
@@ -28,19 +28,24 @@ import { appendInfobar, refreshInfobarInfo, extractInfobarData } from "./core/in
|
|
|
28
28
|
(globalThis => {
|
|
29
29
|
|
|
30
30
|
const browser = globalThis.browser;
|
|
31
|
+
const MutationObserver = globalThis.MutationObserver;
|
|
32
|
+
init();
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
if (
|
|
34
|
-
document.
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
function init() {
|
|
35
|
+
if (globalThis.window == globalThis.top) {
|
|
36
|
+
if (document.readyState == "loading") {
|
|
37
|
+
document.addEventListener("DOMContentLoaded", displayIcon, false);
|
|
38
|
+
} else {
|
|
39
|
+
displayIcon();
|
|
40
|
+
}
|
|
41
|
+
document.addEventListener("single-file-display-infobar", displayIcon, false);
|
|
42
|
+
new MutationObserver(init).observe(document, { childList: true });
|
|
43
|
+
}
|
|
44
|
+
if (globalThis.singlefile) {
|
|
45
|
+
globalThis.singlefile.infobar = {
|
|
46
|
+
displayIcon
|
|
47
|
+
};
|
|
37
48
|
}
|
|
38
|
-
document.addEventListener("single-file-display-infobar", displayIcon, false);
|
|
39
|
-
}
|
|
40
|
-
if (globalThis.singlefile) {
|
|
41
|
-
globalThis.singlefile.infobar = {
|
|
42
|
-
displayIcon
|
|
43
|
-
};
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
async function displayIcon() {
|
package/single-file.js
CHANGED
|
@@ -110,6 +110,7 @@ async function getPageData(options = {}, initOptions, doc = globalThis.document,
|
|
|
110
110
|
url: options.url,
|
|
111
111
|
createRootDirectory: options.createRootDirectory,
|
|
112
112
|
selfExtractingArchive: options.selfExtractingArchive,
|
|
113
|
+
insertEmbeddedImage: options.insertEmbeddedImage,
|
|
113
114
|
extractDataFromPage: options.extractDataFromPage,
|
|
114
115
|
preventAppendedData: options.preventAppendedData,
|
|
115
116
|
insertCanonicalLink: options.insertCanonicalLink,
|