single-file-core 1.2.20 → 1.2.22

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.
@@ -16966,6 +16966,7 @@ async function evalTemplate(template = "", options, util, content, doc, dontRepl
16966
16966
  "substring": (value, start, end) => value.substring(start, end),
16967
16967
  "lowercase": value => value.toLowerCase(),
16968
16968
  "uppercase": value => value.toUpperCase(),
16969
+ "capitalize": value => value.charAt(0).toUpperCase() + value.slice(1),
16969
16970
  "replace": (value, searchValue, replaceValue) => searchValue && replaceValue ? value.replaceAll(searchValue, replaceValue) : value,
16970
16971
  "trim": value => value.trim(),
16971
16972
  "trim-left": value => value.trimLeft(),
@@ -16973,8 +16974,8 @@ async function evalTemplate(template = "", options, util, content, doc, dontRepl
16973
16974
  "pad-left": (value, length, padString) => length > 0 ? value.padStart(length, padString) : value,
16974
16975
  "pad-right": (value, length, padString) => length > 0 ? value.padEnd(length, padString) : value,
16975
16976
  "repeat": (value, count) => count > 0 ? value.repeat(count) : "",
16976
- "index-of": (value, searchValue) => value.indexOf(searchValue),
16977
- "last-index-of": (value, searchValue) => value.lastIndexOf(searchValue),
16977
+ "index-of": (value, searchValue, fromIndex) => value.indexOf(searchValue, fromIndex),
16978
+ "last-index-of": (value, searchValue, fromIndex) => value.lastIndexOf(searchValue, fromIndex),
16978
16979
  "length": value => value.length,
16979
16980
  "url-search-name": (index = 0) => params[index] && params[index][0],
16980
16981
  "url-search-value": (index = 0) => params[index] && params[index][1],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "single-file-core",
3
- "version": "1.2.20",
3
+ "version": "1.2.22",
4
4
  "description": "SingleFile Core",
5
5
  "author": "Gildas Lormeau",
6
6
  "license": "AGPL-3.0-or-later",
@@ -38,8 +38,21 @@ import {
38
38
  } from "./compression-display.js";
39
39
 
40
40
  const { Blob, fetch, TextEncoder, DOMParser } = globalThis;
41
- const NO_COMPRESSION_EXTENSIONS = [ ".jpg", ".jpeg", ".png", ".pdf", ".woff2", ".mp4", ".mp3", ".ogg", ".webp", ".webm", ".avi", ".mpeg", ".ts", ".ogv" ];
41
+
42
+ const NO_COMPRESSION_EXTENSIONS = [".jpg", ".jpeg", ".png", ".pdf", ".woff2", ".mp4", ".mp3", ".ogg", ".webp", ".webm", ".avi", ".mpeg", ".ts", ".ogv"];
42
43
  const SCRIPT_PATH = "/lib/single-file-zip.min.js";
44
+ const EXTRA_DATA_TAGS = [
45
+ ["<noscript>", "</noscript>"],
46
+ ["<script type=sfz-data>", "</script>"],
47
+ ["<xmp>", "</xmp>"],
48
+ ["<plaintext>", "</plaintext>"]
49
+ ];
50
+ const EXTRA_DATA_REGEXPS = [
51
+ [/<\/noscript>/i],
52
+ [/<\/script>/i],
53
+ [/<\/xmp>/i],
54
+ [/<\/plaintext>/i]
55
+ ];
43
56
 
44
57
  const browser = globalThis.browser;
45
58
 
@@ -76,6 +89,7 @@ async function process(pageData, options, lastModDate = new Date()) {
76
89
  if (pageData.viewport) {
77
90
  pageContent += "<meta name=\"viewport\" content=" + JSON.stringify(pageData.viewport) + ">";
78
91
  }
92
+ pageContent += "<style>@keyframes display-wait-message{0%{opacity:0}100%{opacity:1}}</style>";
79
93
  pageContent += "<body hidden>";
80
94
  pageContent += "<div id='sfz-wait-message'>Please wait...</div>";
81
95
  pageContent += "<div id='sfz-error-message'><strong>Error</strong>: Cannot open the page from the filesystem.";
@@ -104,12 +118,12 @@ async function process(pageData, options, lastModDate = new Date()) {
104
118
  script = "<script>" +
105
119
  script +
106
120
  "document.currentScript.remove();" +
107
- "globalThis.onload = () => {" +
108
- "globalThis.bootstrap=(()=>{let bootstrapStarted;return async content=>{if (bootstrapStarted) return bootstrapStarted;bootstrapStarted = (" +
121
+ "globalThis.addEventListener('load', () => {" +
122
+ "globalThis.bootstrap=(()=>{let bootstrapStarted;return async content=>{if (bootstrapStarted) return bootstrapStarted; bootstrapStarted = (" +
109
123
  extract.toString().replace(/\n|\t/g, "") + ")(content,{prompt}).then(({docContent}) => " +
110
124
  display.toString().replace(/\n|\t/g, "") + "(document,docContent));return bootstrapStarted;}})();(" +
111
- getContent.toString().replace(/\n|\t/g, "") + ")().then(globalThis.bootstrap).catch(()=>{});" +
112
- "};" +
125
+ getContent.toString().replace(/\n|\t/g, "") + ")().then(globalThis.bootstrap).then(() => document.dispatchEvent(new CustomEvent(\"single-file-display-infobar\"))).catch(()=>{});" +
126
+ "});" +
113
127
  "</script>";
114
128
  pageContent += script;
115
129
  let extraData = "";
@@ -137,20 +151,7 @@ async function process(pageData, options, lastModDate = new Date()) {
137
151
  const textContent = new TextDecoder().decode(data);
138
152
  const matchEndTagComment = textContent.match(/-->/i);
139
153
  if (matchEndTagComment) {
140
- const matchEndTagXMP = textContent.match(/<\/\s*xmp>/i);
141
- if (matchEndTagXMP) {
142
- const matchEndTagPlainText = textContent.match(/<\/\s*plaintext>/i);
143
- if (matchEndTagPlainText) {
144
- options.extractDataFromPage = false;
145
- return process(pageData, options, lastModDate);
146
- } else {
147
- options.extractDataFromPageTags = ["<plaintext>", "</plaintext>"];
148
- return process(pageData, options, lastModDate);
149
- }
150
- } else {
151
- options.extractDataFromPageTags = ["<xmp>", "</xmp>"];
152
- return process(pageData, options, lastModDate);
153
- }
154
+ return findExtraDataTags(data, pageData, options, lastModDate);
154
155
  }
155
156
  }
156
157
  for (let index = 0; index < data.length; index++) {
@@ -207,6 +208,17 @@ async function process(pageData, options, lastModDate = new Date()) {
207
208
  return new Blob([pageContent], { type: "application/octet-stream" });
208
209
  }
209
210
 
211
+ function findExtraDataTags(data, pageData, options, lastModDate, indexExtractDataFromPageTags = 0) {
212
+ const textContent = new TextDecoder().decode(data);
213
+ const matchEndTag = textContent.match(EXTRA_DATA_REGEXPS[indexExtractDataFromPageTags]);
214
+ if (matchEndTag) {
215
+ return findExtraDataTags(data, pageData, options, lastModDate, indexExtractDataFromPageTags + 1);
216
+ } else {
217
+ options.extractDataFromPageTags = EXTRA_DATA_TAGS[indexExtractDataFromPageTags];
218
+ return process(pageData, options, lastModDate);
219
+ }
220
+ }
221
+
210
222
  async function arrayToBase64(data) {
211
223
  const fileReader = new FileReader();
212
224
  return await new Promise(resolve => {
@@ -267,50 +279,41 @@ async function addFile(zipWriter, prefixName, data) {
267
279
  }
268
280
 
269
281
  async function getContent() {
270
- const { Blob, XMLHttpRequest, fetch, document, setTimeout, clearTimeout, stop } = globalThis;
282
+ const { Blob, XMLHttpRequest, fetch, document, stop } = globalThis;
271
283
  const characterMap = new Map([
272
284
  [65533, 0], [8364, 128], [8218, 130], [402, 131], [8222, 132], [8230, 133], [8224, 134], [8225, 135], [710, 136], [8240, 137],
273
285
  [352, 138], [8249, 139], [338, 140], [381, 142], [8216, 145], [8217, 146], [8220, 147], [8221, 148], [8226, 149], [8211, 150],
274
286
  [8212, 151], [732, 152], [8482, 153], [353, 154], [8250, 155], [339, 156], [382, 158], [376, 159]
275
287
  ]);
276
288
  const xhr = new XMLHttpRequest();
277
- let displayTimeout;
278
- Array.from(document.documentElement.childNodes).forEach(node => {
279
- if (node != document.body && node != document.head) {
280
- node.remove();
281
- }
282
- });
283
289
  xhr.responseType = "blob";
284
290
  xhr.open("GET", "");
285
291
  return new Promise((resolve, reject) => {
286
292
  xhr.onerror = () => {
287
293
  extractPageData().then(resolve).catch(() => {
288
- displayTimeout = displayMessage("sfz-error-message");
294
+ displayMessage("sfz-error-message", 2);
289
295
  reject();
290
296
  });
291
297
  };
292
298
  xhr.send();
293
299
  xhr.onload = () => {
294
- displayTimeout = displayMessage("sfz-wait-message");
295
300
  stop();
296
- if (displayTimeout) {
297
- clearTimeout(displayTimeout);
298
- }
301
+ displayMessage("sfz-wait-message", 2);
299
302
  resolve(xhr.response);
300
303
  };
301
304
  });
302
305
 
303
- function displayMessage(elementId) {
304
- return setTimeout(() => {
305
- if (document.getElementById(elementId)) {
306
- Array.from(document.body.childNodes).forEach(node => {
307
- if (node.id != elementId) {
308
- node.remove();
309
- }
310
- });
311
- document.body.hidden = false;
312
- }
313
- }, 1500);
306
+ function displayMessage(elementId, delay = 0) {
307
+ const element = document.getElementById(elementId);
308
+ if (element) {
309
+ Array.from(document.body.childNodes).forEach(node => {
310
+ if (node.id != elementId) {
311
+ node.remove();
312
+ }
313
+ });
314
+ document.body.hidden = false;
315
+ element.style = "opacity: 0; animation: 0s linear " + delay + "s display-wait-message 1 normal forwards";
316
+ }
314
317
  }
315
318
 
316
319
  async function extractPageData() {
@@ -326,6 +329,7 @@ async function getContent() {
326
329
  }
327
330
  const zipData = [];
328
331
  let { textContent } = dataNode;
332
+ displayMessage("sfz-wait-message", 2);
329
333
  for (let index = 0; index < textContent.length; index++) {
330
334
  const charCode = textContent.charCodeAt(index);
331
335
  zipData.push(charCode > 255 ? characterMap.get(charCode) : charCode);