textbrowser 0.50.0 → 0.51.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 (104) hide show
  1. package/.ncurc.cjs +3 -0
  2. package/CHANGES.md +8 -0
  3. package/dist/WorkInfo-es.js +361 -111
  4. package/dist/activateCallback-es.js +72 -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 +959 -195
  16. package/dist/index-es.min.js +2 -2
  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 +274 -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 +46 -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 +21 -8
  80. package/resources/activateCallback.js +75 -10
  81. package/resources/index.js +161 -49
  82. package/resources/resultsDisplay.js +517 -152
  83. package/resources/templates/index.js +39 -16
  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 -75
  89. package/resources/templates/workSelect.js +16 -3
  90. package/resources/utils/IntlURLSearchParams.js +46 -4
  91. package/resources/utils/Languages.js +71 -4
  92. package/resources/utils/Metadata.js +219 -22
  93. package/resources/utils/Params.js +70 -23
  94. package/resources/utils/Plugin.js +169 -1
  95. package/resources/utils/ServiceWorker.js +48 -19
  96. package/resources/utils/WorkInfo.js +255 -43
  97. package/resources/utils/dialogs.js +105 -7
  98. package/resources/utils/getLocaleFallbackResults.js +12 -2
  99. package/resources/utils/sanitize.js +4 -0
  100. package/resources/workDisplay.js +151 -25
  101. package/resources/workSelect.js +37 -17
  102. package/server/main.js +111 -19
  103. package/tsconfig.json +30 -0
  104. package/resources/user.js +0 -20
package/dist/index-es.js CHANGED
@@ -1,18 +1,41 @@
1
- /* eslint-disable node/no-unsupported-features/es-syntax */
1
+ /**
2
+ * @typedef {JSONValue[]} JSONArray
3
+ */
4
+ /**
5
+ * @typedef {null|boolean|number|string|JSONArray|{[key: string]: JSONValue}} JSONValue
6
+ */
2
7
 
3
8
  /**
4
- * @callback getJSONCallback
5
- * @param {string|string[]} jsonURL
6
- * @param {SimpleJSONCallback} cb
7
- * @param {SimpleJSONErrback} errBack
8
- * @returns {Promise<JSON>}
9
+ * @callback SimpleJSONCallback
10
+ * @param {...JSONValue} json
11
+ * @returns {void}
12
+ */
13
+
14
+ /**
15
+ * @callback SimpleJSONErrback
16
+ * @param {Error} err
17
+ * @param {string|string[]} jsonURL
18
+ * @returns {JSONValue}
19
+ */
20
+
21
+ /**
22
+ * @typedef {((
23
+ * jsonURL: string|string[],
24
+ * cb?: SimpleJSONCallback,
25
+ * errBack?: SimpleJSONErrback
26
+ * ) => Promise<JSONValue>) & {
27
+ * _fetch?: import('./index-polyglot.js').SimpleFetch,
28
+ * hasURLBasePath?: boolean,
29
+ * basePath?: string|false
30
+ * }} getJSONCallback
9
31
  */
10
32
 
11
33
  /**
12
- * @param {PlainObject} cfg
13
- * @param {fetch} cfg.fetch
34
+ * @param {object} [cfg]
35
+ * @param {import('./index-polyglot.js').SimpleFetch} [cfg.fetch]
14
36
  * @returns {getJSONCallback}
15
37
  */
