textbrowser 0.50.0 → 0.52.0

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.
Files changed (106) hide show
  1. package/.ncurc.cjs +3 -0
  2. package/CHANGES.md +13 -0
  3. package/dist/WorkInfo-es.js +655 -165
  4. package/dist/activateCallback-es.js +81 -10
  5. package/dist/dist/WorkInfo-es.d.ts +331 -0
  6. package/dist/dist/WorkInfo-es.d.ts.map +1 -0
  7. package/dist/dist/activateCallback-es.d.ts +17 -0
  8. package/dist/dist/activateCallback-es.d.ts.map +1 -0
  9. package/dist/dist/index-es.d.ts +619 -0
  10. package/dist/dist/index-es.d.ts.map +1 -0
  11. package/dist/dist/sw-helper.d.ts +3 -0
  12. package/dist/dist/sw-helper.d.ts.map +1 -0
  13. package/dist/eslint.config.d.ts +126 -0
  14. package/dist/eslint.config.d.ts.map +1 -0
  15. package/dist/index-es.js +3449 -1848
  16. package/dist/index-es.min.js +4 -4
  17. package/dist/resources/activateCallback.d.ts +23 -0
  18. package/dist/resources/activateCallback.d.ts.map +1 -0
  19. package/dist/resources/index.d.ts +128 -0
  20. package/dist/resources/index.d.ts.map +1 -0
  21. package/dist/resources/resultsDisplay.d.ts +110 -0
  22. package/dist/resources/resultsDisplay.d.ts.map +1 -0
  23. package/dist/resources/templates/index.d.ts +59 -0
  24. package/dist/resources/templates/index.d.ts.map +1 -0
  25. package/dist/resources/templates/languageSelect.d.ts +18 -0
  26. package/dist/resources/templates/languageSelect.d.ts.map +1 -0
  27. package/dist/resources/templates/resultsDisplayClient.d.ts +26 -0
  28. package/dist/resources/templates/resultsDisplayClient.d.ts.map +1 -0
  29. package/dist/resources/templates/resultsDisplayServerOrClient.d.ts +131 -0
  30. package/dist/resources/templates/resultsDisplayServerOrClient.d.ts.map +1 -0
  31. package/dist/resources/templates/utils/dom.d.ts +15 -0
  32. package/dist/resources/templates/utils/dom.d.ts.map +1 -0
  33. package/dist/resources/templates/utils/html.d.ts +3 -0
  34. package/dist/resources/templates/utils/html.d.ts.map +1 -0
  35. package/dist/resources/templates/workDisplay.d.ts +183 -0
  36. package/dist/resources/templates/workDisplay.d.ts.map +1 -0
  37. package/dist/resources/templates/workSelect.d.ts +18 -0
  38. package/dist/resources/templates/workSelect.d.ts.map +1 -0
  39. package/dist/resources/user-sample.d.ts +2 -0
  40. package/dist/resources/user-sample.d.ts.map +1 -0
  41. package/dist/resources/user.d.ts +2 -0
  42. package/dist/resources/user.d.ts.map +1 -0
  43. package/dist/resources/utils/IntlURLSearchParams.d.ts +56 -0
  44. package/dist/resources/utils/IntlURLSearchParams.d.ts.map +1 -0
  45. package/dist/resources/utils/Languages.d.ts +81 -0
  46. package/dist/resources/utils/Languages.d.ts.map +1 -0
  47. package/dist/resources/utils/Metadata.d.ts +133 -0
  48. package/dist/resources/utils/Metadata.d.ts.map +1 -0
  49. package/dist/resources/utils/Params.d.ts +30 -0
  50. package/dist/resources/utils/Params.d.ts.map +1 -0
  51. package/dist/resources/utils/Plugin.d.ts +278 -0
  52. package/dist/resources/utils/Plugin.d.ts.map +1 -0
  53. package/dist/resources/utils/ServiceWorker.d.ts +26 -0
  54. package/dist/resources/utils/ServiceWorker.d.ts.map +1 -0
  55. package/dist/resources/utils/WorkInfo.d.ts +104 -0
  56. package/dist/resources/utils/WorkInfo.d.ts.map +1 -0
  57. package/dist/resources/utils/dialogs.d.ts +155 -0
  58. package/dist/resources/utils/dialogs.d.ts.map +1 -0
  59. package/dist/resources/utils/getLocaleFallbackResults.d.ts +19 -0
  60. package/dist/resources/utils/getLocaleFallbackResults.d.ts.map +1 -0
  61. package/dist/resources/utils/sanitize.d.ts +6 -0
  62. package/dist/resources/utils/sanitize.d.ts.map +1 -0
  63. package/dist/resources/vendor/json-refs-min.d.ts +3 -0
  64. package/dist/resources/vendor/json-refs-min.d.ts.map +1 -0
  65. package/dist/resources/workDisplay.d.ts +81 -0
  66. package/dist/resources/workDisplay.d.ts.map +1 -0
  67. package/dist/resources/workSelect.d.ts +17 -0
  68. package/dist/resources/workSelect.d.ts.map +1 -0
  69. package/dist/rollup.config.d.ts +19 -0
  70. package/dist/rollup.config.d.ts.map +1 -0
  71. package/dist/server/main.d.ts +47 -0
  72. package/dist/server/main.d.ts.map +1 -0
  73. package/dist/sw-helper.d.ts +3 -0
  74. package/dist/sw-helper.d.ts.map +1 -0
  75. package/dist/sw-helper.js +52 -12
  76. package/dist/sw-sample.d.ts +2 -0
  77. package/dist/sw-sample.d.ts.map +1 -0
  78. package/general-schemas/files.jsonschema +6 -0
  79. package/package.json +32 -19
  80. package/resources/activateCallback.js +81 -10
  81. package/resources/index.js +169 -58
  82. package/resources/resultsDisplay.js +520 -153
  83. package/resources/templates/index.js +39 -17
  84. package/resources/templates/languageSelect.js +14 -1
  85. package/resources/templates/resultsDisplayClient.js +22 -3
  86. package/resources/templates/resultsDisplayServerOrClient.js +188 -49
  87. package/resources/templates/utils/dom.js +13 -2
  88. package/resources/templates/workDisplay.js +299 -76
  89. package/resources/templates/workSelect.js +16 -3
  90. package/resources/user-sample.js +1 -0
  91. package/resources/utils/IntlURLSearchParams.js +46 -4
  92. package/resources/utils/Languages.js +71 -4
  93. package/resources/utils/Metadata.js +222 -23
  94. package/resources/utils/Params.js +70 -23
  95. package/resources/utils/Plugin.js +175 -1
  96. package/resources/utils/ServiceWorker.js +49 -21
  97. package/resources/utils/WorkInfo.js +256 -44
  98. package/resources/utils/dialogs.js +105 -7
  99. package/resources/utils/getLocaleFallbackResults.js +15 -3
  100. package/resources/utils/sanitize.js +4 -0
  101. package/resources/workDisplay.js +151 -25
  102. package/resources/workSelect.js +37 -17
  103. package/server/main.js +118 -20
  104. package/sw-sample.js +2 -1
  105. package/tsconfig.json +30 -0
  106. package/resources/user.js +0 -20
