textbrowser 0.49.1 → 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 +14 -0
  3. package/dist/WorkInfo-es.js +262 -13
  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 +860 -134
  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 +22 -9
  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
@@ -10,6 +10,67 @@ import {
10
10
  import {Languages} from './utils/Languages.js';
11
11
  import {getWorkData} from './utils/WorkInfo.js';
12
12
 
13
+ /**
14
+ * @callback GetCanonicalID
15
+ * @param {{
16
+ * tr: (string|Integer)[]
17
+ * }} cfg
18
+ * @returns {string}
19
+ */
20
+ /**
21
+ * @callback DetermineEnd
22
+ * @param {{
23
+ * tr: (string|Integer)[]
24
+ * foundState: {
25
+ * start: boolean,
26
+ * end: boolean
27
+ * }
28
+ * }} cfg
29
+ * @returns {string|boolean}
30
+ */
31
+
32
+ /**
33
+ * @typedef {import('./utils/Plugin.js').PluginObject} Plugin
34
+ */
35
+
36
+ /**
37
+ * @typedef {{
38
+ * field?: string,
39
+ * fieldAliasOrName: string|string[]|import('../server/main.js').LocalizationStrings,
40
+ * escapeColumn: boolean,
41
+ * fieldLang: string,
42
+ * plugin?: Plugin,
43
+ * applicableField?: string,
44
+ * meta?: {[key: string]: string},
45
+ * j?: number,
46
+ * placement?: number
47
+ * metaApplicableField?: {
48
+ * [key: string]: string
49
+ * },
50
+ * onByDefault?: boolean
51
+ * }[]} FieldInfo
52
+ */
53
+
54
+ /**
55
+ * @typedef {import('./utils/Metadata.js').FieldValueAliases} FieldValueAliases
56
+ */
57
+ /**
58
+ * @typedef {any} AnyValue
59
+ */
60
+ /**
61
+ * @param {AnyValue} val
62
+ * @returns {val is null | undefined}
63
+ */
64
+ const isNullish = (val) => {
65
+ return val === null || val === undefined;
66
+ };
67
+
68
+ /**
69
+ * @typedef {number} Integer
70
+ */
71
+ /**
72
+ * @param {string} locale
73
+ */
13
74
  const getLangDir = (locale) => {
14
75
  const {direction} = new Locale(locale).textInfo;
15
76
  return direction;
@@ -17,12 +78,25 @@ const getLangDir = (locale) => {
17
78
 
18
79
  const fieldValueAliasRegex = /^.* \((.*?)\)$/;
19
80
 
81
+ /**
82
+ * @param {string} v
83
+ */
20
84
  const getRawFieldValue = (v) => {
21
85
  return typeof v === 'string'
22
86
  ? v.replace(fieldValueAliasRegex, '$1')
23
87
  : v;
24
88
  };
25
89
 
90
+ /**
91
+ * @param {{
92
+ * applicableBrowseFieldSet: import('./utils/Metadata.js').BrowseFields,
93
+ * fieldValueAliasMapPreferred: (FieldValueAliases|null|undefined)[],
94
+ * lParamRaw: (key: string, suffix?: string) => string,
95
+ * lIndexedParam: (key: string) => string,
96
+ * max: number,
97
+ * $p: import('./utils/IntlURLSearchParams.js').default
98
+ * }} cfg
99
+ */
26
100
  const setAnchor = ({
27
101
  applicableBrowseFieldSet,
28
102
  fieldValueAliasMapPreferred, lParamRaw, lIndexedParam, max, $p
@@ -40,6 +114,8 @@ const setAnchor = ({
40
114
  }
41
115
  if (!anchor) {
42
116
  const anchors = [];
117
+
118
+ /** @type {string|null} */
43
119
  let anchorField = '';
44
120
  // eslint-disable-next-line sonarjs/misplaced-loop-counter -- Ok
45
121
  for (let i = 1, breakout; !breakout && !anchors.length; i++) {
@@ -65,6 +141,9 @@ const setAnchor = ({
65
141
  }
66
142
  }
67
143
  if (anchors.length) {
144
+ /**
145
+ * @param {string} str
146
+ */
68
147
  const escapeSelectorAttValue = (str) => (str || '').replaceAll(
69
148
  /["\\]/g, String.raw`\$&`
70
149
  );
@@ -82,10 +161,17 @@ const setAnchor = ({
82
161
  }
83
162
  };
84
163
 
164
+ /**
165
+ * @this {import('./index.js').default}
166
+ * @param {Omit<ResultsDisplayServerOrClientArg, "skipIndexedDB"|"prefI18n">} args
167
+ */
85
168
  export const resultsDisplayClient = async function resultsDisplayClient (args) {
86
169
  const persistent = await navigator.storage.persisted();
87
- const skipIndexedDB = this.skipIndexedDB || !persistent || !navigator.serviceWorker.controller;
88
- const prefI18n = localStorage.getItem(this.namespace + '-localizeParamNames');
170
+ const skipIndexedDB = this.skipIndexedDB || !persistent ||
171
+ !navigator.serviceWorker.controller;
172
+ const prefI18n = /** @type {"true"|"false"|null} */ (
173
+ localStorage.getItem(this.namespace + '-localizeParamNames')
174
+ );
89
175
 
90
176
  const {
91
177
  fieldInfo, $p,
@@ -97,14 +183,14 @@ export const resultsDisplayClient = async function resultsDisplayClient (args) {
97
183
  } = await resultsDisplayServerOrClient.call(this, {
98
184
  ...args, skipIndexedDB, prefI18n
99
185
  });
100
- document.title = workI18n(
186
+ document.title = /** @type {string} */ (workI18n(
101
187
  'browserfile-resultsdisplay',
102
188
  {
103
189
  work: fileData
104
- ? getMetaProp(lang, metadataObj, 'alias')
190
+ ? /** @type {string} */ (getMetaProp(lang, metadataObj, 'alias'))
105
191
  : ''
106
192
  }
107
- );
193
+ ));
108
194
  Templates.resultsDisplayClient.main(templateArgs);
109
195
  setAnchor({
110
196
  applicableBrowseFieldSet,
@@ -123,9 +209,12 @@ export const resultsDisplayClient = async function resultsDisplayClient (args) {
123
209
  };
124
210
 
125
211
  /**
212
+ * @this {import('../server/main.js').ResultsDisplayServerContext}
126
213
  * This is server-only code, but kept here as the function is similar.
127
- * @param {{serverOutput: "jamilih"|"html"|"json"}} args
128
- * @returns {Promise<Array|string>}
214
+ * @param {ResultsDisplayServerOrClientArg & {
215
+ * serverOutput?: "jamilih"|"html"|"json"|null
216
+ * }} args
217
+ * @returns {Promise<import('jamilih').JamilihArray|string|(string | number)[][]>}
129
218
  */
130
219
  export const resultsDisplayServer = async function resultsDisplayServer (args) {
131
220
  const {
@@ -149,17 +238,61 @@ export const resultsDisplayServer = async function resultsDisplayServer (args) {
149
238
  }
150
239
  };
151
240
 
241
+ /**
242
+ * @typedef {(info: {
243
+ * tr: (string|Integer)[],
244
+ * idx: number,
245
+ * }) => {
246
+ * tdVal: string|Integer,
247
+ * htmlEscaped: boolean
248
+ * }|{
249
+ * tdVal: string|Integer,
250
+ * htmlEscaped?: undefined
251
+ * }} GetCellValue
252
+ */
253
+
254
+ /**
255
+ * @todo For `locales`, should export `LocaleObject` from intl-dom
256
+ * @typedef {{
257
+ * l: import('intl-dom').I18NCallback,
258
+ * lang: string[],
259
+ * fallbackLanguages: string[]|undefined,
260
+ * locales: {head?: any, body: any},
261
+ * $p: import('./utils/IntlURLSearchParams.js').default,
262
+ * skipIndexedDB: boolean,
263
+ * noIndexedDB?: boolean,
264
+ * prefI18n: "true"|"false"|null,
265
+ * files?: string,
266
+ * allowPlugins?: boolean,
267
+ * langData: import('../server/main.js').LanguagesData,
268
+ * basePath: string,
269
+ * dynamicBasePath?: string
270
+ * }} ResultsDisplayServerOrClientArg
271
+ */
272
+
273
+ /**
274
+ * @this {import('../server/main.js').ResultsDisplayServerContext|import('./index.js').default}
275
+ * @param {ResultsDisplayServerOrClientArg} cfg
276
+ */
152
277
  export const resultsDisplayServerOrClient = async function resultsDisplayServerOrClient ({
153
278
  l, lang, fallbackLanguages, locales, $p, skipIndexedDB, noIndexedDB, prefI18n,
154
279
  files, allowPlugins, langData, basePath = '', dynamicBasePath = ''
155
280
  }) {
156
281
  const languages = new Languages({langData});
282
+
283
+ /**
284
+ * @param {{
285
+ * fieldValueAliasMapPreferred: (FieldValueAliases|null|undefined)[],
286
+ * escapeColumnIndexes: boolean[]
287
+ * }} cfg
288
+ * @returns {GetCellValue}
289
+ */
157
290
  const getCellValue = ({
158
291
  fieldValueAliasMapPreferred, escapeColumnIndexes
159
292
  }) => ({
160
293
  tr, idx
161
294
  }) => {
162
- let tdVal = (fieldValueAliasMapPreferred[idx] !== undefined
295
+ let tdVal = (!isNullish(fieldValueAliasMapPreferred[idx])
163
296
  ? fieldValueAliasMapPreferred[idx][tr[idx]]
164
297
  : tr[idx]
165
298
  );
@@ -167,90 +300,130 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
167
300
  tdVal = Object.values(tdVal);
168
301
  }
169
302
  if (Array.isArray(tdVal)) {
170
- tdVal = tdVal.join(l('comma-space'));
303
+ tdVal = tdVal.join(/** @type {string} */ (l('comma-space')));
171
304
  }
172
305
  return ((escapeColumnIndexes[idx] || !this.trustFormatHTML) &&
173
306
  typeof tdVal === 'string')
174
307
  ? {tdVal: escapeHTML(tdVal), htmlEscaped: true}
175
308
  : {tdVal};
176
309
  };
310
+
311
+ /**
312
+ * @param {{
313
+ * fieldValueAliasMap: (FieldValueAliases|null|undefined)[],
314
+ * fieldValueAliasMapPreferred: (FieldValueAliases|null|undefined)[],
315
+ * localizedFieldNames: (string | string[]|import('../server/main.js').LocalizationStrings)[],
316
+ * canonicalBrowseFieldNames: string[]
317
+ * }} cfg
318
+ */
177
319
  const getCanonicalID = ({
178
320
  fieldValueAliasMap, fieldValueAliasMapPreferred, localizedFieldNames,
179
321
  canonicalBrowseFieldNames
180
- }) => ({
181
- tr // , foundState
182
- }) => {
183
- return canonicalBrowseFieldNames.map((fieldName) => {
184
- const idx = localizedFieldNames.indexOf(fieldName);
185
- // This works to put alias in anchor but this includes
186
- // our ending parenthetical, the alias may be harder
187
- // to remember and/or automated than original (e.g.,
188
- // for a number representing a book); we may wish to
189
- // switch this (and also for other browse field-based
190
- // items).
191
- if (
192
- fieldValueAliasMap[idx] !== undefined &&
193
- // Added this condition after imf->intl-dom conversion; concealing a
194
- // bug?
195
- fieldValueAliasMap[idx] !== null
196
- ) {
197
- return fieldValueAliasMapPreferred[idx][tr[idx]];
198
- }
199
- return tr[idx];
200
- }).join('-'); // rowID;
201
- };
322
+ }) =>
323
+ /** @type {GetCanonicalID} */
324
+ // eslint-disable-next-line @stylistic/implicit-arrow-linebreak -- Ok
325
+ ({
326
+ tr // , foundState
327
+ }) => {
328
+ return canonicalBrowseFieldNames.map((fieldName) => {
329
+ const idx = localizedFieldNames.indexOf(fieldName);
330
+ // This works to put alias in anchor but this includes
331
+ // our ending parenthetical, the alias may be harder
332
+ // to remember and/or automated than original (e.g.,
333
+ // for a number representing a book); we may wish to
334
+ // switch this (and also for other browse field-based
335
+ // items).
336
+ if (
337
+ fieldValueAliasMap[idx] !== undefined &&
338
+ // Added this condition after imf->intl-dom conversion; concealing a
339
+ // bug?
340
+ fieldValueAliasMap[idx] !== null
341
+ ) {
342
+ return /** @type {FieldValueAliases} */ (
343
+ fieldValueAliasMapPreferred[idx]
344
+ )[tr[idx]];
345
+ }
346
+ return tr[idx];
347
+ }).join('-'); // rowID;
348
+ };
349
+
350
+ /**
351
+ * @param {{
352
+ * fieldValueAliasMap: (FieldValueAliases|null|undefined)[],
353
+ * fieldValueAliasMapPreferred: (FieldValueAliases|null|undefined)[],
354
+ * localizedFieldNames: (string|string[]|import('../server/main.js').LocalizationStrings)[],
355
+ * applicableBrowseFieldNames: string[],
356
+ * startsRaw: (string|Integer)[],
357
+ * endsRaw: (string|Integer)[]
358
+ * }} cfg
359
+ */
202
360
  const determineEnd = ({
203
361
  fieldValueAliasMap, fieldValueAliasMapPreferred, localizedFieldNames,
204
362
  applicableBrowseFieldNames, startsRaw, endsRaw
205
- }) => ({
206
- tr, foundState
207
- }) => {
208
- const rowIDPartsPreferred = [];
209
- const rowIDParts = applicableBrowseFieldNames.map((fieldName) => {
210
- const idx = localizedFieldNames.indexOf(fieldName);
211
- // This works to put alias in anchor but this includes
212
- // our ending parenthetical, the alias may be harder
213
- // to remember and/or automated than original (e.g.,
214
- // for a number representing a book), and there could
215
- // be multiple aliases for a value; we may wish to
216
- // switch this (and also for other browse field-based
217
- // items).
218
- if (
219
- fieldValueAliasMap[idx] !== undefined &&
220
- // Added this condition after imf->intl-dom conversion; concealing a
221
- // bug?
222
- fieldValueAliasMap[idx] !== null
223
- ) {
224
- rowIDPartsPreferred.push(fieldValueAliasMapPreferred[idx][tr[idx]]);
225
- } else {
226
- rowIDPartsPreferred.push(tr[idx]);
227
- }
228
- return tr[idx];
229
- });
363
+ }) =>
364
+ /** @type {DetermineEnd} */
365
+ // eslint-disable-next-line @stylistic/implicit-arrow-linebreak -- Ok
366
+ ({
367
+ tr, foundState
368
+ }) => {
369
+ const rowIDPartsPreferred = /** @type {(string|Integer)[]} */ ([]);
370
+ const rowIDParts = applicableBrowseFieldNames.map((fieldName) => {
371
+ const idx = localizedFieldNames.indexOf(fieldName);
372
+ // This works to put alias in anchor but this includes
373
+ // our ending parenthetical, the alias may be harder
374
+ // to remember and/or automated than original (e.g.,
375
+ // for a number representing a book), and there could
376
+ // be multiple aliases for a value; we may wish to
377
+ // switch this (and also for other browse field-based
378
+ // items).
379
+ if (
380
+ fieldValueAliasMap[idx] !== undefined &&
381
+ // Added this condition after imf->intl-dom conversion; concealing a
382
+ // bug?
383
+ fieldValueAliasMap[idx] !== null
384
+ ) {
385
+ rowIDPartsPreferred.push(
386
+ /** @type {string|Integer} */
387
+ (fieldValueAliasMapPreferred[idx]?.[tr[idx]])
388
+ );
389
+ } else {
390
+ rowIDPartsPreferred.push(tr[idx]);
391
+ }
392
+ return tr[idx];
393
+ });
230
394
 
231
- // Todo: Use schema to determine field type and use `Number.parseInt`
232
- // on other value instead of `String` conversions
233
- if (!foundState.start) {
234
- if (startsRaw.some((part, i) => {
395
+ // Todo: Use schema to determine field type and use `Number.parseInt`
396
+ // on other value instead of `String` conversions
397
+ if (!foundState.start) {
398
+ if (startsRaw.some((part, i) => {
399
+ const rowIDPart = rowIDParts[i];
400
+ return part !== rowIDPart;
401
+ })) {
402
+ // Trigger skip of this row
403
+ return false;
404
+ }
405
+ foundState.start = true;
406
+ }
407
+ // This doesn't go in an `else` for the above in case the start is the end
408
+ if (endsRaw.every((part, i) => {
235
409
  const rowIDPart = rowIDParts[i];
236
- return part !== rowIDPart;
410
+ return part === rowIDPart;
237
411
  })) {
238
- // Trigger skip of this row
239
- return false;
412
+ foundState.end = true;
413
+ } else if (foundState.end) { // If no longer matching, trigger end of the table
414
+ return true;
240
415
  }
241
- foundState.start = true;
242
- }
243
- // This doesn't go in an `else` for the above in case the start is the end
244
- if (endsRaw.every((part, i) => {
245
- const rowIDPart = rowIDParts[i];
246
- return part === rowIDPart;
247
- })) {
248
- foundState.end = true;
249
- } else if (foundState.end) { // If no longer matching, trigger end of the table
250
- return true;
251
- }
252
- return rowIDPartsPreferred.join('-'); // rowID;
253
- };
416
+ return rowIDPartsPreferred.join('-'); // rowID;
417
+ };
418
+
419
+ /**
420
+ * @param {{
421
+ * localizedFieldNames: (
422
+ * string|string[]|import('../server/main.js').LocalizationStrings
423
+ * )[],
424
+ * }} cfg
425
+ * @returns {[string[], number[], ("" | number[] | null)[]]}
426
+ */
254
427
  const getCheckedAndInterlinearFieldInfo = ({
255
428
  localizedFieldNames
256
429
  }) => {
@@ -279,35 +452,46 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
279
452
  });
280
453
  return [checkedFields, checkedFieldIndexes, allInterlinearColIndexes];
281
454
  };
455
+
456
+ /**
457
+ * @param {{
458
+ * starts: string[],
459
+ * ends: string[],
460
+ * applicableBrowseFieldNames: string[],
461
+ * heading: string
462
+ * }} cfg
463
+ * @returns {[boolean, string|undefined]}
464
+ */
282
465
  const getCaption = ({starts, ends, applicableBrowseFieldNames, heading}) => {
283
466
  let caption;
284
467
  const hasCaption = $pRaw('caption') !== '0';
285
468
  if (hasCaption) {
286
469
  /*
287
- // Works but displays in parentheses browse fields which
288
- // may be non-applicable
289
- const buildRangePoint = (startOrEnd) => escapeHTML(
290
- browseFieldSets.reduce((txt, bfs, i) =>
291
- (txt ? txt + ' (' : '') + bfs.map((bf, j) =>
292
- (j > 0 ? l('comma-space') : '') + bf + ' ' +
293
- $pRaw(startOrEnd + (i + 1) + '-' + (j + 1))
294
- ).join('') + (txt ? ')' : ''), '')
295
- );
296
- */
297
- /*
298
- // Works but overly long
299
- const buildRangePoint = (startOrEnd) => escapeHTML(
300
- applicableBrowseFieldSet.map((bf, j) =>
470
+ // Works but displays in parentheses browse fields which
471
+ // may be non-applicable
472
+ const buildRangePoint = (startOrEnd) => escapeHTML(
473
+ browseFieldSets.reduce((txt, bfs, i) =>
474
+ (txt ? txt + ' (' : '') + bfs.map((bf, j) =>
301
475
  (j > 0 ? l('comma-space') : '') + bf + ' ' +
302
- $pRaw(startOrEnd + (browseFieldSetIdx + 1) + '-' + (j + 1))
303
- ).join('')
304
- );
305
- */
476
+ $pRaw(startOrEnd + (i + 1) + '-' + (j + 1))
477
+ ).join('') + (txt ? ')' : ''), '')
478
+ );
479
+ */
480
+ /*
481
+ // Works but overly long
482
+ const buildRangePoint = (startOrEnd) => escapeHTML(
483
+ applicableBrowseFieldSet.map((bf, j) =>
484
+ (j > 0 ? l('comma-space') : '') + bf + ' ' +
485
+ $pRaw(startOrEnd + (browseFieldSetIdx + 1) + '-' + (j + 1))
486
+ ).join('')
487
+ );
488
+ */
306
489
  const startSep = Templates.resultsDisplayServerOrClient.startSeparator({l});
307
490
  const innerBrowseFieldSeparator = Templates.resultsDisplayServerOrClient.
308
491
  innerBrowseFieldSeparator({l});
309
492
 
310
493
  const buildRanges = () => {
494
+ /** @type {string[]} */
311
495
  const endVals = [];
312
496
  const startRange = starts.reduce((str, startFieldValue, i) => {
313
497
  const ret = str + startFieldValue;
@@ -332,11 +516,20 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
332
516
  }
333
517
  return [hasCaption, caption];
334
518
  };
519
+
520
+ /**
521
+ * @param {{
522
+ * presort: boolean|undefined,
523
+ * tableData: (string|Integer)[][],
524
+ * applicableBrowseFieldNames: string[],
525
+ * localizedFieldNames: (string|string[]|import('../server/main.js').LocalizationStrings)[]
526
+ * }} cfg
527
+ */
335
528
  const runPresort = ({presort, tableData, applicableBrowseFieldNames, localizedFieldNames}) => {
336
529
  // Todo: Ought to be checking against an aliased table
337
530
  if (presort) {
338
531
  tableData.sort((rowA, rowB) => {
339
- let precedence;
532
+ let precedence = 0;
340
533
  applicableBrowseFieldNames.some((fieldName) => {
341
534
  const idx = localizedFieldNames.indexOf(fieldName);
342
535
  const rowAFirst = rowA[idx] < rowB[idx];
@@ -348,6 +541,18 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
348
541
  });
349
542
  }
350
543
  };
544
+
545
+ /**
546
+ * @param {{
547
+ * schemaItems: {title: string, type: string}[],
548
+ * fieldInfo: FieldInfo,
549
+ * metadataObj: import('./utils/Metadata.js').MetadataObj,
550
+ * getFieldAliasOrName: (
551
+ * field: string
552
+ * ) => string|string[]|import('../server/main.js').LocalizationStrings,
553
+ * usePreferAlias: boolean
554
+ * }} cfg
555
+ */
351
556
  const getFieldValueAliasMap = ({
352
557
  schemaItems, fieldInfo, metadataObj, getFieldAliasOrName, usePreferAlias
353
558
  }) => {
@@ -356,7 +561,9 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
356
561
  return undefined;
357
562
  }
358
563
  const {preferAlias, fieldValueAliasMap} = getFieldNameAndValueAliases({
359
- field, schemaItems, metadataObj, getFieldAliasOrName, lang
564
+ // eslint-disable-next-line object-shorthand -- TS
565
+ field: /** @type {string} */ (field),
566
+ schemaItems, metadataObj, getFieldAliasOrName, lang
360
567
  });
361
568
  if (!usePreferAlias) {
362
569
  return preferAlias !== false ? fieldValueAliasMap : undefined;
@@ -372,36 +579,49 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
372
579
  if (val && typeof val === 'object') {
373
580
  if (typeof preferAlias === 'string') {
374
581
  fieldValueAliasMap[key] =
375
- Templates.resultsDisplayServerOrClient.fieldValueAlias({
376
- key, value: val[preferAlias]
377
- });
582
+ Templates.resultsDisplayServerOrClient.fieldValueAlias({
583
+ key, value: val[preferAlias]
584
+ });
378
585
  } else {
379
586
  Object.entries(val).forEach(([k, value]) => {
380
- fieldValueAliasMap[key][k] =
381
- Templates.resultsDisplayServerOrClient.fieldValueAlias({
382
- key, value
383
- });
587
+ /** @type {{[key: string]: string|number}} */
588
+ (fieldValueAliasMap[key])[k] =
589
+ Templates.resultsDisplayServerOrClient.fieldValueAlias({
590
+ key, value
591
+ });
384
592
  });
385
593
  }
386
594
  return;
387
595
  }
388
596
  fieldValueAliasMap[key] =
389
- Templates.resultsDisplayServerOrClient.fieldValueAlias({key, value: val});
597
+ Templates.resultsDisplayServerOrClient.fieldValueAlias({key, value: val});
390
598
  });
391
599
  return preferAlias !== false ? fieldValueAliasMap : undefined;
392
600
  }
393
601
  return undefined;
394
602
  });
395
603
  };
604
+
605
+ /**
606
+ * @param {string} param
607
+ * @param {boolean} [avoidLog]
608
+ */
396
609
  const $pRaw = (param, avoidLog) => {
397
610
  // Todo: Should work with i18n=true (if names i18nized, need reverse look-up)
611
+
612
+ /** @type {string} */
398
613
  let key;
399
614
  const p = $p.get(param, true);
400
615
  /**
401
- *
402
- * @param {GenericArray|PlainObject} locale
403
- * @returns {boolean}
404
- */
616
+ * @typedef {{
617
+ * [key: string]: string|LocaleObj
618
+ * }} LocaleObj
619
+ */
620
+ /**
621
+ *
622
+ * @param {LocaleObj[]|LocaleObj} locale
623
+ * @returns {boolean}
624
+ */
405
625
  function reverseLocaleLookup (locale) {
406
626
  if (Array.isArray(locale)) {
407
627
  return locale.some(reverseLocaleLookup);
@@ -419,17 +639,33 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
419
639
  });
420
640
  }
421
641
  reverseLocaleLookup(locales);
642
+ // @ts-expect-error TS defect
422
643
  if (!key && !avoidLog) {
423
644
  console.log('Bad param/value', param, '::', p);
424
645
  }
646
+ // @ts-expect-error TS defect
425
647
  return key; // || p; // $p.get(param, true);
426
648
  };
427
649
 
428
650
  const escapeCSS = escapeHTML;
651
+
652
+ /**
653
+ * @param {string} param
654
+ */
429
655
  const $pRawEsc = (param) => escapeHTML($pRaw(param));
430
- const $pEscArbitrary = (param) => escapeHTML($p.get(param, true));
656
+ /**
657
+ * @param {string} param
658
+ */
659
+ const $pEscArbitrary = (param) => escapeHTML(
660
+ /** @type {string} */
661
+ ($p.get(param, true))
662
+ );
431
663
 
432
664
  // Not currently in use
665
+
666
+ /**
667
+ * @param {string} s
668
+ */
433
669
  const escapeQuotedCSS = (s) => s.replaceAll('\\', '\\\\').replaceAll(
434
670
  '"', String.raw`\"`
435
671
  );
@@ -437,6 +673,7 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
437
673
  const {
438
674
  fileData, workI18n, getFieldAliasOrName, schemaObj, metadataObj,
439
675
  pluginsForWork
676
+ // @ts-expect-error Not using `this` given no `languages` arg is passed
440
677
  } = await getWorkData({
441
678
  files: files || this.files,
442
679
  allowPlugins: typeof allowPlugins === 'boolean' ? allowPlugins : this.allowPlugins,
@@ -446,11 +683,15 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
446
683
  });
447
684
  console.log('pluginsForWork', pluginsForWork);
448
685
 
449
- const heading = getMetaProp(lang, metadataObj, 'heading');
686
+ const heading = /** @type {string} */ (getMetaProp(lang, metadataObj, 'heading'));
450
687
  const schemaItems = schemaObj.items.items;
451
688
 
689
+ /** @type {string[]} */
452
690
  const setNames = [];
691
+ /** @type {(boolean|undefined)[]} */
453
692
  const presorts = [];
693
+
694
+ /** @type {import('./utils/Metadata.js').BrowseFields[]} */
454
695
  const browseFieldSets = [];
455
696
  getBrowseFieldData({
456
697
  metadataObj, schemaItems, getFieldAliasOrName, lang,
@@ -461,6 +702,7 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
461
702
  }
462
703
  });
463
704
 
705
+ /** @type {FieldInfo} */
464
706
  const fieldInfo = schemaItems.map(({title: field, format}) => {
465
707
  return {
466
708
  field,
@@ -484,12 +726,26 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
484
726
  placement = placement === 'end'
485
727
  ? Number.POSITIVE_INFINITY // push
486
728
  : placement;
729
+
730
+ /**
731
+ * @param {{
732
+ * applicableField?: string,
733
+ * targetLanguage?: string,
734
+ * onByDefault?: boolean,
735
+ * metaApplicableField?: {
736
+ * [key: string]: string
737
+ * },
738
+ * }} [cfg]
739
+ */
487
740
  const processField = ({applicableField, targetLanguage, onByDefault, metaApplicableField} = {}) => {
488
741
  const plugin = pluginsForWork.getPluginObject(pluginName) || {};
489
- const applicableFieldLang = metadata.getFieldLang(applicableField);
742
+ const applicableFieldLang = metadata.getFieldLang(
743
+ /** @type {string} */ (applicableField)
744
+ );
490
745
  if (plugin.getTargetLanguage) {
491
746
  targetLanguage = plugin.getTargetLanguage({
492
- applicableField,
747
+ // eslint-disable-next-line object-shorthand -- TS
748
+ applicableField: /** @type {string} */ (applicableField),
493
749
  targetLanguage,
494
750
  // Default lang for plug-in (from files.json)
495
751
  pluginLang,
@@ -502,27 +758,47 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
502
758
  if (targetLanguage === '{locale}') {
503
759
  targetLanguage = preferredLocale;
504
760
  }
505
- const applicableFieldI18N = getMetaProp(lang, metadataObj, ['fieldnames', applicableField]);
761
+ const applicableFieldI18N = getMetaProp(
762
+ lang,
763
+ metadataObj,
764
+ [
765
+ 'fieldnames',
766
+ /** @type {string} */
767
+ (applicableField)
768
+ ]
769
+ );
506
770
  const fieldAliasOrName = plugin.getFieldAliasOrName
507
771
  ? plugin.getFieldAliasOrName({
508
772
  locales: lang,
509
773
  workI18n,
510
- targetLanguage,
511
- applicableField,
774
+ // eslint-disable-next-line object-shorthand -- TS
775
+ targetLanguage: /** @type {string} */ (targetLanguage),
776
+ // eslint-disable-next-line object-shorthand -- TS
777
+ applicableField: /** @type {string} */ (applicableField),
512
778
  applicableFieldI18N,
513
779
  meta,
514
- metaApplicableField,
515
- targetLanguageI18N: languages.getLanguageFromCode(targetLanguage)
780
+ // eslint-disable-next-line object-shorthand -- TS
781
+ metaApplicableField: /** @type {{[key: string]: string }} */ (
782
+ metaApplicableField
783
+ ),
784
+ targetLanguageI18N: languages.getLanguageFromCode(
785
+ /** @type {string} */ (targetLanguage)
786
+ )
516
787
  })
517
788
  : languages.getFieldNameFromPluginNameAndLocales({
518
789
  pluginName,
519
- locales: lang,
790
+ // locales: lang,
520
791
  workI18n,
521
- targetLanguage,
522
- applicableFieldI18N,
792
+ // eslint-disable-next-line object-shorthand -- TS
793
+ targetLanguage: /** @type {string} */ (targetLanguage),
794
+ // eslint-disable-next-line object-shorthand -- TS
795
+ applicableFieldI18N: /** @type {string|string[]} */ (applicableFieldI18N),
523
796
  // Todo: Should have formal way to i18nize meta
524
797
  meta,
525
- metaApplicableField
798
+ // eslint-disable-next-line object-shorthand -- TS
799
+ metaApplicableField: /** @type {{[key: string]: string }} */ (
800
+ metaApplicableField
801
+ )
526
802
  });
527
803
  fieldInfo.splice(
528
804
  // Todo: Allow default placement overriding for
@@ -546,7 +822,7 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
546
822
  // not need here)
547
823
  applicableField,
548
824
  metaApplicableField,
549
- fieldLang: targetLanguage
825
+ fieldLang: /** @type {string} */ (targetLanguage)
550
826
  }
551
827
  );
552
828
  };
@@ -576,21 +852,81 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
576
852
  prefI18n !== 'false' && this.localizeParamNames
577
853
  );
578
854
  const lParam = localizeParamNames
579
- ? (key) => l(['params', key])
580
- : (key) => key;
855
+ // eslint-disable-next-line @stylistic/operator-linebreak -- Ok
856
+ ?
857
+ /**
858
+ * @param {string} key
859
+ * @returns {string}
860
+ */
861
+ (key) => /** @type {string} */ (l(['params', key]))
862
+ // eslint-disable-next-line @stylistic/operator-linebreak -- Ok
863
+ :
864
+ /**
865
+ * @param {string} key
866
+ * @returns {string}
867
+ */
868
+ (key) => key;
581
869
  const lIndexedParam = localizeParamNames
582
- ? (key) => l(['params', 'indexed', key])
583
- : (key) => key;
870
+ // eslint-disable-next-line @stylistic/operator-linebreak -- Ok
871
+ ?
872
+ /**
873
+ * @param {string} key
874
+ * @returns {string}
875
+ */
876
+ (key) => /** @type {string} */ (l(['params', 'indexed', key]))
877
+ // eslint-disable-next-line @stylistic/operator-linebreak -- Ok
878
+ :
879
+ /**
880
+ * @param {string} key
881
+ * @returns {string}
882
+ */
883
+ (key) => key;
584
884
  const lParamRaw = localizeParamNames
585
- ? (key, suffix = '') => $p.get(lParam(key) + suffix, true)
586
- : (key, suffix = '') => $p.get(key + suffix, true);
885
+ // eslint-disable-next-line @stylistic/operator-linebreak -- Ok
886
+ ?
887
+ /**
888
+ * @param {string} key
889
+ * @param {string} [suffix]
890
+ * @returns {string}
891
+ */
892
+ (key, suffix = '') => /** @type {string} */ (
893
+ $p.get(lParam(key) + suffix, true)
894
+ )
895
+ // eslint-disable-next-line @stylistic/operator-linebreak -- Ok
896
+ :
897
+ /**
898
+ * @param {string} key
899
+ * @param {string} [suffix]
900
+ * @returns {string}
901
+ */
902
+ (key, suffix = '') => /** @type {string} */ (
903
+ $p.get(key + suffix, true)
904
+ );
587
905
  const lIndexedParamRaw = localizeParamNames
588
- ? (key, suffix = '') => $p.get($p.get('work') + '-' + lIndexedParam(key) + suffix, true)
589
- : (key, suffix = '') => $p.get($p.get('work') + '-' + key + suffix, true);
906
+ // eslint-disable-next-line @stylistic/operator-linebreak -- Ok
907
+ ?
908
+ /**
909
+ * @param {string} key
910
+ * @param {string} [suffix]
911
+ * @returns {string}
912
+ */
913
+ (key, suffix = '') => /** @type {string} */ (
914
+ $p.get($p.get('work') + '-' + lIndexedParam(key) + suffix, true)
915
+ )
916
+ // eslint-disable-next-line @stylistic/operator-linebreak -- Ok
917
+ :
918
+ /**
919
+ * @param {string} key
920
+ * @param {string} [suffix]
921
+ * @returns {string}
922
+ */
923
+ (key, suffix = '') => /** @type {string} */ (
924
+ $p.get($p.get('work') + '-' + key + suffix, true)
925
+ );
590
926
 
591
927
  // Now that we know `browseFieldSets`, we can parse `startEnd`
592
928
  const browseFieldSetStartEndIdx = browseFieldSets.findIndex((item, i) => {
593
- return lIndexedParamRaw('startEnd', (i + 1));
929
+ return lIndexedParamRaw('startEnd', String(i + 1));
594
930
  });
595
931
  if (browseFieldSetStartEndIdx !== -1) {
596
932
  // Todo: i18nize (by work and/or by whole app?)
@@ -603,7 +939,7 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
603
939
  // Todo: Change query beginning at 0 to 1 if none present?
604
940
  // Todo: Support i18nized or canonical aliases (but don't
605
941
  // over-trim in such cases)
606
- const rawSearch = (lIndexedParamRaw('startEnd', browseFieldSetStartEndIdx + 1) || '').trim();
942
+ const rawSearch = (lIndexedParamRaw('startEnd', String(browseFieldSetStartEndIdx + 1)) || '').trim();
607
943
  const [startFull, endFull] = rawSearch.split(rangeSep);
608
944
  if (endFull !== undefined) {
609
945
  const startPartVals = startFull.split(partSep);
@@ -642,12 +978,16 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
642
978
  });
643
979
 
644
980
  const fieldSchemaTypes = applicableBrowseFieldSet.map((abfs) => abfs.fieldSchema.type);
981
+
982
+ /**
983
+ * @param {"start"|"end"} startOrEnd
984
+ */
645
985
  const buildRangePoint = (startOrEnd) => {
646
986
  return applicableBrowseFieldNames.map((bfn, j) => {
647
- return $p.get(
987
+ return /** @type {string} */ ($p.get(
648
988
  $p.get('work') + '-' + startOrEnd + (browseFieldSetIdx + 1) + '-' + (j + 1),
649
989
  true
650
- );
990
+ ));
651
991
  });
652
992
  };
653
993
  const starts = buildRangePoint('start');
@@ -660,6 +1000,11 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
660
1000
 
661
1001
  console.log('rand', lParamRaw('rand') === 'yes');
662
1002
 
1003
+ /**
1004
+ * @param {string} v
1005
+ * @param {Integer} i
1006
+ * @returns {Integer|string}
1007
+ */
663
1008
  const stripToRawFieldValue = (v, i) => {
664
1009
  let val;
665
1010
  if ((/^\d+$/).test(v) || fieldValueAliasRegex.test(v)) {
@@ -672,7 +1017,7 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
672
1017
  const fvEntries = Object.entries(rawFieldValueAliasMap);
673
1018
  if (Array.isArray(fvEntries[0][1])) {
674
1019
  fvEntries.some(([key, arr]) => {
675
- if (arr.includes(v)) {
1020
+ if (/** @type {(string | number)[]} */ (arr).includes(v)) {
676
1021
  dealiased = key;
677
1022
  return true;
678
1023
  }
@@ -699,7 +1044,9 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
699
1044
  const startsRaw = starts.map(stripToRawFieldValue);
700
1045
  const endsRaw = ends.map(stripToRawFieldValue);
701
1046
 
702
- let tableData, usingServerData = false;
1047
+ /** @type {(string|Integer)[][]} */
1048
+ let tableData;
1049
+ let usingServerData = false;
703
1050
  // Site owner may have configured to skip (e.g., testing)
704
1051
  if (!skipIndexedDB &&
705
1052
  // User may have refused, not yet agreed, or are visiting the
@@ -713,7 +1060,8 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
713
1060
  // Todo: Fetch the work in code based on the non-localized `datafileName`
714
1061
  const dbName = this.namespace + '-textbrowser-cache-data';
715
1062
  const req = indexedDB.open(dbName);
716
- req.onsuccess = ({target: {result: db}}) => {
1063
+ req.onsuccess = (e) => {
1064
+ const db = /** @type {EventTarget & {result: IDBDatabase}} */ (e.target).result;
717
1065
  const storeName = 'files-to-cache-' + unlocalizedWorkName;
718
1066
  const trans = db.transaction(storeName);
719
1067
  const store = trans.objectStore(storeName);
@@ -727,10 +1075,22 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
727
1075
  // console.log('applicableBrowseFieldSetName', 'browseFields-' + applicableBrowseFieldSetName);
728
1076
 
729
1077
  const r = index.getAll(IDBKeyRange.bound(startsRaw, endsRaw));
730
- r.onsuccess = ({target: {result}}) => {
731
- const converted = result.map((r) => r.value);
732
- resolve(converted);
733
- };
1078
+ r.addEventListener(
1079
+ 'success',
1080
+ /**
1081
+ * @param {Event} e
1082
+ * @returns {void}
1083
+ */
1084
+ (e) => {
1085
+ // eslint-disable-next-line prefer-destructuring -- TS
1086
+ const result =
1087
+ /** @type {EventTarget & {result: {value: (string|Integer)[]}[]}} */ (
1088
+ e.target
1089
+ ).result;
1090
+ const converted = result.map((r) => r.value);
1091
+ resolve(converted);
1092
+ }
1093
+ );
734
1094
  };
735
1095
  });
736
1096
  } else {
@@ -742,18 +1102,19 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
742
1102
  // needed
743
1103
  // if (presort || this.noDynamic) {
744
1104
  if (this.noDynamic) {
745
- ({
746
- resolved: {data: tableData}
747
- } = await JsonRefs.resolveRefs(fileData.file));
1105
+ const {
1106
+ resolved
1107
+ } = await JsonRefs.resolveRefs(fileData.file);
1108
+ (tableData = /** @type {{data: (string|Integer)[][]}} */ (resolved).data);
748
1109
  runPresort({presort, tableData, applicableBrowseFieldNames, localizedFieldNames});
749
1110
  } else {
750
1111
  /*
751
- const jsonURL = Object.entries({
752
- prefI18n, unlocalizedWorkName, startsRaw, endsRaw
753
- }).reduce((url, [arg, argVal]) => {
754
- return url + '&' + arg + '=' + encodeURIComponent((argVal));
755
- }, `${dynamicBasePath}textbrowser?`);
756
- */
1112
+ const jsonURL = Object.entries({
1113
+ prefI18n, unlocalizedWorkName, startsRaw, endsRaw
1114
+ }).reduce((url, [arg, argVal]) => {
1115
+ return url + '&' + arg + '=' + encodeURIComponent((argVal));
1116
+ }, `${dynamicBasePath}textbrowser?`);
1117
+ */
757
1118
  const jsonURL = `${dynamicBasePath}textbrowser?${$p.toString()}`;
758
1119
  tableData = await (await fetch(jsonURL)).json();
759
1120
  usingServerData = true;
@@ -767,8 +1128,9 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
767
1128
  tableData.forEach((tr) => {
768
1129
  // Todo: We should pass on other arguments (like `meta` but on `applicableFields`)
769
1130
  tr.splice(
770
- placement,
1131
+ placement ?? 0,
771
1132
  0,
1133
+ // @ts-expect-error Only used for `plugin` type?
772
1134
  null // `${i}-${j}`);
773
1135
  );
774
1136
  });
@@ -808,6 +1170,8 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
808
1170
  escapeQuotedCSS, escapeCSS, escapeHTML,
809
1171
  l, localizedFieldNames, fieldLangs, fieldDirs,
810
1172
  caption, hasCaption, showInterlinTitles,
1173
+ showEmptyInterlinear: this.showEmptyInterlinear,
1174
+ showTitleOnSingleInterlinear: this.showTitleOnSingleInterlinear,
811
1175
  determineEnd: determineEnd({
812
1176
  applicableBrowseFieldNames,
813
1177
  fieldValueAliasMap, fieldValueAliasMapPreferred,
@@ -821,7 +1185,8 @@ export const resultsDisplayServerOrClient = async function resultsDisplayServerO
821
1185
  localizedFieldNames
822
1186
  }),
823
1187
  getCellValue: getCellValue({
824
- fieldValueAliasMapPreferred, escapeColumnIndexes, escapeHTML
1188
+ fieldValueAliasMapPreferred, escapeColumnIndexes
1189
+ // escapeHTML
825
1190
  }),
826
1191
  checkedAndInterlinearFieldInfo: getCheckedAndInterlinearFieldInfo({
827
1192
  localizedFieldNames