single-file-core 1.2.23 → 1.2.24
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/package.json +1 -1
- package/processors/compression/compression.js +92 -77
- package/single-file.js +5 -0
package/package.json
CHANGED
|
@@ -72,70 +72,7 @@ async function process(pageData, options, lastModDate = new Date()) {
|
|
|
72
72
|
zipDataWriter.init();
|
|
73
73
|
let extraDataOffset, extraData;
|
|
74
74
|
if (options.selfExtractingArchive) {
|
|
75
|
-
|
|
76
|
-
if (options.includeBOM && !options.extractDataFromPage) {
|
|
77
|
-
pageContent += "\ufeff";
|
|
78
|
-
}
|
|
79
|
-
const charset = options.extractDataFromPage ? "windows-1252" : "utf-8";
|
|
80
|
-
const pageDataTitle = pageData.title.replace(/</g, "<").replace(/>/g, ">") || "";
|
|
81
|
-
const title = options.extractDataFromPage ? "" : pageDataTitle;
|
|
82
|
-
pageContent += pageData.doctype + "<html data-sfz><meta charset=" + charset + "><title>" + title + "</title>";
|
|
83
|
-
if (options.insertCanonicalLink) {
|
|
84
|
-
pageContent += "<link rel=canonical href=\"" + options.url + "\">";
|
|
85
|
-
}
|
|
86
|
-
if (options.insertMetaNoIndex) {
|
|
87
|
-
pageContent += "<meta name=robots content=noindex>";
|
|
88
|
-
}
|
|
89
|
-
if (pageData.viewport) {
|
|
90
|
-
pageContent += "<meta name=\"viewport\" content=" + JSON.stringify(pageData.viewport) + ">";
|
|
91
|
-
}
|
|
92
|
-
pageContent += "<style>@keyframes display-wait-message{0%{opacity:0}100%{opacity:1}}</style>";
|
|
93
|
-
pageContent += "<body hidden>";
|
|
94
|
-
pageContent += "<div id='sfz-wait-message'>Please wait...</div>";
|
|
95
|
-
pageContent += "<div id='sfz-error-message'><strong>Error</strong>: Cannot open the page from the filesystem.";
|
|
96
|
-
pageContent += "<ul style='line-height:20px;'>";
|
|
97
|
-
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>";
|
|
98
|
-
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>";
|
|
99
|
-
pageContent += "<li><strong>Safari</strong>: Select \"Security > Disable Local File Restrictions\" in the \"Develop > Developer settings\" menu.</li></ul></div>";
|
|
100
|
-
if (options.insertTextBody) {
|
|
101
|
-
const doc = (new DOMParser()).parseFromString(pageData.content, "text/html");
|
|
102
|
-
doc.body.querySelectorAll("style, script, noscript").forEach(element => element.remove());
|
|
103
|
-
let textBody = "";
|
|
104
|
-
if (options.extractDataFromPage) {
|
|
105
|
-
textBody += pageDataTitle + "\n\n";
|
|
106
|
-
}
|
|
107
|
-
textBody += doc.body.innerText;
|
|
108
|
-
doc.body.querySelectorAll("single-file-note").forEach(node => {
|
|
109
|
-
const template = node.querySelector("template");
|
|
110
|
-
if (template) {
|
|
111
|
-
const docTemplate = (new DOMParser()).parseFromString(template.innerHTML, "text/html");
|
|
112
|
-
textBody += "\n" + docTemplate.body.querySelector("textarea").value;
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
textBody = textBody.replace(/</g, "<").replace(/>/g, ">").replace(/\n +/g, "\n").replace(/\n\n\n+/g, "\n\n").trim();
|
|
116
|
-
pageContent += "\n<main hidden>\n" + textBody + "\n</main>\n";
|
|
117
|
-
}
|
|
118
|
-
script = "<script>" +
|
|
119
|
-
script +
|
|
120
|
-
"document.currentScript.remove();" +
|
|
121
|
-
"globalThis.addEventListener('load', () => {" +
|
|
122
|
-
"globalThis.bootstrap=(()=>{let bootstrapStarted;return async content=>{if (bootstrapStarted) return bootstrapStarted; bootstrapStarted = (" +
|
|
123
|
-
extract.toString().replace(/\n|\t/g, "") + ")(content,{prompt}).then(({docContent}) => " +
|
|
124
|
-
display.toString().replace(/\n|\t/g, "") + "(document,docContent));return bootstrapStarted;}})();(" +
|
|
125
|
-
getContent.toString().replace(/\n|\t/g, "") + ")().then(globalThis.bootstrap).then(() => document.dispatchEvent(new CustomEvent(\"single-file-display-infobar\"))).catch(()=>{});" +
|
|
126
|
-
"});" +
|
|
127
|
-
"</script>";
|
|
128
|
-
pageContent += script;
|
|
129
|
-
let extraData = "";
|
|
130
|
-
if (options.extractDataFromPage && options.extraDataSize) {
|
|
131
|
-
const extraTags = "<sfz-extra-data></sfz-extra-data>";
|
|
132
|
-
extraData += extraTags + new Array(options.extraDataSize - extraTags.length).fill(" ").join("");
|
|
133
|
-
}
|
|
134
|
-
pageContent += extraData;
|
|
135
|
-
const startTag = options.extractDataFromPageTags ? options.extractDataFromPageTags[0] : "<!--";
|
|
136
|
-
pageContent += startTag;
|
|
137
|
-
extraDataOffset = startTag.length + extraData.length;
|
|
138
|
-
await writeData(zipDataWriter.writable, (new TextEncoder()).encode(pageContent));
|
|
75
|
+
extraDataOffset = await prependHTMLData(pageData, zipDataWriter, script, options);
|
|
139
76
|
}
|
|
140
77
|
const zipWriter = new ZipWriter(zipDataWriter, { bufferedWrite: true, keepOrder: false, lastModDate });
|
|
141
78
|
let startOffset = zipDataWriter.offset;
|
|
@@ -165,19 +102,22 @@ async function process(pageData, options, lastModDate = new Date()) {
|
|
|
165
102
|
}
|
|
166
103
|
}
|
|
167
104
|
let pageContent = "";
|
|
168
|
-
if (options.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
105
|
+
if (!options.preventAppendedData) {
|
|
106
|
+
if (options.extractDataFromPageTags) {
|
|
107
|
+
pageContent += options.extractDataFromPageTags[1];
|
|
108
|
+
} else {
|
|
109
|
+
pageContent += "-->";
|
|
110
|
+
}
|
|
172
111
|
}
|
|
173
|
-
const endTags = "</body></html>";
|
|
112
|
+
const endTags = options.preventAppendedData ? "" : "</body></html>";
|
|
174
113
|
if (options.extractDataFromPage) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
114
|
+
const payload = await Promise.all([
|
|
115
|
+
arrayToBase64(insertionsCRLF),
|
|
116
|
+
arrayToBase64(substitutionsLF),
|
|
117
|
+
arrayToBase64([startOffset])
|
|
118
|
+
]);
|
|
119
|
+
extraData = "<sfz-extra-data>" + payload.join(",") + "</sfz-extra-data>";
|
|
120
|
+
if (options.preventAppendedData || extraData.length > 65535 - endTags.length) {
|
|
181
121
|
if (!options.extraDataSize) {
|
|
182
122
|
options.extraDataSize = Math.floor(extraData.length * 1.001);
|
|
183
123
|
return process(pageData, options, lastModDate);
|
|
@@ -192,7 +132,9 @@ async function process(pageData, options, lastModDate = new Date()) {
|
|
|
192
132
|
}
|
|
193
133
|
}
|
|
194
134
|
pageContent += endTags;
|
|
195
|
-
|
|
135
|
+
if (pageContent) {
|
|
136
|
+
await writeData(zipDataWriter.writable, (new TextEncoder()).encode(pageContent));
|
|
137
|
+
}
|
|
196
138
|
}
|
|
197
139
|
await zipDataWriter.writable.close();
|
|
198
140
|
const pageContent = await zipDataWriter.getData();
|
|
@@ -208,11 +150,84 @@ async function process(pageData, options, lastModDate = new Date()) {
|
|
|
208
150
|
return new Blob([pageContent], { type: "application/octet-stream" });
|
|
209
151
|
}
|
|
210
152
|
|
|
153
|
+
async function prependHTMLData(pageData, zipDataWriter, script, options) {
|
|
154
|
+
let pageContent = "";
|
|
155
|
+
if (options.includeBOM && !options.extractDataFromPage) {
|
|
156
|
+
pageContent += "\ufeff";
|
|
157
|
+
}
|
|
158
|
+
const charset = options.extractDataFromPage ? "windows-1252" : "utf-8";
|
|
159
|
+
const pageDataTitle = pageData.title.replace(/</g, "<").replace(/>/g, ">") || "";
|
|
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.";
|
|
175
|
+
pageContent += "<ul style='line-height:20px;'>";
|
|
176
|
+
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
|
+
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>";
|
|
178
|
+
pageContent += "<li><strong>Safari</strong>: Select \"Security > Disable Local File Restrictions\" in the \"Develop > Developer settings\" menu.</li></ul></div>";
|
|
179
|
+
if (options.insertTextBody) {
|
|
180
|
+
const doc = (new DOMParser()).parseFromString(pageData.content, "text/html");
|
|
181
|
+
doc.body.querySelectorAll("style, script, noscript").forEach(element => element.remove());
|
|
182
|
+
let textBody = "";
|
|
183
|
+
if (options.extractDataFromPage) {
|
|
184
|
+
textBody += pageDataTitle + "\n\n";
|
|
185
|
+
}
|
|
186
|
+
textBody += doc.body.innerText;
|
|
187
|
+
doc.body.querySelectorAll("single-file-note").forEach(node => {
|
|
188
|
+
const template = node.querySelector("template");
|
|
189
|
+
if (template) {
|
|
190
|
+
const docTemplate = (new DOMParser()).parseFromString(template.innerHTML, "text/html");
|
|
191
|
+
textBody += "\n" + docTemplate.body.querySelector("textarea").value;
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
textBody = textBody.replace(/</g, "<").replace(/>/g, ">").replace(/\n +/g, "\n").replace(/\n\n\n+/g, "\n\n").trim();
|
|
195
|
+
pageContent += "\n<main hidden>\n" + textBody + "\n</main>\n";
|
|
196
|
+
}
|
|
197
|
+
script = "<script>" +
|
|
198
|
+
script +
|
|
199
|
+
"document.currentScript.remove();" +
|
|
200
|
+
"globalThis.addEventListener('load', () => {" +
|
|
201
|
+
"globalThis.bootstrap=(()=>{let bootstrapStarted;return async content=>{if (bootstrapStarted) return bootstrapStarted; bootstrapStarted = (" +
|
|
202
|
+
extract.toString().replace(/\n|\t/g, "") + ")(content,{prompt}).then(({docContent}) => " +
|
|
203
|
+
display.toString().replace(/\n|\t/g, "") + "(document,docContent));return bootstrapStarted;}})();(" +
|
|
204
|
+
getContent.toString().replace(/\n|\t/g, "") + ")().then(globalThis.bootstrap).then(() => document.dispatchEvent(new CustomEvent(\"single-file-display-infobar\"))).catch(()=>{});" +
|
|
205
|
+
"});" +
|
|
206
|
+
"</script>";
|
|
207
|
+
pageContent += script;
|
|
208
|
+
let extraData = "";
|
|
209
|
+
if (options.extractDataFromPage && options.extraDataSize) {
|
|
210
|
+
const extraTags = "<sfz-extra-data></sfz-extra-data>";
|
|
211
|
+
extraData += extraTags + new Array(options.extraDataSize - extraTags.length).fill(" ").join("");
|
|
212
|
+
}
|
|
213
|
+
pageContent += extraData;
|
|
214
|
+
const startTag = options.extractDataFromPageTags ? options.extractDataFromPageTags[0] : "<!--";
|
|
215
|
+
pageContent += startTag;
|
|
216
|
+
const extraDataOffset = startTag.length + extraData.length;
|
|
217
|
+
await writeData(zipDataWriter.writable, (new TextEncoder()).encode(pageContent));
|
|
218
|
+
return extraDataOffset;
|
|
219
|
+
}
|
|
220
|
+
|
|
211
221
|
function findExtraDataTags(data, pageData, options, lastModDate, indexExtractDataFromPageTags = 0) {
|
|
212
222
|
const textContent = new TextDecoder().decode(data);
|
|
213
223
|
const matchEndTag = textContent.match(EXTRA_DATA_REGEXPS[indexExtractDataFromPageTags]);
|
|
214
224
|
if (matchEndTag) {
|
|
215
|
-
|
|
225
|
+
if (indexExtractDataFromPageTags < EXTRA_DATA_TAGS.length - 1) {
|
|
226
|
+
return findExtraDataTags(data, pageData, options, lastModDate, indexExtractDataFromPageTags + 1);
|
|
227
|
+
} else {
|
|
228
|
+
options.extractDataFromPage = false;
|
|
229
|
+
return process(pageData, options, lastModDate);
|
|
230
|
+
}
|
|
216
231
|
} else {
|
|
217
232
|
options.extractDataFromPageTags = EXTRA_DATA_TAGS[indexExtractDataFromPageTags];
|
|
218
233
|
return process(pageData, options, lastModDate);
|
package/single-file.js
CHANGED
|
@@ -88,11 +88,16 @@ async function getPageData(options = {}, initOptions, doc = globalThis.document,
|
|
|
88
88
|
options.doc = doc;
|
|
89
89
|
options.win = win;
|
|
90
90
|
options.insertCanonicalLink = true;
|
|
91
|
+
|
|
92
|
+
const externalOnProgress = options.onprogress;
|
|
91
93
|
options.onprogress = event => {
|
|
92
94
|
if (event.type === event.RESOURCES_INITIALIZED && doc && win && options.loadDeferredImages) {
|
|
93
95
|
processors.lazy.resetZoomLevel(options);
|
|
94
96
|
}
|
|
97
|
+
|
|
98
|
+
if (externalOnProgress) externalOnProgress(event);
|
|
95
99
|
};
|
|
100
|
+
|
|
96
101
|
const processor = new SingleFile(options);
|
|
97
102
|
await processor.run();
|
|
98
103
|
if (framesSessionId) {
|