38
+
16
39
  function _await$2$1(value, then, direct) {
17
40
  if (!value || !value.then) {
18
41
  value = Promise.resolve(value);
@@ -38,22 +61,9 @@ function _catch$2(body, recover) {
38
61
  return result;
39
62
  }
40
63
  function buildGetJSONWithFetch({
41
- // eslint-disable-next-line no-shadow
64
+ // eslint-disable-next-line no-shadow, no-undef -- This is a polyfill
42
65
  fetch = typeof window !== 'undefined' ? window.fetch : self.fetch
43
66
  } = {}) {
44
- /**
45
- * @callback SimpleJSONCallback
46
- * @param {JSON} json
47
- * @returns {void}
48
- */
49
-
50
- /**
51
- * @callback SimpleJSONErrback
52
- * @param {Error} err
53
- * @param {string|string[]} jsonURL
54
- * @returns {void}
55
- */
56
-
57
67
  /**
58
68
  * @type {getJSONCallback}
59
69
  */
@@ -64,10 +74,10 @@ function buildGetJSONWithFetch({
64
74
  return _invoke$1(function () {
65
75
  if (Array.isArray(jsonURL)) {
66
76
  return _await$2$1(Promise.all(jsonURL.map(url => {
67
- return getJSON(url);
77
+ return /** @type {getJSONCallback} */getJSON(url);
68
78
  })), function (arrResult) {
69
79
  if (cb) {
70
- // eslint-disable-next-line node/callback-return, node/no-callback-literal, promise/prefer-await-to-callbacks
80
+ // eslint-disable-next-line promise/prefer-await-to-callbacks -- Old-style API
71
81
  cb(...arrResult);
72
82
  }
73
83
  _exit = true;
@@ -77,20 +87,22 @@ function buildGetJSONWithFetch({
77
87
  }, function (_result) {
78
88
  return _exit ? _result : _await$2$1(fetch(jsonURL), function (resp) {
79
89
  return _await$2$1(resp.json(), function (result) {
80
- return typeof cb === 'function' // eslint-disable-next-line promise/prefer-await-to-callbacks
81
- ? cb(result) : result; // https://github.com/bcoe/c8/issues/135
82
-
90
+ return typeof cb === 'function'
91
+ // eslint-disable-next-line promise/prefer-await-to-callbacks -- Old-style API
92
+ ? cb(result) : result;
93
+ // https://github.com/bcoe/c8/issues/135
83
94
  /* c8 ignore next */
84
95
  });
85
96
  });
86
97
  });
87
- }, function (e) {
98
+ }, function (err) {
99
+ const e = /** @type {Error} */err;
88
100
  e.message += ` (File: ${jsonURL})`;
89
101
  if (errBack) {
90
102
  return errBack(e, jsonURL);
91
103
  }
92
- throw e; // https://github.com/bcoe/c8/issues/135
93
-
104
+ throw e;
105
+ // https://github.com/bcoe/c8/issues/135
94
106
  /* c8 ignore next */
95
107
  }));
96
108
  /* c8 ignore next */
@@ -105,27 +117,33 @@ function _await$1$1(value, then, direct) {
105
117
  }
106
118
  return then ? value.then(then) : value;
107
119
  }
120
+ /* globals process -- Node */
108
121
 
109
- /* eslint-disable node/no-unsupported-features/node-builtins,
110
- node/no-unsupported-features/es-syntax, compat/compat */
111
122
  // Needed for polyglot support (no `path` in browser); even if
112
123
  // polyglot using dynamic `import` not supported by Rollup (complaining
113
124
  // of inability to do tree-shaking in UMD builds), still useful to delay
114
125
  // path import for our testing, so that test can import this file in
115
126
  // the browser without compilation without it choking
116
- let dirname, isWindows;
117
- function _empty() {}
127
+
118
128
  /**
119
- * @param {string} path
120
- * @returns {string}
129
+ * @type {(directory: string) => string}
121
130
  */
131
+ let dirname;
132
+
133
+ /** @type {boolean} */
122
134
 
135
+ function _empty() {}
136
+ let isWindows;
123
137
  function _invokeIgnored(body) {
124
138
  var result = body();
125
139
  if (result && result.then) {
126
140
  return result.then(_empty);
127
141
  }
128
- }
142
+ } /**
143
+ * @param {string} path
144
+ * @returns {string}
145
+ */
146
+
129
147
  function _async$1$1(f) {
130
148
  return function () {
131
149
  for (var args = [], i = 0; i < arguments.length; i++) {
@@ -141,7 +159,7 @@ function _async$1$1(f) {
141
159
  const setDirname = _async$1$1(function () {
142
160
  return _invokeIgnored(function () {
143
161
  if (!dirname) {
144
- return _await$1$1(import('path'), function (_import) {
162
+ return _await$1$1(import('node:path'), function (_import) {
145
163
  ({
146
164
  dirname
147
165
  } = _import);
@@ -155,15 +173,14 @@ function fixWindowsPath(path) {
155
173
  }
156
174
  return path.slice(
157
175
  // https://github.com/bcoe/c8/issues/135
158
-
159
176
  /* c8 ignore next */
160
177
  isWindows ? 1 : 0);
161
178
  }
179
+
162
180
  /**
163
181
  * @param {string} url
164
182
  * @returns {string}
165
183
  */
166
-
167
184
  function getDirectoryForURL(url) {
168
185
  // Node should be ok with this, but transpiling
169
186
  // to `require` doesn't work, so detect Windows
@@ -172,7 +189,13 @@ function getDirectoryForURL(url) {
172
189
  return fixWindowsPath(dirname(new URL(url).pathname));
173
190
  }
174
191
 
175
- /* eslint-disable node/no-unsupported-features/es-syntax */
192
+ /* globals window, self -- Polyglot */
193
+
194
+ /**
195
+ * @typedef {(url: string) => Promise<Response>} SimpleFetch
196
+ */
197
+
198
+ /** @type {{default: SimpleFetch}} */
176
199
 
177
200
  function _await$3(value, then, direct) {
178
201
  if (!value || !value.then) {
@@ -182,10 +205,10 @@ function _await$3(value, then, direct) {
182
205
  }
183
206
  let nodeFetch;
184
207
  /**
185
- * @param {PlainObject} cfg
186
- * @param {string} cfg.baseURL
187
- * @param {string} cfg.cwd
188
- * @returns {getJSONCallback}
208
+ * @param {object} [cfg]
209
+ * @param {string} [cfg.baseURL]
210
+ * @param {string|false} [cfg.cwd]
211
+ * @returns {import('./buildGetJSONWithFetch.js').getJSONCallback}
189
212
  */
190
213
 
191
214
  function _invoke$2(body, then) {
@@ -219,18 +242,27 @@ function buildGetJSON({
219
242
  baseURL,
220
243
  cwd: basePath
221
244
  } = {}) {
222
- const _fetch = typeof window !== 'undefined' || typeof self !== 'undefined' ? typeof window !== 'undefined' ? window.fetch : self.fetch : _async$2(function (jsonURL) {
245
+ const _fetch = typeof window !== 'undefined' || typeof self !== 'undefined' ? typeof window !== 'undefined' ? window.fetch : self.fetch
246
+ // eslint-disable-next-line @stylistic/operator-linebreak -- TS
247
+ :
248
+ /**
249
+ * @param {string} jsonURL
250
+ * @returns {Promise<Response>}
251
+ */
252
+ _async$2(function (jsonURL) {
223
253
  let _exit = false;
224
254
  return _invoke$2(function () {
225
255
  if (/^https?:/u.test(jsonURL)) {
226
256
  return _invoke$2(function () {
227
257
  if (!nodeFetch) {
228
- return _await$3(import('node-fetch'), function (_import) {
258
+ return _await$3(import('node-fetch'), function (/** @type {{default: SimpleFetch}} */
259
+ /** @type {unknown} */
260
+ _import) {
229
261
  nodeFetch = _import;
230
262
  });
231
263
  }
232
264
  }, function () {
233
- const _nodeFetch$default = nodeFetch.default(jsonURL);
265
+ const _nodeFetch$default = /** @type {SimpleFetch} */nodeFetch.default(jsonURL);
234
266
  _exit = true;
235
267
  return _nodeFetch$default;
236
268
  });
@@ -246,40 +278,46 @@ function buildGetJSON({
246
278
  // Filed https://github.com/bergos/file-fetch/issues/12 to see
247
279
  // about getting relative basePaths in `file-fetch` and using
248
280
  // that better-tested package instead
281
+ // @ts-expect-error Todo
282
+ // Don't change to an import as won't resolve for browser testing
283
+ // eslint-disable-next-line promise/avoid-new -- own API
284
+ /* c8 ignore next */
249
285
  return _await$3(import('local-xmlhttprequest'), function (localXMLHttpRequest) {
250
- // eslint-disable-next-line no-shadow
251
- const XMLHttpRequest = localXMLHttpRequest.default({
286
+ const XMLHttpRequest = /* eslint-disable jsdoc/valid-types -- Bug */
287
+ /**
288
+ * @type {{
289
+ * prototype: XMLHttpRequest;
290
+ * new(): XMLHttpRequest
291
+ * }}
292
+ */localXMLHttpRequest.default({
293
+ /* eslint-enable jsdoc/valid-types -- Bug */
252
294
  basePath
253
- }); // Don't change to an import as won't resolve for browser testing
254
- // eslint-disable-next-line promise/avoid-new
255
-
295
+ });
256
296
  return new Promise((resolve, reject) => {
257
297
  const r = new XMLHttpRequest();
258
- r.open('GET', jsonURL, true); // r.responseType = 'json';
298
+ r.open('GET', jsonURL, true);
299
+ // r.responseType = 'json';
259
300
  // eslint-disable-next-line unicorn/prefer-add-event-listener -- May not be available
260
-
261
301
  r.onreadystatechange = function () {
262
302
  // Not sure how to simulate `if`
263
-
264
- /* c8 ignore next */
303
+ /* c8 ignore next 3 */
265
304
  if (r.readyState !== 4) {
266
305
  return;
267
306
  }
268
307
  if (r.status === 200) {
269
308
  // var json = r.json;
270
309
  const response = r.responseText;
271
- resolve({
310
+ resolve(/** @type {Response} */{
272
311
  json: () => JSON.parse(response)
273
312
  });
274
313
  return;
275
314
  }
276
315
  reject(new SyntaxError('Failed to fetch URL: ' + jsonURL + 'state: ' + r.readyState + '; status: ' + r.status));
277
316
  };
278
- r.send(); // https://github.com/bcoe/c8/issues/135
279
-
317
+ r.send();
318
+ // https://github.com/bcoe/c8/issues/135
280
319
  /* c8 ignore next */
281
320
  });
282
- /* c8 ignore next */
283
321
  });
284
322
  });
285
323
  });
@@ -3710,6 +3748,17 @@ function deserialize(form, hash) {
3710
3748
  /**
3711
3749
  * @file Note that this should be kept as a polyglot client-server file.
3712
3750
  */
3751
+
3752
+ /**
3753
+ * @param {{
3754
+ * $p: import('./IntlURLSearchParams').default,
3755
+ * lang: string[],
3756
+ * langs: import('../../server/main.js').LanguageInfo[],
3757
+ * langData: import('../../server/main.js').LanguagesData,
3758
+ * fallbackLanguages?: string[],
3759
+ * basePath?: string
3760
+ * }} options
3761
+ */
3713
3762
  async function getLocaleFallbackResults(_ref) {
3714
3763
  let {
3715
3764
  $p,
@@ -3728,9 +3777,9 @@ async function getLocaleFallbackResults(_ref) {
3728
3777
  // `$ref` (as with <https://github.com/whitlockjc/json-refs>) and
3729
3778
  // replace `loadLocales` behavior with our own now resolved
3730
3779
  // locales; see https://github.com/jdorn/json-editor/issues/132
3731
- return basePath + langData.localeFileBasePath + langs.find(l => {
3780
+ return basePath + langData.localeFileBasePath + (langs.find(l => {
3732
3781
  return l.code === code;
3733
- }).locale.$ref;
3782
+ })?.locale?.$ref ?? '');
3734
3783
  }
3735
3784
  });
3736
3785
  if (!$p.l10n) {
@@ -6061,13 +6110,35 @@ if (doc && doc.body) {
6061
6110
  }
6062
6111
  const nbsp = '\u00A0'; // Very commonly needed in templates
6063
6112
 
6113
+ /**
6114
+ * @param {string} sel
6115
+ */
6064
6116
  const $ = sel => document.querySelector(sel);
6117
+
6118
+ /**
6119
+ * @param {string|HTMLElement} el
6120
+ * @param {string} descendentsSel
6121
+ */
6065
6122
  const $e = (el, descendentsSel) => {
6066
- el = typeof el === 'string' ? $(el) : el;
6067
- return el.querySelector(descendentsSel);
6123
+ const elem = typeof el === 'string' ? $(el) : el;
6124
+ return elem?.querySelector(descendentsSel);
6068
6125
  };
6069
6126
 
6127
+ /**
6128
+ * @typedef {{
6129
+ * submit: string,
6130
+ * cancel: string,
6131
+ * ok: string
6132
+ * }} LocaleObject
6133
+ */
6134
+
6135
+ /**
6136
+ * @typedef {{[locale: string]: LocaleObject}} Locales
6137
+ */
6138
+
6070
6139
  const defaultLocale = 'en';
6140
+
6141
+ /** @type {Locales} */
6071
6142
  const localeStrings = {
6072
6143
  en: {
6073
6144
  submit: 'Submit',
@@ -6076,27 +6147,72 @@ const localeStrings = {
6076
6147
  }
6077
6148
  };
6078
6149
  class Dialog {
6150
+ /**
6151
+ * @param {{
6152
+ * locale?: string,
6153
+ * localeObject?: LocaleObject
6154
+ * }} [cfg]
6155
+ */
6079
6156
  constructor() {
6080
6157
  let {
6081
6158
  locale,
6082
6159
  localeObject
6083
6160
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
6161
+ this.localeStrings = localeStrings.en; // For types
6084
6162
  this.setLocale({
6085
6163
  locale,
6086
6164
  localeObject
6087
6165
  });
6088
6166
  }
6167
+ /**
6168
+ * @param {{
6169
+ * locale?: string,
6170
+ * localeObject?: Partial<LocaleObject>
6171
+ * }} cfg
6172
+ * @returns {void}
6173
+ */
6089
6174
  setLocale(_ref) {
6090
6175
  let {
6091
- locale = {},
6176
+ locale,
6092
6177
  localeObject = {}
6093
6178
  } = _ref;
6094
6179
  this.localeStrings = {
6095
6180
  ...localeStrings[defaultLocale],
6096
- ...localeStrings[locale],
6181
+ ...(locale ? localeStrings[locale] : {}),
6097
6182
  ...localeObject
6098
6183
  };
6099
6184
  }
6185
+
6186
+ /**
6187
+ * @typedef {{
6188
+ * atts?: import('jamilih').JamilihAttributes,
6189
+ * children?: import('jamilih').JamilihChildren,
6190
+ * close?: () => void,
6191
+ * remove?: boolean
6192
+ * }} MakeDialogCfg
6193
+ */
6194
+
6195
+ /**
6196
+ * @typedef {MakeDialogCfg & {
6197
+ * submit?: (
6198
+ * this: HTMLElement, args: {e: Event, dialog: HTMLDialogElement}
6199
+ * ) => void,
6200
+ * cancel: (
6201
+ * this: HTMLElement,
6202
+ * args: {
6203
+ * e: Event,
6204
+ * dialog: HTMLDialogElement
6205
+ * }
6206
+ * ) => boolean|void,
6207
+ * cancelClass?: string,
6208
+ * submitClass?: string
6209
+ * }} CancelDialogCfg
6210
+ */
6211
+
6212
+ /**
6213
+ * @param {MakeDialogCfg} cfg
6214
+ * @returns {HTMLDialogElement}
6215
+ */
6100
6216
  makeDialog(_ref2) {
6101
6217
  let {
6102
6218
  atts = {
@@ -6114,7 +6230,8 @@ class Dialog {
6114
6230
  atts.$on.close = close;
6115
6231
  }
6116
6232
  }
6117
- const dialog = /** @type {HTMLDialogElement} */jml('dialog', atts, children, $$1('#main'));
6233
+ const dialog = /** @type {HTMLDialogElement} */
6234
+ jml('dialog', atts, children, $$1('#main'));
6118
6235
  dialog.showModal();
6119
6236
  if (remove) {
6120
6237
  dialog.addEventListener('close', () => {
@@ -6123,6 +6240,10 @@ class Dialog {
6123
6240
  }
6124
6241
  return dialog;
6125
6242
  }
6243
+ /**
6244
+ * @param {CancelDialogCfg} cfg
6245
+ * @returns {HTMLDialogElement}
6246
+ */
6126
6247
  makeSubmitDialog(_ref3) {
6127
6248
  let {
6128
6249
  submit,
@@ -6131,6 +6252,7 @@ class Dialog {
6131
6252
  ...args
6132
6253
  } = _ref3;
6133
6254
  const dialog = this.makeCancelDialog(args);
6255
+ /** @type {HTMLDialogElement} */
6134
6256
  $e(dialog, `button.${args.cancelClass || 'cancel'}`).before(jml('button', {
6135
6257
  class: submitClass,
6136
6258
  $on: {
@@ -6146,6 +6268,11 @@ class Dialog {
6146
6268
  }, [this.localeStrings.submit]), nbsp.repeat(2));
6147
6269
  return dialog;
6148
6270
  }
6271
+
6272
+ /**
6273
+ * @param {CancelDialogCfg} cfg
6274
+ * @returns {HTMLDialogElement}
6275
+ */
6149
6276
  makeCancelDialog(_ref4) {
6150
6277
  let {
6151
6278
  // eslint-disable-next-line no-unused-vars -- Discarding
@@ -6178,6 +6305,12 @@ class Dialog {
6178
6305
  }, [this.localeStrings.cancel]]], dialog);
6179
6306
  return dialog;
6180
6307
  }
6308
+
6309
+ /**
6310
+ * @param {string|{message: string, ok?: boolean, submitClass?: string}} message
6311
+ * @param {boolean|{ok: boolean}} [ok]
6312
+ * @returns {Promise<void>}
6313
+ */
6181
6314
  alert(message, ok) {
6182
6315
  message = typeof message === 'string' ? {
6183
6316
  message
@@ -6188,7 +6321,7 @@ class Dialog {
6188
6321
  submitClass = 'submit'
6189
6322
  } = message;
6190
6323
  return new Promise(resolve => {
6191
- const dialog = /** @type {HTMLDialogElement} */jml('dialog', [msg, ...(includeOk ? [['br'], ['br'], ['div', {
6324
+ const dialog = /** @type {HTMLDialogElement} */jml('dialog', [msg, ...(includeOk ? (/** @type {import('jamilih').JamilihChildren} */[['br'], ['br'], ['div', {
6192
6325
  class: submitClass
6193
6326
  }, [['button', {
6194
6327
  $on: {
@@ -6197,10 +6330,16 @@ class Dialog {
6197
6330
  resolve();
6198
6331
  }
6199
6332
  }
6200
- }, [this.localeStrings.ok]]]]] : [])], $$1('#main'));
6333
+ }, [this.localeStrings.ok]]]]]) : [])], $$1('#main'));
6201
6334
  dialog.showModal();
6202
6335
  });
6203
6336
  }
6337
+ /**
6338
+ * @param {string|Partial<CancelDialogCfg> & {
6339
+ * message: string
6340
+ * }} message
6341
+ * @returns {Promise<string>}
6342
+ */
6204
6343
  prompt(message) {
6205
6344
  message = typeof message === 'string' ? {
6206
6345
  message
@@ -6211,19 +6350,28 @@ class Dialog {
6211
6350
  ...submitArgs
6212
6351
  } = message;
6213
6352
  return new Promise((resolve, reject) => {
6353
+ /**
6354
+ * @param {{
6355
+ * e: Event,
6356
+ * dialog: HTMLDialogElement
6357
+ * }} args
6358
+ */
6214
6359
  const submit = function (_ref5) {
6215
6360
  let {
6216
6361
  e,
6217
6362
  dialog
6218
6363
  } = _ref5;
6219
6364
  if (userSubmit) {
6220
- userSubmit.call(this, {
6365
+ userSubmit.call(
6366
+ // @ts-expect-error Ok
6367
+ /** @type {HTMLElement} */
6368
+ this, {
6221
6369
  e,
6222
6370
  dialog
6223
6371
  });
6224
6372
  }
6225
6373
  dialog.close();
6226
- resolve($e(dialog, 'input').value);
6374
+ resolve(/** @type {HTMLInputElement} */$e(dialog, 'input').value);
6227
6375
  };
6228
6376
  /* const dialog = */
6229
6377
  this.makeSubmitDialog({
@@ -6236,6 +6384,10 @@ class Dialog {
6236
6384
  });
6237
6385
  });
6238
6386
  }
6387
+ /**
6388
+ * @param {string|{message: string, submitClass?: string}} message
6389
+ * @returns {Promise<void>}
6390
+ */
6239
6391
  confirm(message) {
6240
6392
  message = typeof message === 'string' ? {
6241
6393
  message
@@ -6269,6 +6421,13 @@ class Dialog {
6269
6421
  const dialogs = new Dialog();
6270
6422
 
6271
6423
  // Todo: remember this locales choice by cookie?
6424
+
6425
+ /**
6426
+ * @param {{
6427
+ * namespace: string,
6428
+ * preferredLocale: string
6429
+ * }} cfg
6430
+ */
6272
6431
  const getPreferredLanguages = _ref => {
6273
6432
  let {
6274
6433
  namespace,
@@ -6278,7 +6437,10 @@ const getPreferredLanguages = _ref => {
6278
6437
  // Todo: Switch to fallbackLanguages so can default to
6279
6438
  // navigator.languages?
6280
6439
  const langCodes = localStorage.getItem(namespace + '-langCodes');
6281
- const lngs = langCodes && JSON.parse(langCodes) || [preferredLocale];
6440
+ const lngs = /** @type {string[]} */
6441
+ langCodes && JSON.parse(langCodes) || [preferredLocale];
6442
+
6443
+ /** @type {string[]} */
6282
6444
  const langArr = [];
6283
6445
  lngs.forEach(lng => {
6284
6446
  // Todo: Check for multiple separate hyphenated
@@ -6297,20 +6459,62 @@ const getPreferredLanguages = _ref => {
6297
6459
  * @classdesc Note that this should be kept as a polyglot client-server class.
6298
6460
  */
6299
6461
  class Languages {
6462
+ /**
6463
+ * @param {{
6464
+ * langData: import('../../server/main.js').LanguagesData
6465
+ * }} cfg
6466
+ */
6300
6467
  constructor(_ref2) {
6301
6468
  let {
6302
6469
  langData
6303
6470
  } = _ref2;
6304
6471
  this.langData = langData;
6305
6472
  }
6473
+ /**
6474
+ * @param {string} langCode
6475
+ * @returns {{
6476
+ * languages: {
6477
+ * [key: string]: string
6478
+ * }
6479
+ * }}
6480
+ */
6306
6481
  localeFromLangData(langCode) {
6307
- return this.langData['localization-strings'][langCode];
6482
+ return (
6483
+ /**
6484
+ * @type {{
6485
+ * languages: {
6486
+ * [key: string]: string
6487
+ * }
6488
+ * }}
6489
+ */
6490
+ this.langData['localization-strings'][langCode]
6491
+ );
6308
6492
  }
6493
+ /**
6494
+ * @param {string} code
6495
+ * @returns {string}
6496
+ */
6309
6497
  getLanguageFromCode(code) {
6310
6498
  return this.localeFromLangData(code).languages[code];
6311
6499
  // Could add something like this in place or as fallback, though need to pass in locale
6312
6500
  // || new Intl.DisplayNames([locale], {type: 'language'}).of(code);
6313
6501
  }
6502
+
6503
+ /**
6504
+ * @param {{
6505
+ * pluginName: string,
6506
+ * workI18n: import('intl-dom').I18NCallback,
6507
+ * targetLanguage: string,
6508
+ * applicableFieldI18N: string,
6509
+ * meta: {
6510
+ * [key: string]: string
6511
+ * },
6512
+ * metaApplicableField: {
6513
+ * [key: string]: string
6514
+ * },
6515
+ * }} cfg
6516
+ * @returns {string}
6517
+ */
6314
6518
  getFieldNameFromPluginNameAndLocales(_ref3) {
6315
6519
  let {
6316
6520
  pluginName,
@@ -6321,7 +6525,7 @@ class Languages {
6321
6525
  meta,
6322
6526
  metaApplicableField
6323
6527
  } = _ref3;
6324
- return workI18n(['plugins', pluginName, 'fieldname'], {
6528
+ return /** @type {string} */workI18n(['plugins', pluginName, 'fieldname'], {
6325
6529
  ...meta,
6326
6530
  ...metaApplicableField,
6327
6531
  applicableField: applicableFieldI18N,
@@ -6331,11 +6535,24 @@ class Languages {
6331
6535
  throwOnExtraSuppliedFormatters: false
6332
6536
  });
6333
6537
  }
6538
+
6539
+ /**
6540
+ * @param {{$p: import('./IntlURLSearchParams.js').default}} cfg
6541
+ * @returns {{
6542
+ * lang: string[],
6543
+ * langs: import('../../server/main.js').LanguageInfo[],
6544
+ * languageParam: string|null,
6545
+ * fallbackLanguages: string[]
6546
+ * }}
6547
+ */
6334
6548
  getLanguageInfo(_ref4) {
6335
6549
  let {
6336
6550
  $p
6337
6551
  } = _ref4;
6338
6552
  const langs = this.langData.languages;
6553
+ /**
6554
+ * @param {string} lcl
6555
+ */
6339
6556
  const localePass = lcl => {
6340
6557
  return langs.some(_ref5 => {
6341
6558
  let {
@@ -14285,23 +14502,57 @@ var JsonRefs = function (t) {
14285
14502
  const getCurrDir = () => {
14286
14503
  return window.location.href.replace(/(index\.html)?#.*$/, '');
14287
14504
  };
14505
+
14506
+ /**
14507
+ * @typedef {{
14508
+ * "localization-strings": import('../../server/main.js').LocalizationStrings
14509
+ * table: {browse_fields: (string|{
14510
+ * name?: string,
14511
+ * set: string[],
14512
+ * presort?: boolean
14513
+ * })[]}
14514
+ * fields: {
14515
+ * [key: string]: {
14516
+ * prefer_alias: boolean,
14517
+ * lang: string,
14518
+ * 'fieldvalue-aliases': {
14519
+ * localeKey: string,
14520
+ * [key: string]: string|string[]
14521
+ * }
14522
+ * }
14523
+ * }
14524
+ * }} MetadataObj
14525
+ */
14526
+
14527
+ /**
14528
+ * @param {string[]} lang
14529
+ * @param {MetadataObj} metadataObj
14530
+ * @param {string|string[]} properties
14531
+ * @param {boolean} [allowObjects]
14532
+ * @returns {string|string[]|import('../../server/main.js').LocalizationStrings}
14533
+ */
14288
14534
  const getMetaProp = function getMetaProp(lang, metadataObj, properties, allowObjects) {
14289
14535
  let prop;
14290
14536
  properties = typeof properties === 'string' ? [properties] : properties;
14291
- lang.some(lan => {
14537
+ for (const lan of lang) {
14292
14538
  const p = [...properties];
14293
- let strings = metadataObj['localization-strings'][lan];
14539
+ let strings = /** @type {string | string[]|import('../../server/main.js').LocalizationStrings} */
14540
+ metadataObj['localization-strings'][lan];
14294
14541
  while (strings && p.length) {
14295
- strings = strings[p.shift()];
14542
+ strings = /** @type {import('../../server/main.js').LocalizationStrings} */strings[(/** @type {string} */p.shift())];
14296
14543
  }
14297
14544
  // Todo: Fix this allowance for allowObjects (as it does not properly
14298
14545
  // fallback if an object is returned from a language because
14299
14546
  // that language is missing content and is only thus returning
14300
14547
  // an object)
14301
14548
  prop = allowObjects || typeof strings === 'string' ? strings : undefined;
14302
- return prop;
14303
- });
14304
- return prop;
14549
+ if (prop) {
14550
+ break;
14551
+ }
14552
+ }
14553
+ return /** @type {string|string[]|import('../../server/main.js').LocalizationStrings} */(
14554
+ prop
14555
+ );
14305
14556
  };
14306
14557
 
14307
14558
  // Use the following to dynamically add specific file schema in place of
@@ -14309,6 +14560,12 @@ const getMetaProp = function getMetaProp(lang, metadataObj, properties, allowObj
14309
14560
  // filesSchema.properties.groups.items.properties.files.items.properties.
14310
14561
  // file.anyOf.splice(1, 1, {$ref: schemaFile});
14311
14562
  // Todo: Allow use of dbs and fileGroup together in base directories?
14563
+
14564
+ /**
14565
+ * @param {string} file
14566
+ * @param {string} property
14567
+ * @param {string} basePath
14568
+ */
14312
14569
  const getMetadata = async (file, property, basePath) => {
14313
14570
  const url = new URL(basePath || getCurrDir());
14314
14571
  url.search = ''; // Clear out query string, e.g., `?fbclid` from Facebook
@@ -14316,6 +14573,13 @@ const getMetadata = async (file, property, basePath) => {
14316
14573
  url.hash = property ? '#/' + property : '';
14317
14574
  return (await JsonRefs.resolveRefsAt(url.toString(), {
14318
14575
  loaderOptions: {
14576
+ /**
14577
+ * @param {{
14578
+ * text: string,
14579
+ * body: any
14580
+ * }} res
14581
+ * @param {(err?: Error, cbValue: any) => void} callback
14582
+ */
14319
14583
  processContent(res, callback) {
14320
14584
  callback(undefined, JSON.parse(res.text ||
14321
14585
  // `.metadata` not a recognized extension, so
@@ -14325,6 +14589,37 @@ const getMetadata = async (file, property, basePath) => {
14325
14589
  }
14326
14590
  })).resolved;
14327
14591
  };
14592
+
14593
+ /**
14594
+ * @typedef {{
14595
+ * field: string,
14596
+ * schemaItems: {
14597
+ * title: string,
14598
+ * type: string,
14599
+ * enum?: string[]
14600
+ * }[],
14601
+ * metadataObj: MetadataObj,
14602
+ * getFieldAliasOrName: (field: string) => string,
14603
+ * lang: string[]
14604
+ * }} GetFieldNameAndValueAliasesOptions
14605
+ */
14606
+
14607
+ /**
14608
+ * @param {GetFieldNameAndValueAliasesOptions} cfg
14609
+ * @returns {{
14610
+ * aliases: string[]|null,
14611
+ * fieldValueAliasMap: Record<string, string[]>|null,
14612
+ * rawFieldValueAliasMap: Record<string, string[]>|null,
14613
+ * fieldName: string,
14614
+ * fieldSchema: {
14615
+ * title: string,
14616
+ * type: string
14617
+ * },
14618
+ * fieldSchemaIndex: number,
14619
+ * preferAlias: boolean,
14620
+ * lang: string
14621
+ * }}
14622
+ */
14328
14623
  const getFieldNameAndValueAliases = function (_ref) {
14329
14624
  let {
14330
14625
  field,
@@ -14338,6 +14633,22 @@ const getFieldNameAndValueAliases = function (_ref) {
14338
14633
  });
14339
14634
  const fieldSchema = schemaItems[fieldSchemaIndex];
14340
14635
  const fieldInfo = metadataObj.fields[field];
14636
+
14637
+ /**
14638
+ * @type {{
14639
+ * aliases: string[]|null,
14640
+ * fieldValueAliasMap: Record<string, string[]>|null,
14641
+ * rawFieldValueAliasMap: Record<string, string[]>|null,
14642
+ * fieldName: string,
14643
+ * fieldSchema: {
14644
+ * title: string,
14645
+ * type: string
14646
+ * },
14647
+ * fieldSchemaIndex: number,
14648
+ * preferAlias: boolean,
14649
+ * lang: string
14650
+ * }}
14651
+ */
14341
14652
  const ret = {
14342
14653
  // field,
14343
14654
  aliases: null,
@@ -14349,10 +14660,14 @@ const getFieldNameAndValueAliases = function (_ref) {
14349
14660
  preferAlias: fieldInfo.prefer_alias,
14350
14661
  lang: fieldInfo.lang
14351
14662
  };
14663
+
14664
+ /** @type {import('../../server/main.js').LocalizationStrings} */
14352
14665
  let fieldValueAliasMap = fieldInfo && fieldInfo['fieldvalue-aliases'];
14353
14666
  if (fieldValueAliasMap) {
14354
14667
  if (fieldValueAliasMap.localeKey) {
14355
- fieldValueAliasMap = getMetaProp(lang, metadataObj, fieldValueAliasMap.localeKey.split('/'), true);
14668
+ fieldValueAliasMap = /** @type {import('../../server/main.js').LocalizationStrings} */
14669
+ getMetaProp(lang, metadataObj, /** @type {string} */
14670
+ fieldValueAliasMap.localeKey.split('/'), true);
14356
14671
  }
14357
14672
  // eslint-disable-next-line unicorn/prefer-structured-clone -- Expecting JSON
14358
14673
  ret.rawFieldValueAliasMap = JSON.parse(JSON.stringify(fieldValueAliasMap));
@@ -14361,11 +14676,14 @@ const getFieldNameAndValueAliases = function (_ref) {
14361
14676
  // needed cases
14362
14677
  if (fieldSchema.enum && fieldSchema.enum.length) {
14363
14678
  fieldSchema.enum.forEach(enm => {
14364
- ret.aliases.push(getMetaProp(lang, metadataObj, ['fieldvalue', field, enm], true));
14679
+ /** @type {string[]} */
14680
+ ret.aliases.push(/** @type {string} */
14681
+ getMetaProp(lang, metadataObj, ['fieldvalue', field, enm], true));
14365
14682
  if (enm in fieldValueAliasMap &&
14366
14683
  // Todo: We could allow numbers here too, but crowds
14367
14684
  // pull-down
14368
14685
  typeof fieldValueAliasMap[enm] === 'string') {
14686
+ /** @type {string[]} */
14369
14687
  ret.aliases.push(...fieldValueAliasMap[enm]);
14370
14688
  }
14371
14689
  });
@@ -14378,9 +14696,12 @@ const getFieldNameAndValueAliases = function (_ref) {
14378
14696
  // We'll preserve the numbers since probably more useful if
14379
14697
  // stored with data (as opposed to enums)
14380
14698
  if (!Array.isArray(aliases)) {
14381
- aliases = Object.values(aliases);
14699
+ aliases = /** @type {string[]} */
14700
+ Object.values(/** @type {import('../../server/main.js').LocalizationStrings} */
14701
+ aliases);
14382
14702
  }
14383
14703
  // We'll assume the longest version is best for auto-complete
14704
+ /** @type {string[]} */
14384
14705
  ret.aliases.push(...aliases.filter(v => {
14385
14706
  return aliases.every(x => {
14386
14707
  return x === v || !x.toLowerCase().startsWith(v.toLowerCase());
@@ -14395,6 +14716,40 @@ const getFieldNameAndValueAliases = function (_ref) {
14395
14716
  }
14396
14717
  return ret;
14397
14718
  };
14719
+
14720
+ /**
14721
+ * @typedef {{
14722
+ * metadataObj: MetadataObj,
14723
+ * schemaItems: {
14724
+ * title: string,
14725
+ * type: string
14726
+ * }[],
14727
+ * getFieldAliasOrName: (field: string) => string,
14728
+ * lang: string[],
14729
+ * callback: (cfg: {
14730
+ * setName: string,
14731
+ * browseFields: {
14732
+ * aliases: string[]|null,
14733
+ * fieldValueAliasMap: Record<string, string[]>|null,
14734
+ * rawFieldValueAliasMap: Record<string, string[]>|null,
14735
+ * fieldName: string,
14736
+ * fieldSchema: {
14737
+ * title: string,
14738
+ * type: string
14739
+ * },
14740
+ * fieldSchemaIndex: number,
14741
+ * preferAlias: boolean,
14742
+ * lang: string
14743
+ * }[],
14744
+ * i: number,
14745
+ * presort: boolean|undefined
14746
+ * }) => void
14747
+ * }} GetBrowseFieldDataOptions
14748
+ */
14749
+
14750
+ /**
14751
+ * @param {GetBrowseFieldDataOptions} cfg
14752
+ */
14398
14753
  const getBrowseFieldData = function (_ref3) {
14399
14754
  let {
14400
14755
  metadataObj,
@@ -14440,12 +14795,22 @@ const getBrowseFieldData = function (_ref3) {
14440
14795
 
14441
14796
  // Todo: Incorporate other methods into this class
14442
14797
  class Metadata {
14798
+ /**
14799
+ * @param {{
14800
+ * metadataObj: MetadataObj
14801
+ * }} cfg
14802
+ */
14443
14803
  constructor(_ref4) {
14444
14804
  let {
14445
14805
  metadataObj
14446
14806
  } = _ref4;
14447
14807
  this.metadataObj = metadataObj;
14448
14808
  }
14809
+
14810
+ /**
14811
+ * @param {string} field
14812
+ * @returns {string|undefined}
14813
+ */
14449
14814
  getFieldLang(field) {
14450
14815
  const {
14451
14816
  metadataObj
@@ -14453,6 +14818,19 @@ class Metadata {
14453
14818
  const fields = metadataObj && metadataObj.fields;
14454
14819
  return fields && fields[field] && fields[field].lang;
14455
14820
  }
14821
+
14822
+ /**
14823
+ * @param {{
14824
+ * namespace: string,
14825
+ * preferredLocale: string,
14826
+ * schemaItems: {
14827
+ * title: string,
14828
+ * type: string
14829
+ * }[],
14830
+ * pluginsForWork: import('./Plugin.js').PluginsForWork
14831
+ * }} cfg
14832
+ * @returns {(field: string) => boolean}
14833
+ */
14456
14834
  getFieldMatchesLocale(_ref5) {
14457
14835
  let {
14458
14836
  namespace,
@@ -14487,7 +14865,9 @@ class Metadata {
14487
14865
  // If this is a localized field (e.g., enum), we don't want
14488
14866
  // to avoid as may be translated (should check though)
14489
14867
  const hasFieldValue = localeStrings && Object.keys(localeStrings).some(lng => {
14490
- const fv = localeStrings[lng] && localeStrings[lng].fieldvalue;
14868
+ const fv = localeStrings[lng] && (/** @type {import('../../server/main.js').LocalizationStrings} */
14869
+ /** @type {import('../../server/main.js').LocalizationStrings} */
14870
+ localeStrings[lng].fieldvalue);
14491
14871
  return fv && fv[field];
14492
14872
  });
14493
14873
  return hasFieldValue || metaLang && preferredLanguages.includes(metaLang) || schemaItems.some(item => {
@@ -14497,11 +14877,18 @@ class Metadata {
14497
14877
  }
14498
14878
  }
14499
14879
 
14880
+ /**
14881
+ * @param {string} pluginName
14882
+ */
14500
14883
  const escapePluginComponent = pluginName => {
14501
14884
  return pluginName.replaceAll('^', '^^').
14502
14885
  // Escape our escape
14503
14886
  replaceAll('-', '^0');
14504
14887
  };
14888
+
14889
+ /**
14890
+ * @param {string|undefined} pluginName
14891
+ */
14505
14892
  const unescapePluginComponent = pluginName => {
14506
14893
  if (!pluginName) {
14507
14894
  return pluginName;
@@ -14510,6 +14897,14 @@ const unescapePluginComponent = pluginName => {
14510
14897
  return esc.length % 2 ? esc.slice(1) + '-' : n0;
14511
14898
  }).replaceAll('^^', '^');
14512
14899
  };
14900
+
14901
+ /**
14902
+ * @param {{
14903
+ * pluginName: string,
14904
+ * applicableField: string,
14905
+ * targetLanguage: string
14906
+ * }} cfg
14907
+ */
14513
14908
  const escapePlugin = _ref => {
14514
14909
  let {
14515
14910
  pluginName,
@@ -14518,7 +14913,28 @@ const escapePlugin = _ref => {
14518
14913
  } = _ref;
14519
14914
  return escapePluginComponent(pluginName) + (applicableField ? '-' + escapePluginComponent(applicableField) : '-') + (targetLanguage ? '-' + escapePluginComponent(targetLanguage) : '');
14520
14915
  };
14916
+
14917
+ /**
14918
+ * @todo Complete
14919
+ * @typedef {{}} PluginObject
14920
+ */
14921
+
14521
14922
  class PluginsForWork {
14923
+ /**
14924
+ * @param {{
14925
+ * pluginsInWork: [string, {
14926
+ * lang: string,
14927
+ * meta: any,
14928
+ * onByDefault: boolean
14929
+ * }][],
14930
+ * pluginFieldMappings: {
14931
+ * placement: string,
14932
+ * 'applicable-fields': {
14933
+ * }
14934
+ * }[],
14935
+ * pluginObjects: PluginObject[]
14936
+ * }} cfg
14937
+ */
14522
14938
  constructor(_ref2) {
14523
14939
  let {
14524
14940
  pluginsInWork,
@@ -14529,6 +14945,11 @@ class PluginsForWork {
14529
14945
  this.pluginFieldMappings = pluginFieldMappings;
14530
14946
  this.pluginObjects = pluginObjects;
14531
14947
  }
14948
+
14949
+ /**
14950
+ * @param {string} pluginName
14951
+ * @returns {PluginObject}
14952
+ */
14532
14953
  getPluginObject(pluginName) {
14533
14954
  const idx = this.pluginsInWork.findIndex(_ref3 => {
14534
14955
  let [name] = _ref3;
@@ -14537,6 +14958,25 @@ class PluginsForWork {
14537
14958
  const plugin = this.pluginObjects[idx];
14538
14959
  return plugin;
14539
14960
  }
14961
+
14962
+ /**
14963
+ * @param {(cfg: {
14964
+ * plugin: PluginObject,
14965
+ * placement: string,
14966
+ * applicableFields: {
14967
+ * [applicableField: string]: {
14968
+ * targetLanguage: string|string[],
14969
+ * onByDefault: boolean,
14970
+ * meta: any
14971
+ * }
14972
+ * },
14973
+ * pluginName: string,
14974
+ * pluginLang: string,
14975
+ * onByDefaultDefault: boolean,
14976
+ * meta: {}
14977
+ * }) => void} cb
14978
+ * @returns {void}
14979
+ */
14540
14980
  iterateMappings(cb) {
14541
14981
  this.pluginFieldMappings.forEach((_ref4, i) => {
14542
14982
  let {
@@ -14566,6 +15006,25 @@ class PluginsForWork {
14566
15006
  });
14567
15007
  });
14568
15008
  }
15009
+
15010
+ /**
15011
+ * @param {{
15012
+ * [applicableField: string]: {
15013
+ * targetLanguage: string|string[],
15014
+ * onByDefault: boolean,
15015
+ * meta: any
15016
+ * }
15017
+ * }} applicableFields
15018
+ * @param {(cfg: {
15019
+ * applicableField: string,
15020
+ * targetLanguage: string,
15021
+ * onByDefault: boolean,
15022
+ * metaApplicableField: {
15023
+ * [key: string]: string
15024
+ * }
15025
+ * }) => void} cb
15026
+ * @returns {boolean}
15027
+ */
14569
15028
  processTargetLanguages(applicableFields, cb) {
14570
15029
  if (!applicableFields) {
14571
15030
  return false;
@@ -14596,6 +15055,14 @@ class PluginsForWork {
14596
15055
  });
14597
15056
  return true;
14598
15057
  }
15058
+
15059
+ /**
15060
+ * @param {{
15061
+ * namespace: string,
15062
+ * field: string
15063
+ * }} cfg
15064
+ * @returns {boolean}
15065
+ */
14599
15066
  isPluginField(_ref6) {
14600
15067
  let {
14601
15068
  namespace,
@@ -14603,6 +15070,14 @@ class PluginsForWork {
14603
15070
  } = _ref6;
14604
15071
  return field.startsWith(`${namespace}-plugin-`);
14605
15072
  }
15073
+
15074
+ /**
15075
+ * @param {{
15076
+ * namespace: string,
15077
+ * field: string
15078
+ * }} cfg
15079
+ * @returns {[string, string|undefined, string|undefined]}
15080
+ */
14606
15081
  getPluginFieldParts(_ref7) {
14607
15082
  let {
14608
15083
  namespace,
@@ -14615,11 +15090,19 @@ class PluginsForWork {
14615
15090
  } else {
14616
15091
  pluginName = field;
14617
15092
  }
14618
- return [pluginName, applicableField, targetLanguage].map(unescapePluginComponent);
15093
+ return /** @type {[string, string|undefined, string|undefined]} */(
15094
+ [pluginName, applicableField, targetLanguage].map(unescapePluginComponent)
15095
+ );
14619
15096
  }
14620
15097
  }
14621
15098
 
14622
15099
  /* globals process -- Node polyglot */
15100
+
15101
+ /**
15102
+ * @param {FilesObject} filesObj
15103
+ * @param {FileGroup} fileGroup
15104
+ * @param {FileData} fileData
15105
+ */
14623
15106
  const getFilePaths = function getFilePaths(filesObj, fileGroup, fileData) {
14624
15107
  const baseDir = (filesObj.baseDirectory || '') + (fileGroup.baseDirectory || '') + '/';
14625
15108
  const schemaBaseDir = (filesObj.schemaBaseDirectory || '') + (fileGroup.schemaBaseDirectory || '') + '/';
@@ -14633,6 +15116,23 @@ const getFilePaths = function getFilePaths(filesObj, fileGroup, fileData) {
14633
15116
  metadataFile
14634
15117
  };
14635
15118
  };
15119
+
15120
+ /**
15121
+ * @typedef {{
15122
+ * lang: string[],
15123
+ * fallbackLanguages: string[],
15124
+ * work: string,
15125
+ * files: string,
15126
+ * allowPlugins: boolean|undefined,
15127
+ * basePath: string,
15128
+ * languages: import('./Languages.js').Languages,
15129
+ * preferredLocale: string
15130
+ * }} GetWorkDataOptions
15131
+ */
15132
+
15133
+ /**
15134
+ * @param {GetWorkDataOptions} cfg
15135
+ */
14636
15136
  const getWorkData = async function (_ref) {
14637
15137
  let {
14638
15138
  lang,
@@ -14645,7 +15145,15 @@ const getWorkData = async function (_ref) {
14645
15145
  preferredLocale
14646
15146
  } = _ref;
14647
15147
  const filesObj = await getJSON(files);
14648
- const localizationStrings = filesObj['localization-strings'];
15148
+ const localizationStrings =
15149
+ /**
15150
+ * @type {{
15151
+ * "localization-strings": {
15152
+ * [key: string]: {}
15153
+ * }
15154
+ * }}
15155
+ */
15156
+ filesObj?.['localization-strings'];
14649
15157
  const workI18n = await i18n({
14650
15158
  messageStyle: 'plainNested',
14651
15159
  locales: lang,
@@ -14885,16 +15393,21 @@ const getWorkData = async function (_ref) {
14885
15393
  // import {escapeHTML} from './sanitize.js';
14886
15394
 
14887
15395
  /**
14888
- * Note that this function be kept as a polyglot client-server file.
14889
- * @param {PlainObject} target
14890
- * @param {PlainObject} source
14891
- * @returns {{
15396
+ * @typedef {{
14892
15397
  * userJSON: string,
14893
15398
  * languages: string,
14894
15399
  * serviceWorkerPath: string,
14895
15400
  * files: string,
14896
- * namespace: string
14897
- * }}
15401
+ * namespace: string,
15402
+ * stylesheets?: string[]
15403
+ * }} ServiceWorkerConfig
15404
+ */
15405
+
15406
+ /**
15407
+ * Note that this function be kept as a polyglot client-server file.
15408
+ * @param {Partial<ServiceWorkerConfig>} target
15409
+ * @param {Partial<ServiceWorkerConfig>} source
15410
+ * @returns {ServiceWorkerConfig}
14898
15411
  */
14899
15412
  const setServiceWorkerDefaults = (target, source) => {
14900
15413
  target.userJSON = source.userJSON || 'resources/user.json';
@@ -14902,13 +15415,18 @@ const setServiceWorkerDefaults = (target, source) => {
14902
15415
  target.serviceWorkerPath = source.serviceWorkerPath || `sw.js?pathToUserJSON=${encodeURIComponent(target.userJSON)}&stylesheets=${encodeURIComponent(JSON.stringify(target.stylesheets || []))}`;
14903
15416
  target.files = source.files || 'files.json';
14904
15417
  target.namespace = source.namespace || 'textbrowser';
14905
- return target;
15418
+ return /** @type {ServiceWorkerConfig} */target;
14906
15419
  };
14907
15420
 
14908
15421
  // (Unless skipped in code, will wait between install
14909
15422
  // of new and activation of new or existing if still
14910
15423
  // some tabs open)
14911
15424
 
15425
+ /**
15426
+ * @param {{
15427
+ * r: ServiceWorkerRegistration
15428
+ * }} cfg
15429
+ */
14912
15430
  const listenForWorkerUpdate = _ref => {
14913
15431
  let {
14914
15432
  r
@@ -14919,7 +15437,7 @@ const listenForWorkerUpdate = _ref => {
14919
15437
  // r.installing now available (though r.active is also,
14920
15438
  // apparently due to prior activation; but not r.waiting)
14921
15439
  console.log('update found', e);
14922
- const newWorker = r.installing;
15440
+ const newWorker = /** @type {ServiceWorker} */r.installing;
14923
15441
 
14924
15442
  // statechange won't catch this installing event as already installing
14925
15443
 
@@ -14975,6 +15493,19 @@ for offline installation.
14975
15493
  });
14976
15494
  });
14977
15495
  };
15496
+
15497
+ /**
15498
+ * @typedef {{
15499
+ * addLogEntry: (entry: {text: string}) => void,
15500
+ * }} Logger
15501
+ */
15502
+
15503
+ /**
15504
+ * @param {{
15505
+ * r: ServiceWorkerRegistration,
15506
+ * logger: Logger
15507
+ * }} cfg
15508
+ */
14978
15509
  const respondToState = async _ref2 => {
14979
15510
  let {
14980
15511
  r,
@@ -15045,20 +15576,20 @@ const respondToState = async _ref2 => {
15045
15576
  text: message + `${errorType === 'dbError' ? `Database error ${name}` : ''}; trying again...`
15046
15577
  });
15047
15578
  /*
15048
- if (errorType === 'dbError') {
15049
- logger.dbError({
15050
- type: name || errorType,
15051
- escapedErrorMessage: escapeHTML(message)
15052
- });
15053
- }
15054
- */
15579
+ if (errorType === 'dbError') {
15580
+ logger.dbError({
15581
+ type: name || errorType,
15582
+ escapedErrorMessage: escapeHTML(message)
15583
+ });
15584
+ }
15585
+ */
15055
15586
  // Todo: auto-close any dbError dialog if retrying
15056
15587
  // No longer rejecting as should auto-retry
15057
15588
  /*
15058
- const err = new Error(message);
15059
- err.type = type;
15060
- reject(err);
15061
- */
15589
+ const err = new Error(message);
15590
+ err.type = type;
15591
+ reject(err);
15592
+ */
15062
15593
  break;
15063
15594
  default:
15064
15595
  console.error('Unexpected type', type);
@@ -15109,6 +15640,13 @@ any indication it is installing.
15109
15640
 
15110
15641
  // Keep in this file as may wish to avoid using for server (while still
15111
15642
  // doing other service worker work)
15643
+
15644
+ /**
15645
+ * @param {{
15646
+ * serviceWorkerPath: string,
15647
+ * logger: Logger
15648
+ * }} cfg
15649
+ */
15112
15650
  const registerServiceWorker = async _ref4 => {
15113
15651
  let {
15114
15652
  serviceWorkerPath,
@@ -15167,6 +15705,10 @@ Please refresh the page if you wish to reattempt.
15167
15705
  });
15168
15706
  };
15169
15707
 
15708
+ /**
15709
+ * Prevent XSS attacks.
15710
+ * @param {string} s - The string to sanitize
15711
+ */
15170
15712
  const escapeHTML = s => {
15171
15713
  return !s ? '' : s.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
15172
15714
  };
@@ -16596,7 +17138,7 @@ const Templates = {
16596
17138
  // We empty rather than `replaceWith` as our Jamilih `body`
16597
17139
  // aliases expect the old instance
16598
17140
  while (body.hasChildNodes()) {
16599
- body.firstChild.remove();
17141
+ body.firstChild?.remove();
16600
17142
  }
16601
17143
  return jml('div', {
16602
17144
  id: 'main',
@@ -16605,21 +17147,27 @@ const Templates = {
16605
17147
  },
16606
17148
  permissions: {
16607
17149
  versionChange() {
16608
- $$1('#versionChange').showModal();
17150
+ /** @type {HTMLDialogElement} */
17151
+ $$1('#versionChange')?.showModal();
16609
17152
  },
17153
+ /**
17154
+ * @param {{text: string}} cfg
17155
+ */
16610
17156
  addLogEntry(_ref) {
16611
17157
  let {
16612
17158
  text
16613
17159
  } = _ref;
16614
17160
  const installationDialog = $$1('#installationLogContainer');
16615
17161
  try {
17162
+ /** @type {HTMLDialogElement} */
16616
17163
  installationDialog.showModal();
16617
- const container = $$1('#dialogContainer');
17164
+ const container = /** @type {HTMLElement} */$$1('#dialogContainer');
16618
17165
  container.hidden = false;
16619
17166
  // eslint-disable-next-line no-unused-vars -- Ok
16620
17167
  } catch (err) {
16621
17168
  // May already be open
16622
17169
  }
17170
+ /** @type {HTMLElement} */
16623
17171
  $$1('#installationLog').append(text + '\n');
16624
17172
  },
16625
17173
  exitDialogs() {
@@ -16628,6 +17176,12 @@ const Templates = {
16628
17176
  container.hidden = true;
16629
17177
  }
16630
17178
  },
17179
+ /**
17180
+ * @param {{
17181
+ * type: string,
17182
+ * escapedErrorMessage: string
17183
+ * }} cfg
17184
+ */
16631
17185
  dbError(_ref2) {
16632
17186
  let {
16633
17187
  type,
@@ -16636,26 +17190,32 @@ const Templates = {
16636
17190
  if (type) {
16637
17191
  jml('span', [type, ' ', escapedErrorMessage], $$1('#dbError'));
16638
17192
  }
17193
+ /** @type {HTMLDialogElement} */
16639
17194
  $$1('#dbError').showModal();
16640
17195
  },
17196
+ /**
17197
+ * @param {string} escapedErrorMessage
17198
+ */
16641
17199
  errorRegistering(escapedErrorMessage) {
16642
17200
  if (escapedErrorMessage) {
16643
17201
  jml('span', [escapedErrorMessage], $$1('#errorRegistering'));
16644
17202
  }
17203
+ /** @type {HTMLDialogElement} */
16645
17204
  $$1('#errorRegistering').showModal();
16646
17205
  },
16647
17206
  browserNotGrantingPersistence() {
17207
+ /** @type {HTMLDialogElement} */
16648
17208
  $$1('#browserNotGrantingPersistence').showModal();
16649
17209
  },
16650
17210
  /**
16651
- * @param {PlainObject} cfg
16652
- * @param {I18NCallback} cfg.siteI18n
16653
- * @param {() => Promise<void>} cfg.ok
16654
- * @param {() => void} cfg.refuse
16655
- * @param {() => Promise<void>} cfg.close
16656
- * @param {() => void} cfg.closeBrowserNotGranting
17211
+ * @param {object} cfg
17212
+ * @param {import('intl-dom').I18NCallback} cfg.siteI18n
17213
+ * @param {() => Promise<void>} [cfg.ok]
17214
+ * @param {() => void} [cfg.refuse]
17215
+ * @param {() => Promise<void>} [cfg.close]
17216
+ * @param {() => void} [cfg.closeBrowserNotGranting]
16657
17217
  * @returns {[
16658
- * HTMLDialogElement, HTMLDialogElement, HTMLDialogElement,
17218
+ * HTMLDialogElement, HTMLDialogElement|"", HTMLDialogElement|"",
16659
17219
  * HTMLDialogElement, HTMLDialogElement, HTMLDialogElement
16660
17220
  * ]}
16661
17221
  */
@@ -16678,8 +17238,10 @@ const Templates = {
16678
17238
  }, []]]]
16679
17239
  // ['textarea', {readonly: true, style: 'width: 80%; height: 80%;'}]
16680
17240
  ]);
17241
+
17242
+ /** @type {""|HTMLDialogElement} */
16681
17243
  let requestPermissionsDialog = '';
16682
- if (ok) {
17244
+ if (ok && refuse && close) {
16683
17245
  requestPermissionsDialog = jml('dialog', {
16684
17246
  id: 'willRequestStoragePermissions',
16685
17247
  $on: {
@@ -16700,6 +17262,8 @@ const Templates = {
16700
17262
  const errorRegisteringNotice = jml('dialog', {
16701
17263
  id: 'errorRegistering'
16702
17264
  }, [['section', [siteI18n('errorRegistering')]]]);
17265
+
17266
+ /** @type {""|HTMLDialogElement} */
16703
17267
  let browserNotGrantingPersistenceAlert = '';
16704
17268
  if (closeBrowserNotGranting) {
16705
17269
  browserNotGrantingPersistenceAlert = jml('dialog', {
@@ -16731,10 +17295,10 @@ const Templates = {
16731
17295
  * @file Note that this should be kept as a polyglot client-server file.
16732
17296
  */
16733
17297
  /**
16734
- *
16735
- * @param {string} param
16736
- * @param {boolean} skip
16737
17298
  * @this {IntlURLSearchParams}
17299
+ * @param {string} param
17300
+ * @param {boolean} [skip]
17301
+ * @throws {Error}
16738
17302
  * @returns {string}
16739
17303
  */
16740
17304
  function _prepareParam(param, skip) {
@@ -16746,42 +17310,84 @@ function _prepareParam(param, skip) {
16746
17310
  // start, end, toggle
16747
17311
  const endNums = /\d+(-\d+)?$/;
16748
17312
  const indexed = param.match(endNums);
17313
+ if (!this.l10n) {
17314
+ throw new Error('l10n is not defined');
17315
+ }
16749
17316
  if (indexed) {
16750
17317
  // Todo: We could i18nize numbers as well
16751
17318
  return this.l10n(['params', 'indexed', param.replace(endNums, '')]) + indexed[0];
16752
17319
  }
16753
- return this.l10n(['params', param]);
17320
+ return /** @type {string} */this.l10n(['params', param]);
16754
17321
  }
16755
17322
  class IntlURLSearchParams {
17323
+ /**
17324
+ * @param {object} [options]
17325
+ * @param {import('intl-dom').I18NCallback} [options.l10n]
17326
+ * @param {URLSearchParams|string} [options.params]
17327
+ */
16756
17328
  constructor() {
16757
17329
  let {
16758
17330
  l10n,
16759
17331
  params
16760
17332
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
16761
17333
  this.l10n = l10n;
17334
+ this.localizeParamNames = false;
16762
17335
  if (!params) {
16763
17336
  params = location.hash.slice(1);
16764
17337
  }
16765
17338
  if (typeof params === 'string') {
16766
17339
  params = new URLSearchParams(params);
16767
17340
  }
17341
+ /** @type {URLSearchParams} */
16768
17342
  this.params = params;
16769
17343
  }
17344
+ /**
17345
+ * @param {string} param
17346
+ * @param {boolean} [skip]
17347
+ * @returns {string|null}
17348
+ */
16770
17349
  get(param, skip) {
16771
17350
  return this.params.get(_prepareParam.call(this, param, skip));
16772
17351
  }
17352
+ /**
17353
+ * @param {string} param
17354
+ * @param {boolean} skip
17355
+ * @returns {string[]}
17356
+ */
16773
17357
  getAll(param, skip) {
16774
17358
  return this.params.getAll(_prepareParam.call(this, param, skip));
16775
17359
  }
17360
+ /**
17361
+ * @param {string} param
17362
+ * @param {boolean} skip
17363
+ * @returns {boolean}
17364
+ */
16776
17365
  has(param, skip) {
16777
17366
  return this.params.has(_prepareParam.call(this, param, skip));
16778
17367
  }
17368
+ /**
17369
+ * @param {string} param
17370
+ * @param {boolean} skip
17371
+ * @returns {void}
17372
+ */
16779
17373
  delete(param, skip) {
16780
17374
  return this.params.delete(_prepareParam.call(this, param, skip));
16781
17375
  }
17376
+ /**
17377
+ * @param {string} param
17378
+ * @param {string} value
17379
+ * @param {boolean} skip
17380
+ * @returns {void}
17381
+ */
16782
17382
  set(param, value, skip) {
16783
17383
  return this.params.set(_prepareParam.call(this, param, skip), value);
16784
17384
  }
17385
+ /**
17386
+ * @param {string} param
17387
+ * @param {string} value
17388
+ * @param {boolean} skip
17389
+ * @returns {void}
17390
+ */
16785
17391
  append(param, value, skip) {
16786
17392
  return this.params.append(_prepareParam.call(this, param, skip), value);
16787
17393
  }
@@ -16790,6 +17396,15 @@ class IntlURLSearchParams {
16790
17396
  }
16791
17397
  }
16792
17398
 
17399
+ /**
17400
+ * @param {{
17401
+ * files: string,
17402
+ * lang: string[],
17403
+ * fallbackLanguages: string[],
17404
+ * $p: import('./utils/IntlURLSearchParams.js').default,
17405
+ * followParams: (formSelector: string, cb: () => void) => void
17406
+ * }} cfg
17407
+ */
16793
17408
  async function workSelect(_ref) {
16794
17409
  let {
16795
17410
  files,
@@ -16830,7 +17445,7 @@ async function workSelect(_ref) {
16830
17445
  };
16831
17446
  }
16832
17447
  });
16833
- document.title = workI18n('browserfile-workselect');
17448
+ document.title = /** @type {string} */workI18n('browserfile-workselect');
16834
17449
  /*
16835
17450
  // Would need adapting now that not using IMF
16836
17451
  function lDirectional (key, substitutions, formats) {
@@ -16866,22 +17481,63 @@ async function workSelect(_ref) {
16866
17481
  }
16867
17482
 
16868
17483
  // Todo: Reimplement this with `formSerialize.deserialize` as possible
17484
+
17485
+
17486
+ /**
17487
+ * @param {URLSearchParams} paramsCopy
17488
+ */
16869
17489
  const replaceHash = paramsCopy => {
16870
17490
  return location.href.replace(/#.*$/, '') + '#' + paramsCopy.toString();
16871
17491
  };
16872
- const getSerializeParamsAsURL = function () {
16873
- const setter = getParamsSetter(...arguments);
16874
- return function () {
16875
- const paramsCopy = setter(...arguments);
17492
+
17493
+ /**
17494
+ * @param {{
17495
+ * l: import('intl-dom').I18NCallback,
17496
+ * lParam: (key: string) => string,
17497
+ * $p: import('./IntlURLSearchParams.js').default
17498
+ * }} args
17499
+ */
17500
+ const getSerializeParamsAsURL = function (args) {
17501
+ const setter = getParamsSetter(args);
17502
+ /**
17503
+ * @param {{
17504
+ * form: HTMLFormElement,
17505
+ * random: {checked: boolean},
17506
+ * checkboxes: HTMLInputElement[],
17507
+ * type: string,
17508
+ * fieldAliasOrNames: string[],
17509
+ * workName: string
17510
+ * }} innerArg
17511
+ */
17512
+ return function (innerArg) {
17513
+ const paramsCopy = setter(innerArg);
16876
17514
  return replaceHash(paramsCopy);
16877
17515
  };
16878
17516
  };
17517
+
17518
+ /**
17519
+ * @param {{
17520
+ * l: import('intl-dom').I18NCallback,
17521
+ * lParam: (key: string) => string,
17522
+ * $p: import('./IntlURLSearchParams.js').default
17523
+ * }} cfg
17524
+ */
16879
17525
  const getParamsSetter = function (_ref) {
16880
17526
  let {
16881
17527
  l,
16882
17528
  lParam,
16883
17529
  $p
16884
17530
  } = _ref;
17531
+ /**
17532
+ * @param {{
17533
+ * form: HTMLFormElement,
17534
+ * random: {checked: boolean},
17535
+ * checkboxes: HTMLInputElement[],
17536
+ * type: string,
17537
+ * fieldAliasOrNames: string[],
17538
+ * workName: string
17539
+ * }} cfg
17540
+ */
16885
17541
  return function (_ref2) {
16886
17542
  let {
16887
17543
  form,
@@ -16904,7 +17560,8 @@ const getParamsSetter = function (_ref) {
16904
17560
 
16905
17561
  // Follow the same style (and order) for checkboxes
16906
17562
  paramsCopy.delete(lParam('rand'));
16907
- paramsCopy.set(lParam('rand'), random.checked ? l('yes') : l('no'));
17563
+ paramsCopy.set(lParam('rand'), /** @type {string} */
17564
+ random.checked ? l('yes') : l('no'));
16908
17565
 
16909
17566
  // We want checkboxes to typically show by default, so we cannot use the
16910
17567
  // standard serialization
@@ -16913,7 +17570,8 @@ const getParamsSetter = function (_ref) {
16913
17570
  paramsCopy.delete(checkbox.name);
16914
17571
  if (checkbox.name) {
16915
17572
  // We don't want, e.g., preference controls added to URL
16916
- paramsCopy.set(checkbox.name, checkbox.checked ? l('yes') : l('no'));
17573
+ paramsCopy.set(checkbox.name, /** @type {string} */
17574
+ checkbox.checked ? l('yes') : l('no'));
16917
17575
  }
16918
17576
  });
16919
17577
 
@@ -16924,11 +17582,11 @@ const getParamsSetter = function (_ref) {
16924
17582
  function removeStartsEndsAndAnchors() {
16925
17583
  let num = 1;
16926
17584
  let num2 = 1;
16927
- while (paramsCopy.has(`${workName}-start${num}-${num2}`, true)) {
16928
- while (paramsCopy.has(`${workName}-start${num}-${num2}`, true)) {
16929
- paramsCopy.delete(`${workName}-start${num}-${num2}`, true);
16930
- paramsCopy.delete(`${workName}-end${num}-${num2}`, true);
16931
- paramsCopy.delete(`${workName}-anchor${num}-${num2}`, true);
17585
+ while (paramsCopy.has(`${workName}-start${num}-${num2}`)) {
17586
+ while (paramsCopy.has(`${workName}-start${num}-${num2}`)) {
17587
+ paramsCopy.delete(`${workName}-start${num}-${num2}`);
17588
+ paramsCopy.delete(`${workName}-end${num}-${num2}`);
17589
+ paramsCopy.delete(`${workName}-anchor${num}-${num2}`);
16932
17590
  num2++;
16933
17591
  }
16934
17592
  num2 = 1;
@@ -16947,28 +17605,28 @@ const getParamsSetter = function (_ref) {
16947
17605
  {
16948
17606
  paramsCopy.delete(lParam('rand'));
16949
17607
  let num = 1;
16950
- while (paramsCopy.has(`anchorfield${num}`, true)) {
16951
- paramsCopy.delete(`anchorfield${num}`, true);
17608
+ while (paramsCopy.has(`anchorfield${num}`)) {
17609
+ paramsCopy.delete(`anchorfield${num}`);
16952
17610
  num++;
16953
17611
  }
16954
17612
  removeStartsEndsAndAnchors();
16955
17613
  num = 1;
16956
17614
  // Delete field-specific so we can add our own
16957
- while (paramsCopy.has(`field${num}`, true)) {
16958
- paramsCopy.delete(`field${num}`, true);
16959
- paramsCopy.delete(`checked${num}`, true);
16960
- paramsCopy.delete(`interlin${num}`, true);
16961
- paramsCopy.delete(`css${num}`, true);
17615
+ while (paramsCopy.has(`field${num}`)) {
17616
+ paramsCopy.delete(`field${num}`);
17617
+ paramsCopy.delete(`checked${num}`);
17618
+ paramsCopy.delete(`interlin${num}`);
17619
+ paramsCopy.delete(`css${num}`);
16962
17620
  num++;
16963
17621
  }
16964
17622
  fieldAliasOrNames.forEach((fieldAliasOrName, i) => {
16965
- paramsCopy.set(`field${i + 1}`, fieldAliasOrName, true);
17623
+ paramsCopy.set(`field${i + 1}`, fieldAliasOrName);
16966
17624
  // Todo: Restrict by content locale?
16967
- paramsCopy.set(`checked${i + 1}`, l('yes'), true);
17625
+ paramsCopy.set(`checked${i + 1}`, /** @type {string} */l('yes'));
16968
17626
  paramsCopy.set(`interlin${i + 1}`, '');
16969
17627
  paramsCopy.set(`css${i + 1}`, '');
16970
17628
  });
16971
- paramsCopy.delete('work', true);
17629
+ paramsCopy.delete('work');
16972
17630
  }
16973
17631
  // Fallthrough
16974
17632
  case 'startEndResult':
@@ -16982,9 +17640,9 @@ const getParamsSetter = function (_ref) {
16982
17640
  // let's put random again toward the end.
16983
17641
  if (type === 'randomResult' || random.checked) {
16984
17642
  paramsCopy.delete(lParam('rand'));
16985
- paramsCopy.set(lParam('rand'), l('yes'));
17643
+ paramsCopy.set(lParam('rand'), /** @type {string} */l('yes'));
16986
17644
  }
16987
- paramsCopy.set(lParam('result'), l('yes'));
17645
+ paramsCopy.set(lParam('result'), /** @type {string} */l('yes'));
16988
17646
  break;
16989
17647
  }
16990
17648
  default:
@@ -16996,6 +17654,18 @@ const getParamsSetter = function (_ref) {
16996
17654
  };
16997
17655
  };
16998
17656
 
17657
+ /**
17658
+ * @this {import('./index.js').default}
17659
+ * @param {{
17660
+ * l: import('intl-dom').I18NCallback,
17661
+ * languageParam: string,
17662
+ * lang: string[],
17663
+ * preferredLocale: string,
17664
+ * languages: import('./utils/Languages.js').Languages,
17665
+ * fallbackLanguages: string[],
17666
+ * $p: import('./utils/IntlURLSearchParams.js').default
17667
+ * }} cfg
17668
+ */
16999
17669
  async function workDisplay(_ref) {
17000
17670
  let {
17001
17671
  l,
@@ -17187,7 +17857,7 @@ async function workDisplay(_ref) {
17187
17857
  fallbackLanguages,
17188
17858
  preferredLocale,
17189
17859
  languages,
17190
- work: $p.get('work')
17860
+ work: (/** @type {string} */$p.get('work'))
17191
17861
  });
17192
17862
  document.title = workI18n('browserfile-workdisplay', {
17193
17863
  work: fileData ? getMetaProp(lang, metadataObj, 'alias') : ''
@@ -17634,6 +18304,9 @@ Locale._BIDI_RTL_LANGS = [
17634
18304
  'zdj' // Comorian, Ngazidja
17635
18305
  ];
17636
18306
 
18307
+ /**
18308
+ * @param {string} locale
18309
+ */
17637
18310
  const getLangDir = locale => {
17638
18311
  const {
17639
18312
  direction
@@ -17847,7 +18520,7 @@ const resultsDisplayServerOrClient = async function resultsDisplayServerOrClient
17847
18520
  tr,
17848
18521
  foundState
17849
18522
  } = _ref9;
17850
- const rowIDPartsPreferred = [];
18523
+ const rowIDPartsPreferred = /** @type {string[]} */[];
17851
18524
  const rowIDParts = applicableBrowseFieldNames.map(fieldName => {
17852
18525
  const idx = localizedFieldNames.indexOf(fieldName);
17853
18526
  // This works to put alias in anchor but this includes
@@ -18082,7 +18755,7 @@ const resultsDisplayServerOrClient = async function resultsDisplayServerOrClient
18082
18755
  const p = $p.get(param, true);
18083
18756
  /**
18084
18757
  *
18085
- * @param {GenericArray|PlainObject} locale
18758
+ * @param {GenericArray|object} locale
18086
18759
  * @returns {boolean}
18087
18760
  */
18088
18761
  function reverseLocaleLookup(locale) {
@@ -18602,7 +19275,16 @@ const resultsDisplayServerOrClient = async function resultsDisplayServerOrClient
18602
19275
  };
18603
19276
 
18604
19277
  /**
18605
- *
19278
+ * @typedef {{
19279
+ * 'localization-strings': {
19280
+ * [locale: string]: {
19281
+ * [key: string]: string
19282
+ * }
19283
+ * }
19284
+ * }} SiteData
19285
+ */
19286
+ /**
19287
+ * @this {TextBrowser}
18606
19288
  * @returns {Promise<void>}
18607
19289
  */
18608
19290
  async function prepareForServiceWorker() {
@@ -18629,32 +19311,29 @@ async function prepareForServiceWorker() {
18629
19311
  } catch (err) {
18630
19312
  console.log('err', err);
18631
19313
  if (err && typeof err === 'object') {
18632
- const {
18633
- errorType
18634
- } = err;
18635
- if (errorType === 'versionChange') {
19314
+ if ('errorType' in err && err.errorType === 'versionChange') {
18636
19315
  Templates.permissions.versionChange();
18637
19316
  return;
18638
19317
  }
18639
19318
  }
18640
- Templates.permissions.errorRegistering(escapeHTML(err && err.message));
19319
+ Templates.permissions.errorRegistering(escapeHTML(/** @type {Error} */err?.message));
18641
19320
  }
18642
19321
  }
18643
19322
 
18644
19323
  /**
18645
- * @typedef {PlainObject} Langs
19324
+ * @typedef {object} Langs
18646
19325
  * @property {string} code
18647
19326
  * @property {string} direction
18648
- * @property {PlainObject} locale
19327
+ * @property {object} locale
18649
19328
  */
18650
19329
 
18651
19330
  /**
18652
- *
18653
- * @param {Langs} langs
18654
- * @param {Logger} l
19331
+ * @this {TextBrowser}
19332
+ * @param {import('../server/main.js').LanguageInfo[]} _langs
19333
+ * @param {import('intl-dom').I18NCallback} siteI18n
18655
19334
  * @returns {Promise<void>}
18656
19335
  */
18657
- async function requestPermissions(langs, l) {
19336
+ async function requestPermissions(_langs, siteI18n) {
18658
19337
  return await new Promise(resolve => {
18659
19338
  // Todo: We could run the dialog code below for every page if
18660
19339
  // `Notification.permission === 'default'` (i.e., not choice
@@ -18678,18 +19357,19 @@ async function requestPermissions(langs, l) {
18678
19357
  *
18679
19358
  * @returns {void}
18680
19359
  */
18681
- function rememberRefusal() {
19360
+ const rememberRefusal = () => {
18682
19361
  // Todo: We could go forward with worker, caching files, and
18683
19362
  // indexedDB regardless of permissions, but this way
18684
19363
  // we can continue to gauge performance differences for now
18685
19364
  localStorage.setItem(this.namespace + '-refused', 'true');
18686
- }
19365
+ };
18687
19366
  try {
18688
19367
  if (!requestPermissionsDialog.returnValue) {
18689
19368
  rememberRefusal();
18690
19369
  return;
18691
19370
  }
18692
- } catch (err) {
19371
+ } catch (error) {
19372
+ const err = /** @type {Error} */error;
18693
19373
  console.log('err', err);
18694
19374
  Templates.permissions.errorRegistering(escapeHTML(err && err.message));
18695
19375
  }
@@ -18720,19 +19400,48 @@ async function requestPermissions(langs, l) {
18720
19400
  break;
18721
19401
  }
18722
19402
  };
18723
- const [, requestPermissionsDialog, browserNotGrantingPersistenceAlert] =
19403
+ const permissionsInfo =
18724
19404
  // , errorRegisteringNotice
18725
19405
  Templates.permissions.main({
18726
- l,
19406
+ siteI18n,
18727
19407
  ok,
18728
19408
  refuse,
18729
19409
  close,
18730
19410
  closeBrowserNotGranting
18731
19411
  });
19412
+ const requestPermissionsDialog = /** @type {HTMLDialogElement} */permissionsInfo[1];
19413
+ const browserNotGrantingPersistenceAlert = /** @type {HTMLDialogElement} */
19414
+ permissionsInfo[2];
18732
19415
  requestPermissionsDialog.showModal();
18733
19416
  });
18734
19417
  }
19418
+
19419
+ /**
19420
+ * @typedef {import('./utils/ServiceWorker.js').ServiceWorkerConfig} ServiceWorkerConfig
19421
+ */
19422
+
19423
+ /**
19424
+ * @implements {ServiceWorkerConfig}
19425
+ */
18735
19426
  class TextBrowser {
19427
+ /**
19428
+ * @param {ServiceWorkerConfig & {
19429
+ * site?: string,
19430
+ * stylesheets?: string[],
19431
+ * allowPlugins?: boolean,
19432
+ * dynamicBasePath?: string,
19433
+ * trustFormatHTML?: boolean,
19434
+ * requestPersistentStorage?: boolean,
19435
+ * localizeParamNames?: boolean,
19436
+ * hideFormattingSection?: boolean,
19437
+ * preferencesPlugin?: string,
19438
+ * interlinearSeparator?: string,
19439
+ * showEmptyInterlinear?: boolean,
19440
+ * showTitleOnSingleInterlinear?: boolean,
19441
+ * noDynamic?: boolean,
19442
+ * skipIndexedDB?: boolean
19443
+ * }} options
19444
+ */
18736
19445
  constructor(options) {
18737
19446
  this.site = options.site || 'site.json';
18738
19447
  const stylesheets = options.stylesheets || ['@builtin'];
@@ -18741,6 +19450,25 @@ class TextBrowser {
18741
19450
  stylesheets.splice(builtinIndex, 1, new URL(new URL('assets/index-D_XVedS3.css', import.meta.url).href, import.meta.url).href);
18742
19451
  }
18743
19452
  this.stylesheets = stylesheets;
19453
+
19454
+ // Satisfy TS
19455
+
19456
+ /** @type {SiteData} */
19457
+ this.siteData = {
19458
+ 'localization-strings': {}
19459
+ };
19460
+ /** @type {import('../server/main.js').LanguagesData} */
19461
+ this.langData = {
19462
+ languages: [],
19463
+ 'localization-strings': {}
19464
+ };
19465
+ /** @type {string[]} */
19466
+ this.lang = [];
19467
+ this.userJSON = '';
19468
+ this.languages = '';
19469
+ this.serviceWorkerPath = '';
19470
+ this.files = '';
19471
+ this.namespace = '';
18744
19472
  setServiceWorkerDefaults(this, options);
18745
19473
  this.allowPlugins = options.allowPlugins;
18746
19474
  this.dynamicBasePath = options.dynamicBasePath;
@@ -18761,9 +19489,16 @@ class TextBrowser {
18761
19489
 
18762
19490
  // We use getJSON instead of JsonRefs as we do not need to resolve the locales here
18763
19491
  try {
18764
- const [langData, siteData] = await getJSON([this.languages, this.site]);
18765
- this.langData = langData;
18766
- this.siteData = siteData;
19492
+ const data =
19493
+ /**
19494
+ * @type {[
19495
+ * import('../server/main.js').LanguagesData,
19496
+ * SiteData
19497
+ * ]}
19498
+ */
19499
+ await getJSON([this.languages, this.site]);
19500
+ this.langData = data[0];
19501
+ this.siteData = data[1];
18767
19502
  const p = this.paramChange();
18768
19503
 
18769
19504
  // INIT/ADD EVENTS
@@ -18771,11 +19506,16 @@ class TextBrowser {
18771
19506
  // and just check `history.state`
18772
19507
  window.addEventListener('hashchange', () => this.paramChange());
18773
19508
  return p;
18774
- } catch (err) {
19509
+ } catch (error) {
19510
+ const err = /** @type {Error} */error;
18775
19511
  console.log('err', err);
18776
19512
  dialogs.alert(err);
18777
19513
  }
18778
19514
  }
19515
+
19516
+ /**
19517
+ * @param {import('./utils/WorkInfo.js').GetWorkDataOptions} opts
19518
+ */
18779
19519
  getWorkData(opts) {
18780
19520
  try {
18781
19521
  return getWorkData.call(this, {
@@ -18792,6 +19532,10 @@ class TextBrowser {
18792
19532
  // Need for directionality even if language specified (and we don't want
18793
19533
  // to require it as a param)
18794
19534
  // Todo: Use intl-locale-textinfo-polyfill (already included)
19535
+
19536
+ /**
19537
+ * @param {string} code
19538
+ */
18795
19539
  getDirectionForLanguageCode(code) {
18796
19540
  const langs = this.langData.languages;
18797
19541
  const exactMatch = langs.find(lang => {
@@ -18801,12 +19545,21 @@ class TextBrowser {
18801
19545
  return lang.code.startsWith(code + '-');
18802
19546
  });
18803
19547
  }
19548
+
19549
+ /**
19550
+ * @param {import('./utils/Metadata.js').GetFieldNameAndValueAliasesOptions} args
19551
+ */
18804
19552
  getFieldNameAndValueAliases(args) {
18805
19553
  return getFieldNameAndValueAliases({
18806
19554
  ...args,
18807
19555
  lang: this.lang
18808
19556
  });
18809
19557
  }
19558
+
19559
+ /**
19560
+ * @param {import('./utils/Metadata.js').GetBrowseFieldDataOptions} args
19561
+ * @returns {void}
19562
+ */
18810
19563
  getBrowseFieldData(args) {
18811
19564
  return getBrowseFieldData({
18812
19565
  ...args,
@@ -18821,6 +19574,10 @@ class TextBrowser {
18821
19574
  params: history.state
18822
19575
  }) : new IntlURLSearchParams(); // Uses URL hash for params
18823
19576
 
19577
+ /**
19578
+ * @param {string} formSelector
19579
+ * @param {() => void} cb
19580
+ */
18824
19581
  const followParams = (formSelector, cb) => {
18825
19582
  const form = document.querySelector(formSelector);
18826
19583
  // Record current URL along with state
@@ -18848,25 +19605,26 @@ class TextBrowser {
18848
19605
  const [preferredLocale] = lang;
18849
19606
  const direction = this.getDirectionForLanguageCode(preferredLocale);
18850
19607
  document.documentElement.lang = preferredLocale;
18851
- document.dir = direction;
19608
+ document.dir = /** @type {string} */direction;
18852
19609
  const localizationStrings = this.siteData['localization-strings'];
18853
19610
  const siteI18n = await i18n({
18854
19611
  messageStyle: 'plainNested',
18855
19612
  locales: lang,
18856
19613
  defaultLocales: fallbackLanguages,
18857
- localeStringFinder(_ref) {
19614
+ async localeStringFinder() {
18858
19615
  let {
18859
19616
  locales,
18860
19617
  defaultLocales
18861
- } = _ref;
18862
- const locale = [...locales, ...defaultLocales].find(language => {
19618
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
19619
+ const locale = [...(/** @type {string[]} */locales), ...(/** @type {string[]} */defaultLocales)].find(language => {
18863
19620
  return language in localizationStrings;
18864
19621
  });
18865
19622
  return {
18866
- locale,
19623
+ // eslint-disable-next-line object-shorthand -- TS
19624
+ locale: (/** @type {string} */locale),
18867
19625
  strings: {
18868
19626
  head: {},
18869
- body: localizationStrings[locale]
19627
+ body: localizationStrings[(/** @type {string} */locale)]
18870
19628
  }
18871
19629
  };
18872
19630
  }
@@ -18874,7 +19632,7 @@ class TextBrowser {
18874
19632
 
18875
19633
  // Even if individual pages may end up changing, we need a
18876
19634
  // title now for accessibility
18877
- document.title = siteI18n('browser-title');
19635
+ document.title = /** @type {string} */siteI18n('browser-title');
18878
19636
  const refusedIndexedDB =
18879
19637
  // User may have persistence via bookmarks, etc. but just not
18880
19638
  // want commital on notification
@@ -18971,8 +19729,8 @@ class TextBrowser {
18971
19729
  try {
18972
19730
  return respondToState({
18973
19731
  r,
18974
- langs,
18975
- languages: this.languages,
19732
+ // langs,
19733
+ // languages: this.languages,
18976
19734
  logger: Templates.permissions
18977
19735
  });
18978
19736
  } catch (err) {
@@ -19001,13 +19759,13 @@ class TextBrowser {
19001
19759
  // We don't await the fulfillment of this promise
19002
19760
  respondToStateOfWorker();
19003
19761
  listenForWorkerUpdate({
19004
- r,
19005
- logger: {
19006
- addLogEntry(s) {
19007
- // We don't put the log in the page as user using
19008
- console.log(s);
19009
- }
19010
- }
19762
+ r
19763
+ // logger: {
19764
+ // addLogEntry (s) {
19765
+ // // We don't put the log in the page as user using
19766
+ // console.log(s);
19767
+ // }
19768
+ // }
19011
19769
  });
19012
19770
  // Don't return as user may continue working until installed (though
19013
19771
  // will get message to close tab)
@@ -19032,6 +19790,12 @@ class TextBrowser {
19032
19790
  Please wait for a short while as we work to update to a new version.
19033
19791
  `);
19034
19792
  respondToStateOfWorker();
19793
+ /**
19794
+ * @type {(
19795
+ * this: ServiceWorkerContainer,
19796
+ * ev: {data: string}
19797
+ * ) => any}
19798
+ */
19035
19799
  navigator.serviceWorker.onmessage({
19036
19800
  data: 'finishActivate'
19037
19801
  });
@@ -19046,13 +19810,13 @@ class TextBrowser {
19046
19810
  // May need to pass in arguments if new service worker appears and
19047
19811
  // it needs arguments for update
19048
19812
  listenForWorkerUpdate({
19049
- r,
19050
- logger: {
19051
- addLogEntry(s) {
19052
- // We don't put the log in the page as user using
19053
- console.log(s);
19054
- }
19055
- }
19813
+ r
19814
+ // logger: {
19815
+ // addLogEntry (s) {
19816
+ // // We don't put the log in the page as user using
19817
+ // console.log(s);
19818
+ // }
19819
+ // }
19056
19820
  });
19057
19821
  break;
19058
19822
  case 'redundant':
@@ -19074,7 +19838,7 @@ class TextBrowser {
19074
19838
  // Also could use siteI18n('chooselanguage'), but assumes locale
19075
19839
  // as with page title
19076
19840
  // $p.l10n = siteI18n; // Is this in use? No `params`, so not currently
19077
- document.title = siteI18n('languages-title');
19841
+ document.title = /** @type {string} */siteI18n('languages-title');
19078
19842
  Templates.languageSelect.main({
19079
19843
  langs,
19080
19844
  languages,
@@ -19113,8 +19877,8 @@ class TextBrowser {
19113
19877
  fallbackLanguages,
19114
19878
  languageParam,
19115
19879
  $p,
19116
- languages,
19117
- preferencesPlugin: this.preferencesPlugin
19880
+ languages
19881
+ // preferencesPlugin: this.preferencesPlugin
19118
19882
  });
19119
19883
  return true;
19120
19884
  }