@@ -1,6 +1,9 @@
1
1
  import {getJSON} from 'simple-get-json';
2
2
  import {i18n} from 'intl-dom';
3
3
  import loadStylesheets from 'load-stylesheets';
4
+
5
+ // Todo
6
+ // @ts-expect-error -- No types
4
7
  import {serialize as formSerialize} from 'form-serialization';
5
8
 
6
9
  import getLocaleFallbackResults from './utils/getLocaleFallbackResults.js';
@@ -21,7 +24,16 @@ import workDisplay from './workDisplay.js';
21
24
  import {resultsDisplayClient} from './resultsDisplay.js';
22
25
 
23
26
  /**
24
- *
27
+ * @typedef {{
28
+ * 'localization-strings': {
29
+ * [locale: string]: {
30
+ * [key: string]: string
31
+ * }
32
+ * }
33
+ * }} SiteData
34
+ */
35
+ /**
36
+ * @this {TextBrowser}
25
37
  * @returns {Promise<void>}
26
38
  */
27
39
  async function prepareForServiceWorker () {
@@ -48,32 +60,34 @@ async function prepareForServiceWorker () {
48
60
  } catch (err) {
49
61
  console.log('err', err);
50
62
  if (err && typeof err === 'object') {
51
- const {errorType} = err;
52
- if (errorType === 'versionChange') {
63
+ if ('errorType' in err && err.errorType === 'versionChange') {
53
64
  Templates.permissions.versionChange();
54
65
  return;
55
66
  }
56
67
  }
57
68
  Templates.permissions.errorRegistering(
58
- escapeHTML(err && err.message)
69
+ escapeHTML(/** @type {Error} */ (err)?.message)
59
70
  );
60
71
  }
61
72
  }
62
73
 
63
74
  /**
64
- * @typedef {PlainObject} Langs
75
+ * @typedef {object} Langs
65
76
  * @property {string} code
66
77
  * @property {string} direction
67
- * @property {PlainObject} locale
78
+ * @property {object} locale
68
79
  */
69
80
 
70
81
  /**
71
- *
72
- * @param {Langs} langs
73
- * @param {Logger} l
82
+ * @this {TextBrowser}
83
+ * @param {import('../server/main.js').LanguageInfo[]} _langs
84
+ * @param {import('intl-dom').I18NCallback} siteI18n
74
85
  * @returns {Promise<void>}
75
86
  */
76
- async function requestPermissions (langs, l) {
87
+ async function requestPermissions (
88
+ _langs,
89
+ siteI18n
90
+ ) {
77
91
  return await new Promise((resolve) => {
78
92
  // Todo: We could run the dialog code below for every page if
79
93
  // `Notification.permission === 'default'` (i.e., not choice
@@ -97,7 +111,7 @@ async function requestPermissions (langs, l) {
97
111
  *
98
112
  * @returns {void}
99
113
  */
100
- function rememberRefusal () {
114
+ const rememberRefusal = () => {
101
115
  // Todo: We could go forward with worker, caching files, and
102
116
  // indexedDB regardless of permissions, but this way
103
117
  // we can continue to gauge performance differences for now
@@ -105,13 +119,14 @@ async function requestPermissions (langs, l) {
105
119
  this.namespace + '-refused',
106
120
  'true'
107
121
  );
108
- }
122
+ };
109
123
  try {
110
124
  if (!requestPermissionsDialog.returnValue) {
111
125
  rememberRefusal();
112
126
  return;
113
127
  }
114
- } catch (err) {
128
+ } catch (error) {
129
+ const err = /** @type {Error} */ (error);
115
130
  console.log('err', err);
116
131
  Templates.permissions.errorRegistering(
117
132
  escapeHTML(err && err.message)
@@ -144,15 +159,46 @@ async function requestPermissions (langs, l) {
144
159
  break;
145
160
  }
146
161
  };
147
- const [, requestPermissionsDialog, browserNotGrantingPersistenceAlert] = // , errorRegisteringNotice
148
- Templates.permissions.main({
149
- l, ok, refuse, close, closeBrowserNotGranting
150
- });
162
+ const permissionsInfo = // , errorRegisteringNotice
163
+ Templates.permissions.main({
164
+ siteI18n,
165
+ ok, refuse, close, closeBrowserNotGranting
166
+ });
167
+
168
+ const requestPermissionsDialog = /** @type {HTMLDialogElement} */ (permissionsInfo[1]);
169
+ const browserNotGrantingPersistenceAlert = /** @type {HTMLDialogElement} */ (
170
+ permissionsInfo[2]
171
+ );
151
172
  requestPermissionsDialog.showModal();
152
173
  });
153
174
  }
154
175
 
176
+ /**
177
+ * @typedef {import('./utils/ServiceWorker.js').ServiceWorkerConfig} ServiceWorkerConfig
178
+ */
179
+
180
+ /**
181
+ * @implements {ServiceWorkerConfig}
182
+ */
155
183
  class TextBrowser {
184
+ /**
185
+ * @param {ServiceWorkerConfig & {
186
+ * site?: string,
187
+ * stylesheets?: string[],
188
+ * allowPlugins?: boolean,
189
+ * dynamicBasePath?: string,
190
+ * trustFormatHTML?: boolean,
191
+ * requestPersistentStorage?: boolean,
192
+ * localizeParamNames?: boolean,
193
+ * hideFormattingSection?: boolean,
194
+ * preferencesPlugin?: import('./templates/workDisplay.js').PreferencesPlugin,
195
+ * interlinearSeparator?: string,
196
+ * showEmptyInterlinear?: boolean,
197
+ * showTitleOnSingleInterlinear?: boolean,
198
+ * noDynamic?: boolean,
199
+ * skipIndexedDB?: boolean
200
+ * }} options
201
+ */
156
202
  constructor (options) {
157
203
  this.site = options.site || 'site.json';
158
204
  const stylesheets = options.stylesheets || ['@builtin'];
@@ -166,6 +212,24 @@ class TextBrowser {
166
212
  }
167
213
  this.stylesheets = stylesheets;
168
214
 
215
+ // Satisfy TS
216
+
217
+ /** @type {SiteData} */
218
+ this.siteData = {
219
+ 'localization-strings': {}
220
+ };
221
+ /** @type {import('../server/main.js').LanguagesData} */
222
+ this.langData = {
223
+ languages: [],
224
+ 'localization-strings': {}
225
+ };
226
+ /** @type {string[]} */
227
+ this.lang = [];
228
+ this.userJSON = '';
229
+ this.languages = '';
230
+ this.serviceWorkerPath = '';
231
+ this.files = '';
232
+ this.namespace = '';
169
233
  setServiceWorkerDefaults(this, options);
170
234
 
171
235
  this.allowPlugins = options.allowPlugins;
@@ -191,24 +255,45 @@ class TextBrowser {
191
255
 
192
256
  // We use getJSON instead of JsonRefs as we do not need to resolve the locales here
193
257
  try {
194
- const [langData, siteData] = await getJSON([this.languages, this.site]);
195
- this.langData = langData;
196
- this.siteData = siteData;
258
+ const data =
259
+ /**
260
+ * @type {[
261
+ * import('../server/main.js').LanguagesData,
262
+ * SiteData
263
+ * ]}
264
+ */ (
265
+ await getJSON([this.languages, this.site])
266
+ );
267
+ this.langData = data[0];
268
+ this.siteData = data[1];
197
269
 
198
270
  const p = this.paramChange();
199
271
 
200
272
  // INIT/ADD EVENTS
201
273
  // With `hashchange` more generic than `popstate`, we use it
202
274
  // and just check `history.state`
203
- window.addEventListener('hashchange', () => this.paramChange());
275
+ globalThis.addEventListener('hashchange', () => this.paramChange());
204
276
 
205
277
  return p;
206
- } catch (err) {
278
+ } catch (error) {
279
+ const err = /** @type {Error} */ (error);
207
280
  console.log('err', err);
208
281
  dialogs.alert(err);
209
282
  }
210
283
  }
211
284
 
285
+ /**
286
+ * @template T
287
+ * @template {keyof T} K
288
+ * @typedef {Omit<T, K> & Partial<T>} PartialBy
289
+ */
290
+
291
+ /**
292
+ * @param {PartialBy<
293
+ * import('./utils/WorkInfo.js').GetWorkDataOptions,
294
+ * "files"|"basePath"|"allowPlugins"
295
+ * >} opts
296
+ */
212
297
  getWorkData (opts) {
213
298
  try {
214
299
  return getWorkData.call(this, {
@@ -225,6 +310,10 @@ class TextBrowser {
225
310
  // Need for directionality even if language specified (and we don't want
226
311
  // to require it as a param)
227
312
  // Todo: Use intl-locale-textinfo-polyfill (already included)
313
+
314
+ /**
315
+ * @param {string} code
316
+ */
228
317
  getDirectionForLanguageCode (code) {
229
318
  const langs = this.langData.languages;
230
319
  const exactMatch = langs.find((lang) => {
@@ -236,10 +325,17 @@ class TextBrowser {
236
325
  });
237
326
  }
238
327
 
328
+ /**
329
+ * @param {import('./utils/Metadata.js').GetFieldNameAndValueAliasesOptions} args
330
+ */
239
331
  getFieldNameAndValueAliases (args) {
240
332
  return getFieldNameAndValueAliases({...args, lang: this.lang});
241
333
  }
242
334
 
335
+ /**
336
+ * @param {Omit<import('./utils/Metadata.js').GetBrowseFieldDataOptions, "lang">} args
337
+ * @returns {void}
338
+ */
243
339
  getBrowseFieldData (args) {
244
340
  return getBrowseFieldData({...args, lang: this.lang});
245
341
  }
@@ -252,6 +348,10 @@ class TextBrowser {
252
348
  ? new IntlURLSearchParams({params: history.state})
253
349
  : new IntlURLSearchParams(); // Uses URL hash for params
254
350
 
351
+ /**
352
+ * @param {string} formSelector
353
+ * @param {() => void} cb
354
+ */
255
355
  const followParams = (formSelector, cb) => {
256
356
  const form = document.querySelector(formSelector);
257
357
  // Record current URL along with state
@@ -274,24 +374,28 @@ class TextBrowser {
274
374
  const [preferredLocale] = lang;
275
375
  const direction = this.getDirectionForLanguageCode(preferredLocale);
276
376
  document.documentElement.lang = preferredLocale;
277
- document.dir = direction;
377
+ document.dir = /** @type {string} */ (direction);
278
378
 
279
379
  const localizationStrings = this.siteData['localization-strings'];
280
380
  const siteI18n = await i18n({
281
381
  messageStyle: 'plainNested',
282
382
  locales: lang,
283
383
  defaultLocales: fallbackLanguages,
284
- localeStringFinder ({
384
+ async localeStringFinder ({
285
385
  locales, defaultLocales
286
- }) {
287
- const locale = [...locales, ...defaultLocales].find((language) => {
386
+ } = {}) {
387
+ const locale = [
388
+ ...(/** @type {string[]} */ (locales)),
389
+ ...(/** @type {string[]} */ (defaultLocales))
390
+ ].find((language) => {
288
391
  return language in localizationStrings;
289
392
  });
290
393
  return {
291
- locale,
394
+ // eslint-disable-next-line object-shorthand -- TS
395
+ locale: /** @type {string} */ (locale),
292
396
  strings: {
293
397
  head: {},
294
- body: localizationStrings[locale]
398
+ body: localizationStrings[/** @type {string} */ (locale)]
295
399
  }
296
400
  };
297
401
  }
@@ -299,14 +403,14 @@ class TextBrowser {
299
403
 
300
404
  // Even if individual pages may end up changing, we need a
301
405
  // title now for accessibility
302
- document.title = siteI18n('browser-title');
406
+ document.title = /** @type {string} */ (siteI18n('browser-title'));
303
407
 
304
408
  const refusedIndexedDB =
305
- // User may have persistence via bookmarks, etc. but just not
306
- // want commital on notification
307
- // Notification.permission === 'default' ||
308
- // We always expect a controller, so is probably first visit
309
- localStorage.getItem(this.namespace + '-refused');
409
+ // User may have persistence via bookmarks, etc. but just not
410
+ // want commital on notification
411
+ // Notification.permission === 'default' ||
412
+ // We always expect a controller, so is probably first visit
413
+ localStorage.getItem(this.namespace + '-refused') === 'true';
310
414
 
311
415
  // This check goes further than `Notification.permission === 'granted'`
312
416
  // to see whether the browser actually considers the notification
@@ -395,8 +499,9 @@ class TextBrowser {
395
499
  const respondToStateOfWorker = async () => {
396
500
  try {
397
501
  return respondToState({
398
- r, langs,
399
- languages: this.languages,
502
+ r,
503
+ // langs,
504
+ // languages: this.languages,
400
505
  logger: Templates.permissions
401
506
  });
402
507
  } catch (err) {
@@ -426,13 +531,13 @@ class TextBrowser {
426
531
  // We don't await the fulfillment of this promise
427
532
  respondToStateOfWorker();
428
533
  listenForWorkerUpdate({
429
- r,
430
- logger: {
431
- addLogEntry (s) {
432
- // We don't put the log in the page as user using
433
- console.log(s);
434
- }
435
- }
534
+ r
535
+ // logger: {
536
+ // addLogEntry (s) {
537
+ // // We don't put the log in the page as user using
538
+ // console.log(s);
539
+ // }
540
+ // }
436
541
  });
437
542
  // Don't return as user may continue working until installed (though
438
543
  // will get message to close tab)
@@ -456,7 +561,13 @@ class TextBrowser {
456
561
  Please wait for a short while as we work to update to a new version.
457
562
  `);
458
563
  respondToStateOfWorker();
459
- navigator.serviceWorker.onmessage({data: 'finishActivate'});
564
+ /**
565
+ * @type {(
566
+ * this: ServiceWorkerContainer,
567
+ * ev: {data: string}
568
+ * ) => void}
569
+ */
570
+ (navigator.serviceWorker.onmessage)({data: 'finishActivate'});
460
571
  // finishActivate({r, logger, namespace, files});
461
572
  return;
462
573
  case 'activated':
@@ -468,13 +579,13 @@ class TextBrowser {
468
579
  // May need to pass in arguments if new service worker appears and
469
580
  // it needs arguments for update
470
581
  listenForWorkerUpdate({
471
- r,
472
- logger: {
473
- addLogEntry (s) {
474
- // We don't put the log in the page as user using
475
- console.log(s);
476
- }
477
- }
582
+ r
583
+ // logger: {
584
+ // addLogEntry (s) {
585
+ // // We don't put the log in the page as user using
586
+ // console.log(s);
587
+ // }
588
+ // }
478
589
  });
479
590
  break;
480
591
  case 'redundant':
@@ -497,7 +608,7 @@ class TextBrowser {
497
608
  // Also could use siteI18n('chooselanguage'), but assumes locale
498
609
  // as with page title
499
610
  // $p.l10n = siteI18n; // Is this in use? No `params`, so not currently
500
- document.title = siteI18n('languages-title');
611
+ document.title = /** @type {string} */ (siteI18n('languages-title'));
501
612
  Templates.languageSelect.main({
502
613
  langs, languages, followParams, $p
503
614
  });
@@ -531,8 +642,9 @@ class TextBrowser {
531
642
  lang, preferredLocale,
532
643
  fallbackLanguages,
533
644
  languageParam,
534
- $p, languages,
535
- preferencesPlugin: this.preferencesPlugin
645
+ $p,
646
+ languages
647
+ // preferencesPlugin: this.preferencesPlugin
536
648
  });
537
649
  return true;
538
650
  }
@@ -563,10 +675,9 @@ class TextBrowser {
563
675
  };
564
676
  return await resultsDisplay();
565
677
  }
566
- }
567
678
 
568
- // Todo: Definable as public fields?
569
- TextBrowser.prototype.workDisplay = workDisplay;
570
- TextBrowser.prototype.resultsDisplayClient = resultsDisplayClient;
679
+ workDisplay = workDisplay;
680
+ resultsDisplayClient = resultsDisplayClient;
681
+ }
571
682
 
572
683
  export default TextBrowser;