single-file-core 1.2.4 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core/helper.js CHANGED
@@ -453,11 +453,6 @@ function postProcessDoc(doc, markedElements, invalidElements) {
453
453
  doc.querySelectorAll("[" + DISABLED_NOSCRIPT_ATTRIBUTE_NAME + "]").forEach(element => {
454
454
  element.textContent = element.getAttribute(DISABLED_NOSCRIPT_ATTRIBUTE_NAME);
455
455
  element.removeAttribute(DISABLED_NOSCRIPT_ATTRIBUTE_NAME);
456
- if (doc.body.firstChild) {
457
- doc.body.insertBefore(element, doc.body.firstChild);
458
- } else {
459
- doc.body.appendChild(element);
460
- }
461
456
  });
462
457
  doc.querySelectorAll("meta[disabled-http-equiv]").forEach(element => {
463
458
  element.setAttribute("http-equiv", element.getAttribute("disabled-http-equiv"));
@@ -1973,6 +1973,7 @@ async function evalTemplate(template = "", options, util, content, dontReplaceSl
1973
1973
  template = await evalTemplateVariable(template, "bookmark-pathname", () => bookmarkFolder, dontReplaceSlash === undefined ? true : dontReplaceSlash, options.filenameReplacementCharacter);
1974
1974
  template = await evalTemplateVariable(template, "bookmark-pathname-flat", () => bookmarkFolder, false, options.filenameReplacementCharacter);
1975
1975
  template = await evalTemplateVariable(template, "profile-name", () => options.profileName, dontReplaceSlash, options.filenameReplacementCharacter);
1976
+ template = await evalTemplateVariable(template, "filename-extension", () => getFilenameExtension(options), dontReplaceSlash, options.filenameReplacementCharacter);
1976
1977
  return template.trim();
1977
1978
 
1978
1979
  function decode(value) {
@@ -2102,3 +2103,19 @@ function truncateText(content, maxSize) {
2102
2103
  reader.addEventListener("error", reject, false);
2103
2104
  });
2104
2105
  }
2106
+
2107
+ function getFilenameExtension(options) {
2108
+ if (options.compressContent) {
2109
+ if (options.selfExtractingArchive) {
2110
+ if (options.extractDataFromPage) {
2111
+ return "u.zip.html";
2112
+ } else {
2113
+ return "zip.html";
2114
+ }
2115
+ } else {
2116
+ return "zip";
2117
+ }
2118
+ } else {
2119
+ return "html";
2120
+ }
2121
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "single-file-core",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "SingleFile Core",
5
5
  "author": "Gildas Lormeau",
6
6
  "license": "AGPL-3.0-or-later",
@@ -51,6 +51,10 @@ async function display(document, docContent, { disableFramePointerEvents } = {})
51
51
  });
52
52
  }
53
53
  document.replaceChild(document.importNode(doc.documentElement, true), document.documentElement);
54
+ document.querySelectorAll("[" + DISABLED_NOSCRIPT_ATTRIBUTE_NAME + "]").forEach(element => {
55
+ element.textContent = element.getAttribute(DISABLED_NOSCRIPT_ATTRIBUTE_NAME);
56
+ element.removeAttribute(DISABLED_NOSCRIPT_ATTRIBUTE_NAME);
57
+ });
54
58
  document.documentElement.setAttribute("data-sfz", "");
55
59
  document.querySelectorAll("link[rel*=icon]").forEach(element => element.parentElement.replaceChild(element, element));
56
60
  document.open = document.write = document.close = () => { };
@@ -21,7 +21,7 @@
21
21
  * Source.
22
22
  */
23
23
 
24
- /* global globalThis, FileReader, TextDecoder */
24
+ /* global globalThis, FileReader, TextDecoder, Node */
25
25
 
26
26
  import {
27
27
  configure,
@@ -48,7 +48,7 @@ export {
48
48
  process
49
49
  };
50
50
 
51
- async function process(pageData, options) {
51
+ async function process(pageData, options, lastModDate = new Date()) {
52
52
  let script;
53
53
  if (options.zipScript) {
54
54
  script = options.zipScript;
@@ -58,6 +58,7 @@ async function process(pageData, options) {
58
58
  }
59
59
  const zipDataWriter = new Uint8ArrayWriter();
60
60
  zipDataWriter.init();
61
+ let extraDataOffset, extraData;
61
62
  if (options.selfExtractingArchive) {
62
63
  let pageContent = "";
63
64
  if (options.includeBOM && !options.extractDataFromPage) {
@@ -101,14 +102,29 @@ async function process(pageData, options) {
101
102
  textBody = textBody.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n +/g, "\n").replace(/\n\n\n+/g, "\n\n").trim();
102
103
  pageContent += "\n<main hidden>\n" + textBody + "\n</main>\n";
103
104
  }
104
- if (options.extractDataFromPageTags) {
105
- pageContent += options.extractDataFromPageTags[0];
106
- } else {
107
- pageContent += "<xmp>";
105
+ script = "<script>" +
106
+ script +
107
+ "document.currentScript.remove();" +
108
+ "globalThis.onload = () => {" +
109
+ "globalThis.bootstrap=(()=>{let bootstrapStarted;return async content=>{if (bootstrapStarted) return bootstrapStarted;bootstrapStarted = (" +
110
+ extract.toString().replace(/\n|\t/g, "") + ")(content,{prompt}).then(({docContent}) => " +
111
+ display.toString().replace(/\n|\t/g, "") + "(document,docContent));return bootstrapStarted;}})();(" +
112
+ getContent.toString().replace(/\n|\t/g, "") + ")().then(globalThis.bootstrap).catch(()=>{});" +
113
+ "};" +
114
+ "</script>";
115
+ pageContent += script;
116
+ let extraData = "";
117
+ if (options.extractDataFromPage && options.extraDataSize) {
118
+ const extraTags = "<sfz-extra-data></sfz-extra-data>";
119
+ extraData += extraTags + new Array(options.extraDataSize - extraTags.length).fill(" ").join("");
108
120
  }
121
+ pageContent += extraData;
122
+ const startTag = options.extractDataFromPageTags ? options.extractDataFromPageTags[0] : "<!--";
123
+ pageContent += startTag;
124
+ extraDataOffset = startTag.length + extraData.length;
109
125
  await writeData(zipDataWriter.writable, (new TextEncoder()).encode(pageContent));
110
126
  }
111
- const zipWriter = new ZipWriter(zipDataWriter, { bufferedWrite: true, keepOrder: false });
127
+ const zipWriter = new ZipWriter(zipDataWriter, { bufferedWrite: true, keepOrder: false, lastModDate });
112
128
  let startOffset = zipDataWriter.offset;
113
129
  pageData.url = options.url;
114
130
  pageData.archiveTime = (new Date()).toISOString();
@@ -120,21 +136,21 @@ async function process(pageData, options) {
120
136
  if (options.extractDataFromPage) {
121
137
  if (!options.extractDataFromPageTags) {
122
138
  const textContent = new TextDecoder().decode(data);
123
- const matchEndTagXMP = textContent.match(/<\/\s*xmp>/i);
124
- if (matchEndTagXMP) {
125
- const matchEndTagComment = textContent.match(/-->/i);
126
- if (matchEndTagComment) {
127
- const matchTextAreaTagComment = textContent.match(/<\/\s*textarea>/i);
128
- if (matchTextAreaTagComment) {
139
+ const matchEndTagComment = textContent.match(/-->/i);
140
+ if (matchEndTagComment) {
141
+ const matchEndTagXMP = textContent.match(/<\/\s*xmp>/i);
142
+ if (matchEndTagXMP) {
143
+ const matchEndTagPlainText = textContent.match(/<\/\s*plaintext>/i);
144
+ if (matchEndTagPlainText) {
129
145
  options.extractDataFromPage = false;
130
- return process(pageData, options);
146
+ return process(pageData, options, lastModDate);
131
147
  } else {
132
- options.extractDataFromPageTags = ["<textarea>", "</textarea>"];
133
- return process(pageData, options);
148
+ options.extractDataFromPageTags = ["<plaintext>", "</plaintext>"];
149
+ return process(pageData, options, lastModDate);
134
150
  }
135
151
  } else {
136
- options.extractDataFromPageTags = ["<!--", "-->"];
137
- return process(pageData, options);
152
+ options.extractDataFromPageTags = ["<xmp>", "</xmp>"];
153
+ return process(pageData, options, lastModDate);
138
154
  }
139
155
  }
140
156
  }
@@ -152,24 +168,44 @@ async function process(pageData, options) {
152
168
  if (options.extractDataFromPageTags) {
153
169
  pageContent += options.extractDataFromPageTags[1];
154
170
  } else {
155
- pageContent += "</xmp>";
171
+ pageContent += "-->";
156
172
  }
157
- if (insertionsCRLF.length || substitutionsLF.length) {
158
- const extraData =
173
+ const endTags = "</body></html>";
174
+ if (options.extractDataFromPage) {
175
+ extraData = "<sfz-extra-data>" +
159
176
  await arrayToBase64(insertionsCRLF) + "," +
160
177
  await arrayToBase64(substitutionsLF) + "," +
161
- await arrayToBase64([startOffset]);
162
- pageContent += "<sfz-extra-data>" + extraData + "</sfz-extra-data>";
178
+ await arrayToBase64([startOffset]) +
179
+ "</sfz-extra-data>";
180
+ if (extraData.length > 65535 - endTags.length) {
181
+ if (!options.extraDataSize) {
182
+ options.extraDataSize = Math.floor(extraData.length * 1.001);
183
+ return process(pageData, options, lastModDate);
184
+ }
185
+ } else {
186
+ if (options.extraDataSize) {
187
+ options.extraDataSize = undefined;
188
+ return process(pageData, options, lastModDate);
189
+ } else {
190
+ pageContent += extraData;
191
+ }
192
+ }
163
193
  }
164
- script += "document.currentScript.remove();globalThis.bootstrap=(()=>{let bootstrapStarted;return async content=>{if (bootstrapStarted) return bootstrapStarted;bootstrapStarted = (" +
165
- extract.toString().replace(/\n|\t/g, "") + ")(content,{prompt}).then(({docContent}) => " +
166
- display.toString().replace(/\n|\t/g, "") + "(document,docContent));return bootstrapStarted;}})();(" +
167
- getContent.toString().replace(/\n|\t/g, "") + ")().then(globalThis.bootstrap).catch(()=>{});";
168
- pageContent += "<script>" + script + "</script></body></html>";
194
+ pageContent += endTags;
169
195
  await writeData(zipDataWriter.writable, (new TextEncoder()).encode(pageContent));
170
196
  }
171
197
  await zipDataWriter.writable.close();
172
- return new Blob([zipDataWriter.getData()], { type: "application/octet-stream" });
198
+ const pageContent = await zipDataWriter.getData();
199
+ if (options.extractDataFromPage && options.extraDataSize !== undefined) {
200
+ if (options.extraDataSize >= extraData.length) {
201
+ pageContent.set(Array.from(extraData).map(character => character.charCodeAt(0)), startOffset - extraDataOffset);
202
+ } else {
203
+ options.extraData = extraData;
204
+ options.extraDataSize = Math.floor(extraData.length * 1.001);
205
+ return process(pageData, options, lastModDate);
206
+ }
207
+ }
208
+ return new Blob([pageContent], { type: "application/octet-stream" });
173
209
  }
174
210
 
175
211
  async function arrayToBase64(data) {
@@ -281,7 +317,14 @@ async function getContent() {
281
317
  async function extractPageData() {
282
318
  const zipDataElement = document.querySelector("sfz-extra-data");
283
319
  if (zipDataElement) {
284
- const dataNode = zipDataElement.previousSibling;
320
+ let dataNode = zipDataElement.nextSibling;
321
+ if (dataNode) {
322
+ if (dataNode.nodeType == Node.TEXT_NODE) {
323
+ dataNode = dataNode.nextSibling;
324
+ }
325
+ } else {
326
+ dataNode = zipDataElement.previousSibling;
327
+ }
285
328
  const zipData = [];
286
329
  let { textContent } = dataNode;
287
330
  for (let index = 0; index < textContent.length; index++) {