textbrowser 0.54.5 → 0.54.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.md +8 -0
- package/dist/eslint.config.d.ts +3 -0
- package/dist/eslint.config.d.ts.map +1 -0
- package/dist/index-es.js +10 -4
- package/dist/index-es.min.js +1 -1
- package/dist/resources/activateCallback.d.ts +23 -0
- package/dist/resources/activateCallback.d.ts.map +1 -0
- package/dist/resources/index.d.ts +128 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/resultsDisplay.d.ts +110 -0
- package/dist/resources/resultsDisplay.d.ts.map +1 -0
- package/dist/resources/templates/index.d.ts +59 -0
- package/dist/resources/templates/index.d.ts.map +1 -0
- package/dist/resources/templates/languageSelect.d.ts +18 -0
- package/dist/resources/templates/languageSelect.d.ts.map +1 -0
- package/dist/resources/templates/resultsDisplayClient.d.ts +26 -0
- package/dist/resources/templates/resultsDisplayClient.d.ts.map +1 -0
- package/dist/resources/templates/resultsDisplayServerOrClient.d.ts +131 -0
- package/dist/resources/templates/resultsDisplayServerOrClient.d.ts.map +1 -0
- package/dist/resources/templates/utils/dom.d.ts +15 -0
- package/dist/resources/templates/utils/dom.d.ts.map +1 -0
- package/dist/resources/templates/utils/html.d.ts +3 -0
- package/dist/resources/templates/utils/html.d.ts.map +1 -0
- package/dist/resources/templates/workDisplay.d.ts +183 -0
- package/dist/resources/templates/workDisplay.d.ts.map +1 -0
- package/dist/resources/templates/workSelect.d.ts +18 -0
- package/dist/resources/templates/workSelect.d.ts.map +1 -0
- package/dist/resources/utils/IntlURLSearchParams.d.ts +56 -0
- package/dist/resources/utils/IntlURLSearchParams.d.ts.map +1 -0
- package/dist/resources/utils/Languages.d.ts +81 -0
- package/dist/resources/utils/Languages.d.ts.map +1 -0
- package/dist/resources/utils/Metadata.d.ts +133 -0
- package/dist/resources/utils/Metadata.d.ts.map +1 -0
- package/dist/resources/utils/Params.d.ts +30 -0
- package/dist/resources/utils/Params.d.ts.map +1 -0
- package/dist/resources/utils/Plugin.d.ts +273 -0
- package/dist/resources/utils/Plugin.d.ts.map +1 -0
- package/dist/resources/utils/ServiceWorker.d.ts +26 -0
- package/dist/resources/utils/ServiceWorker.d.ts.map +1 -0
- package/dist/resources/utils/WorkInfo.d.ts +106 -0
- package/dist/resources/utils/WorkInfo.d.ts.map +1 -0
- package/dist/resources/utils/dialogs.d.ts +155 -0
- package/dist/resources/utils/dialogs.d.ts.map +1 -0
- package/dist/resources/utils/getLocaleFallbackResults.d.ts +19 -0
- package/dist/resources/utils/getLocaleFallbackResults.d.ts.map +1 -0
- package/dist/resources/utils/sanitize.d.ts +6 -0
- package/dist/resources/utils/sanitize.d.ts.map +1 -0
- package/dist/resources/workDisplay.d.ts +81 -0
- package/dist/resources/workDisplay.d.ts.map +1 -0
- package/dist/resources/workSelect.d.ts +17 -0
- package/dist/resources/workSelect.d.ts.map +1 -0
- package/dist/rollup.config.d.ts +19 -0
- package/dist/rollup.config.d.ts.map +1 -0
- package/dist/server/main.d.ts +47 -0
- package/dist/server/main.d.ts.map +1 -0
- package/dist/sw-helper.js +355 -0
- package/package.json +1 -1
- package/resources/index.js +8 -4
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {() => Promise<{
|
|
3
|
+
* groupName: string | Text | DocumentFragment,
|
|
4
|
+
* worksToFields: {
|
|
5
|
+
* workName: string | Text | DocumentFragment,
|
|
6
|
+
* shortcut: string,
|
|
7
|
+
* fieldAliasOrNames: (
|
|
8
|
+
* string|string[]|import('../server/main.js').LocalizationStrings
|
|
9
|
+
* )[]|undefined
|
|
10
|
+
* }[]
|
|
11
|
+
* }[]>} GetFieldAliasOrNames
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {(innerArg: {
|
|
15
|
+
* form: HTMLFormElement,
|
|
16
|
+
* random: {
|
|
17
|
+
* checked: boolean
|
|
18
|
+
* },
|
|
19
|
+
* checkboxes: HTMLInputElement[],
|
|
20
|
+
* type: string,
|
|
21
|
+
* fieldAliasOrNames?: string[],
|
|
22
|
+
* workName?: string,
|
|
23
|
+
* }) => string} SerializeParamsAsURL
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {(
|
|
27
|
+
* key: string|string[],
|
|
28
|
+
* substitutions?: Record<string, string>
|
|
29
|
+
* ) => string|Text|DocumentFragment} LDirectional
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* @typedef {(
|
|
33
|
+
* key: string,
|
|
34
|
+
* tag: string,
|
|
35
|
+
* attr: string,
|
|
36
|
+
* atts: import('jamilih').JamilihAttributes,
|
|
37
|
+
* children?: import('jamilih').JamilihChildren
|
|
38
|
+
* ) => import('jamilih').JamilihArray} LElement
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* @this {import('./index.js').default}
|
|
42
|
+
* @param {{
|
|
43
|
+
* l: import('intl-dom').I18NCallback,
|
|
44
|
+
* languageParam: string,
|
|
45
|
+
* lang: string[],
|
|
46
|
+
* preferredLocale: string,
|
|
47
|
+
* languages: import('./utils/Languages.js').Languages,
|
|
48
|
+
* fallbackLanguages: string[],
|
|
49
|
+
* $p: import('./utils/IntlURLSearchParams.js').default
|
|
50
|
+
* }} cfg
|
|
51
|
+
*/
|
|
52
|
+
export default function workDisplay(this: import("./index.js").default, { l, languageParam, lang, preferredLocale, languages, fallbackLanguages, $p }: {
|
|
53
|
+
l: import("intl-dom").I18NCallback;
|
|
54
|
+
languageParam: string;
|
|
55
|
+
lang: string[];
|
|
56
|
+
preferredLocale: string;
|
|
57
|
+
languages: import("./utils/Languages.js").Languages;
|
|
58
|
+
fallbackLanguages: string[];
|
|
59
|
+
$p: import("./utils/IntlURLSearchParams.js").default;
|
|
60
|
+
}): Promise<void>;
|
|
61
|
+
export type GetFieldAliasOrNames = () => Promise<{
|
|
62
|
+
groupName: string | Text | DocumentFragment;
|
|
63
|
+
worksToFields: {
|
|
64
|
+
workName: string | Text | DocumentFragment;
|
|
65
|
+
shortcut: string;
|
|
66
|
+
fieldAliasOrNames: (string | string[] | import("../server/main.js").LocalizationStrings)[] | undefined;
|
|
67
|
+
}[];
|
|
68
|
+
}[]>;
|
|
69
|
+
export type SerializeParamsAsURL = (innerArg: {
|
|
70
|
+
form: HTMLFormElement;
|
|
71
|
+
random: {
|
|
72
|
+
checked: boolean;
|
|
73
|
+
};
|
|
74
|
+
checkboxes: HTMLInputElement[];
|
|
75
|
+
type: string;
|
|
76
|
+
fieldAliasOrNames?: string[];
|
|
77
|
+
workName?: string;
|
|
78
|
+
}) => string;
|
|
79
|
+
export type LDirectional = (key: string | string[], substitutions?: Record<string, string>) => string | Text | DocumentFragment;
|
|
80
|
+
export type LElement = (key: string, tag: string, attr: string, atts: import("jamilih").JamilihAttributes, children?: import("jamilih").JamilihChildren) => import("jamilih").JamilihArray;
|
|
81
|
+
//# sourceMappingURL=workDisplay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workDisplay.d.ts","sourceRoot":"","sources":["../../resources/workDisplay.js"],"names":[],"mappings":"AAQA;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;GAWG;AAEH;;;;;GAKG;AAEH;;;;;;;;GAQG;AAEH;;;;;;;;;;;GAWG;AACH,uJAVW;IACN,CAAC,EAAE,OAAO,UAAU,EAAE,YAAY,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,OAAO,sBAAsB,EAAE,SAAS,CAAC;IACpD,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,EAAE,EAAE,OAAO,gCAAgC,EAAE,OAAO,CAAA;CACrD,iBAwOH;mCA5RY,MAAM,OAAO,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,gBAAgB,CAAC;IAC5C,aAAa,EAAE;QACb,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,gBAAgB,CAAC;QAC3C,QAAQ,EAAE,MAAM,CAAC;QACjB,iBAAiB,EAAE,CACzB,MAAc,GAAC,MAAM,EAAE,GAAC,OAAO,mBAAmB,EAAE,mBAAmB,CAChE,EAAE,GAAC,SAAS,CAAA;KACd,EAAE,CAAA;CACJ,EAAE,CAAC;mCAIM,CAAC,QAAQ,EAAE;IACnB,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE;QACN,OAAO,EAAE,OAAO,CAAA;KACjB,CAAC;IACF,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,KAAK,MAAM;2BAIF,CACR,GAAG,EAAE,MAAM,GAAC,MAAM,EAAE,EACpB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACnC,MAAM,GAAC,IAAI,GAAC,gBAAgB;uBAIvB,CACR,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,SAAS,EAAE,iBAAiB,EACzC,QAAQ,CAAC,EAAE,OAAO,SAAS,EAAE,eAAe,KACzC,OAAO,SAAS,EAAE,YAAY"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {{
|
|
3
|
+
* files: string,
|
|
4
|
+
* lang: string[],
|
|
5
|
+
* fallbackLanguages: string[],
|
|
6
|
+
* $p: import('./utils/IntlURLSearchParams.js').default,
|
|
7
|
+
* followParams: (formSelector: string, cb: () => void) => void
|
|
8
|
+
* }} cfg
|
|
9
|
+
*/
|
|
10
|
+
export default function workSelect({ files, lang, fallbackLanguages, $p, followParams }: {
|
|
11
|
+
files: string;
|
|
12
|
+
lang: string[];
|
|
13
|
+
fallbackLanguages: string[];
|
|
14
|
+
$p: import("./utils/IntlURLSearchParams.js").default;
|
|
15
|
+
followParams: (formSelector: string, cb: () => void) => void;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
//# sourceMappingURL=workSelect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workSelect.d.ts","sourceRoot":"","sources":["../../resources/workSelect.js"],"names":[],"mappings":"AAOA;;;;;;;;GAQG;AACH,yFARW;IACN,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,EAAE,EAAE,OAAO,gCAAgC,EAAE,OAAO,CAAC;IACrD,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,CAAA;CAC7D,iBAiFH"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
declare const _default: (import("rollup").RollupOptions | {
|
|
2
|
+
input: string;
|
|
3
|
+
output: {
|
|
4
|
+
format: string;
|
|
5
|
+
file: string;
|
|
6
|
+
name: string;
|
|
7
|
+
};
|
|
8
|
+
plugins: any[];
|
|
9
|
+
} | {
|
|
10
|
+
input: string;
|
|
11
|
+
output: {
|
|
12
|
+
format: string;
|
|
13
|
+
file: string;
|
|
14
|
+
name: string;
|
|
15
|
+
};
|
|
16
|
+
plugins?: undefined;
|
|
17
|
+
})[];
|
|
18
|
+
export default _default;
|
|
19
|
+
//# sourceMappingURL=rollup.config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rollup.config.d.ts","sourceRoot":"","sources":["../rollup.config.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export type UserOptions = {
|
|
3
|
+
nodeActivate: boolean;
|
|
4
|
+
port: number;
|
|
5
|
+
domain: string;
|
|
6
|
+
basePath: string;
|
|
7
|
+
interlinearSeparator: string;
|
|
8
|
+
localizeParamNames: boolean;
|
|
9
|
+
trustFormatHTML: boolean;
|
|
10
|
+
allowPlugins: boolean;
|
|
11
|
+
showEmptyInterlinear: boolean;
|
|
12
|
+
showTitleOnSingleInterlinear: boolean;
|
|
13
|
+
serviceWorkerPath: string;
|
|
14
|
+
userJSON: string;
|
|
15
|
+
languages: string;
|
|
16
|
+
files: string;
|
|
17
|
+
namespace: string;
|
|
18
|
+
httpServer: string;
|
|
19
|
+
expressServer: string;
|
|
20
|
+
};
|
|
21
|
+
export type AnyValue = any;
|
|
22
|
+
export type ResultsDisplayServerContext = import("../resources/utils/ServiceWorker.js").ServiceWorkerConfig & UserOptions & {
|
|
23
|
+
lang: string[];
|
|
24
|
+
langs: LanguageInfo[];
|
|
25
|
+
fallbackLanguages: string[];
|
|
26
|
+
log: (...args: AnyValue[]) => void;
|
|
27
|
+
nodeActivate?: boolean;
|
|
28
|
+
port?: number;
|
|
29
|
+
skipIndexedDB: false;
|
|
30
|
+
noDynamic: false;
|
|
31
|
+
};
|
|
32
|
+
export type LanguageInfo = {
|
|
33
|
+
code: string;
|
|
34
|
+
direction: "ltr" | "rtl";
|
|
35
|
+
locale: {
|
|
36
|
+
$ref: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
export type LocalizationStrings = {
|
|
40
|
+
[key: string]: string | string[] | LocalizationStrings;
|
|
41
|
+
};
|
|
42
|
+
export type LanguagesData = {
|
|
43
|
+
languages: LanguageInfo[];
|
|
44
|
+
localeFileBasePath?: string;
|
|
45
|
+
"localization-strings": LocalizationStrings;
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=main.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../server/main.js"],"names":[],"mappings":";0BAqCa;IACR,YAAY,EAAE,OAAO,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,EAAE,OAAO,CAAC;IACtB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,4BAA4B,EAAE,OAAO,CAAC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAA;CACtB;uBA2CS,GAAG;0CAKH,OAAO,qCAAqC,EAAE,mBAAmB,GACzE,WAAW,GAAG;IACZ,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;IACnC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,KAAK,CAAC;IACrB,SAAS,EAAE,KAAK,CAAC;CAClB;2BAwDO;IACR,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,KAAK,GAAC,KAAK,CAAC;IACvB,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;CACF;kCAIS;IACZ,CAAK,GAAG,EAAE,MAAM,GAAG,MAAM,GAAC,MAAM,EAAE,GAAC,mBAAmB,CAAA;CACnD;4BAIS;IACR,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAChC,sBAA0B,EAAE,mBAAmB,CAAA;CAC5C"}
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import activateCallback from './activateCallback-es.js';
|
|
2
|
+
import {getWorkFiles} from './WorkInfo-es.js';
|
|
3
|
+
|
|
4
|
+
// VERSION 0.1.0
|
|
5
|
+
|
|
6
|
+
const CURRENT_CACHES = {
|
|
7
|
+
prefetch: 'prefetch-cache-v'
|
|
8
|
+
};
|
|
9
|
+
const minutes = 60 * 1000;
|
|
10
|
+
|
|
11
|
+
// UTILITIES
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {number} PositiveInteger
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {number} Float
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {string} url
|
|
23
|
+
*/
|
|
24
|
+
async function getJSON (url) {
|
|
25
|
+
const resp = await fetch(url);
|
|
26
|
+
return await resp.json();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {ServiceWorkerGlobalScope} self
|
|
31
|
+
*/
|
|
32
|
+
function swHelper (self) {
|
|
33
|
+
// These could be made configurable by argument too
|
|
34
|
+
const defaultUserStaticFiles = [
|
|
35
|
+
'/', // Needs a separate entry from `index.html` (at least in Chrome)
|
|
36
|
+
'index.html',
|
|
37
|
+
'files.json',
|
|
38
|
+
'site.json',
|
|
39
|
+
'resources/user.js'
|
|
40
|
+
// We do not put the user.json here as that is obtained live with this
|
|
41
|
+
// service worker via `pathToUserJSON`
|
|
42
|
+
];
|
|
43
|
+
// Todo: We could supply `new URL(fileName, moduleURL).href` to
|
|
44
|
+
// get these as reliable full paths without hard-coding or needing to
|
|
45
|
+
// actually be in `node_modules/textbrowser`; see `resources/index.js`
|
|
46
|
+
const textbrowserStaticResourceFiles = [
|
|
47
|
+
'node_modules/textbrowser/appdata/languages.json',
|
|
48
|
+
|
|
49
|
+
/*
|
|
50
|
+
// Only needed atm for browser validation
|
|
51
|
+
'node_modules/textbrowser/general-schemas/files.jsonschema',
|
|
52
|
+
'node_modules/textbrowser/general-schemas/languages.jsonschema',
|
|
53
|
+
'node_modules/textbrowser-data-schemas/schemas/locale.jsonschema',
|
|
54
|
+
'node_modules/textbrowser-data-schemas/schemas/metadata.jsonschema',
|
|
55
|
+
'node_modules/textbrowser-data-schemas/schemas/table.jsonschema', // Not currently using for validation or meta-data
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
'node_modules/intl-locale-textinfo-polyfill/lib/Locale.js',
|
|
59
|
+
'node_modules/textbrowser/dist/assets/languages-1sAACTKG.json',
|
|
60
|
+
'node_modules/textbrowser/dist/assets/index-_11XnUty.css',
|
|
61
|
+
|
|
62
|
+
'node_modules/textbrowser/dist/index-es.js'
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @typedef {object} ConfigObject
|
|
67
|
+
* @property {string} namespace
|
|
68
|
+
* @property {string} basePath
|
|
69
|
+
* @property {string} languages
|
|
70
|
+
* @property {string} files
|
|
71
|
+
* @property {string[]} userStaticFiles
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
*
|
|
76
|
+
* @param {Partial<ConfigObject>} args
|
|
77
|
+
* @returns {Required<ConfigObject>}
|
|
78
|
+
* @todo Since some of these reused, move to external file (or
|
|
79
|
+
* use `setServiceWorkerDefaults`?)
|
|
80
|
+
*/
|
|
81
|
+
function getConfigDefaults (args) {
|
|
82
|
+
return {
|
|
83
|
+
namespace: 'textbrowser',
|
|
84
|
+
basePath: '',
|
|
85
|
+
languages: new URL('../appdata/languages.json', import.meta.url).href,
|
|
86
|
+
files: 'files.json',
|
|
87
|
+
userStaticFiles: defaultUserStaticFiles,
|
|
88
|
+
// Opportunity to override
|
|
89
|
+
...args
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
*
|
|
95
|
+
* @param {string[]} messages
|
|
96
|
+
* @returns {Promise<void>}
|
|
97
|
+
*/
|
|
98
|
+
function log (...messages) {
|
|
99
|
+
const message = messages.join(' ');
|
|
100
|
+
console.log(message);
|
|
101
|
+
return post({message, type: 'log'});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
*
|
|
106
|
+
* @param {Error} error
|
|
107
|
+
* @param {string[]} messages
|
|
108
|
+
* @returns {Promise<void>} Resolves to `undefined`
|
|
109
|
+
*/
|
|
110
|
+
function logError (error, ...messages) {
|
|
111
|
+
const message = messages.join(' ');
|
|
112
|
+
console.error(error, message);
|
|
113
|
+
return post({
|
|
114
|
+
message,
|
|
115
|
+
// errorType: error.type,
|
|
116
|
+
// name: error.name,
|
|
117
|
+
type: 'error'
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @callback DelayCallback
|
|
123
|
+
* @param {Float} time
|
|
124
|
+
* @returns {void}
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
*
|
|
129
|
+
* @param {DelayCallback} cb
|
|
130
|
+
* @param {PositiveInteger} timeout
|
|
131
|
+
* @param {string} errMessage
|
|
132
|
+
* @param {PositiveInteger} [time]
|
|
133
|
+
* @returns {Promise<void>}
|
|
134
|
+
*/
|
|
135
|
+
async function tryAndRetry (cb, timeout, errMessage, time = 0) {
|
|
136
|
+
time++;
|
|
137
|
+
try {
|
|
138
|
+
await cb(time); // eslint-disable-line n/callback-return -- Needed for retries
|
|
139
|
+
return undefined;
|
|
140
|
+
} catch (err) {
|
|
141
|
+
console.log('errrr', err);
|
|
142
|
+
logError(
|
|
143
|
+
/** @type {Error} */
|
|
144
|
+
(err),
|
|
145
|
+
/** @type {Error} */
|
|
146
|
+
(err).message || errMessage
|
|
147
|
+
);
|
|
148
|
+
return new Promise((resolve) => {
|
|
149
|
+
setTimeout(() => {
|
|
150
|
+
resolve(tryAndRetry(cb, timeout, errMessage, time));
|
|
151
|
+
}, timeout);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
*
|
|
158
|
+
* @param {object} args
|
|
159
|
+
* @param {"log"|"error"|"beginInstall"|"finishedInstall"|"beginActivate"|"finishedActivate"} args.type
|
|
160
|
+
* @param {string} [args.message]
|
|
161
|
+
* @returns {Promise<void>}
|
|
162
|
+
*/
|
|
163
|
+
async function post ({type, message = type}) {
|
|
164
|
+
const clients = await self.clients.matchAll({
|
|
165
|
+
// Are there any uncontrolled within activate anyways?
|
|
166
|
+
includeUncontrolled: true,
|
|
167
|
+
type: 'window'
|
|
168
|
+
}) || [];
|
|
169
|
+
if (message.includes('Posting finished')) {
|
|
170
|
+
message += ` (count: ${clients.length})`;
|
|
171
|
+
}
|
|
172
|
+
clients.forEach((client) => {
|
|
173
|
+
// Although we only need one client to which to send
|
|
174
|
+
// arguments, we want to signal phase complete to all
|
|
175
|
+
// eslint-disable-next-line unicorn/require-post-message-target-origin -- In worker
|
|
176
|
+
client.postMessage({message, type});
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
*
|
|
182
|
+
* @param {PositiveInteger} time
|
|
183
|
+
* @throws {Error}
|
|
184
|
+
* @returns {Promise<void>}
|
|
185
|
+
*/
|
|
186
|
+
async function install (time) {
|
|
187
|
+
post({type: 'beginInstall'});
|
|
188
|
+
log(`Install: Trying, attempt ${time}`);
|
|
189
|
+
const now = Date.now();
|
|
190
|
+
const json = await getJSON(/** @type {string} */ (pathToUserJSON));
|
|
191
|
+
|
|
192
|
+
const {
|
|
193
|
+
namespace, languages, files, userStaticFiles
|
|
194
|
+
} = getConfigDefaults(json);
|
|
195
|
+
|
|
196
|
+
const {version} = await getJSON('./package.json');
|
|
197
|
+
|
|
198
|
+
console.log('opening cache', namespace + CURRENT_CACHES.prefetch + version);
|
|
199
|
+
const [
|
|
200
|
+
cache,
|
|
201
|
+
userDataFiles,
|
|
202
|
+
{languages: langs}
|
|
203
|
+
] = await Promise.all([
|
|
204
|
+
caches.open(namespace + CURRENT_CACHES.prefetch + version),
|
|
205
|
+
getWorkFiles(files),
|
|
206
|
+
getJSON(languages)
|
|
207
|
+
]);
|
|
208
|
+
log('Install: Retrieved dependency values');
|
|
209
|
+
|
|
210
|
+
const langPathParts = languages.split('/');
|
|
211
|
+
|
|
212
|
+
// Todo: Ought to make these locales only conditionally required and
|
|
213
|
+
// then only show those specified in languages menu or go directly
|
|
214
|
+
// to work selection
|
|
215
|
+
// Todo: We might give option to only download
|
|
216
|
+
// one locale and avoid language splash page
|
|
217
|
+
const localeFiles =
|
|
218
|
+
/**
|
|
219
|
+
* @type {{
|
|
220
|
+
* code: string,
|
|
221
|
+
* direction: "rtl"|"ltr",
|
|
222
|
+
* locale: {$ref: string}
|
|
223
|
+
* }[]}
|
|
224
|
+
*/ (langs).map(
|
|
225
|
+
({locale: {$ref}}) => {
|
|
226
|
+
return (langPathParts.length > 1
|
|
227
|
+
? langPathParts.slice(0, -1).join('/') + '/'
|
|
228
|
+
: ''
|
|
229
|
+
) + $ref;
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
const urlsToPrefetch = [
|
|
234
|
+
...textbrowserStaticResourceFiles,
|
|
235
|
+
...localeFiles,
|
|
236
|
+
...userStaticFiles,
|
|
237
|
+
...userDataFiles,
|
|
238
|
+
...stylesheets
|
|
239
|
+
];
|
|
240
|
+
// .map((url) => url === 'index.html' ? new Request(url, {cache: 'reload'}) : url)
|
|
241
|
+
try {
|
|
242
|
+
const cachePromises = urlsToPrefetch.map(async (urlToPrefetch) => {
|
|
243
|
+
// This constructs a new URL object using the service worker's script
|
|
244
|
+
// location as the base for relative URLs.
|
|
245
|
+
const url = new URL(urlToPrefetch, location.href);
|
|
246
|
+
url.search += (url.search ? '&' : '?') + 'cache-bust=' + now;
|
|
247
|
+
const request = new Request(url, {mode: 'no-cors'});
|
|
248
|
+
try {
|
|
249
|
+
const response = await fetch(request);
|
|
250
|
+
if (response.status >= 400) {
|
|
251
|
+
throw new Error('request for ' + urlToPrefetch +
|
|
252
|
+
' failed with status ' + response.statusText);
|
|
253
|
+
}
|
|
254
|
+
return cache.put(urlToPrefetch, response);
|
|
255
|
+
} catch (error) {
|
|
256
|
+
logError(
|
|
257
|
+
/** @type {Error} */
|
|
258
|
+
(error),
|
|
259
|
+
`Not caching ${urlToPrefetch} due to ${error}`
|
|
260
|
+
);
|
|
261
|
+
throw error;
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
await Promise.all(cachePromises);
|
|
265
|
+
log('Install: Pre-fetching complete.');
|
|
266
|
+
} catch (error) {
|
|
267
|
+
logError(
|
|
268
|
+
/** @type {Error} */
|
|
269
|
+
(error),
|
|
270
|
+
`Install: Pre-fetching failed: ${error}`
|
|
271
|
+
);
|
|
272
|
+
// Failing gives chance for a new client to re-trigger install?
|
|
273
|
+
throw error;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// An install update event will not be reported until controlled,
|
|
277
|
+
// so we need to inform the clients
|
|
278
|
+
log(`Install: Posting finished message to clients`);
|
|
279
|
+
|
|
280
|
+
// Although we only need one client to which to send
|
|
281
|
+
// arguments, we want to signal phase complete to all
|
|
282
|
+
post({type: 'finishedInstall'});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
*
|
|
287
|
+
* @param {PositiveInteger} time
|
|
288
|
+
* @returns {Promise<void>}
|
|
289
|
+
*/
|
|
290
|
+
async function activate (time) {
|
|
291
|
+
post({type: 'beginActivate'});
|
|
292
|
+
log(`Activate: Trying, attempt ${time}`);
|
|
293
|
+
const [json, cacheNames] = await Promise.all([
|
|
294
|
+
getJSON(/** @type {string} */ (pathToUserJSON)),
|
|
295
|
+
caches.keys()
|
|
296
|
+
]);
|
|
297
|
+
const {namespace, files, basePath} = getConfigDefaults(json);
|
|
298
|
+
const {version} = await getJSON('./package.json');
|
|
299
|
+
|
|
300
|
+
const expectedCacheNames = Object.values(CURRENT_CACHES).map((n) => namespace + n + version);
|
|
301
|
+
cacheNames.map(async (cacheName) => {
|
|
302
|
+
if (!expectedCacheNames.includes(cacheName)) {
|
|
303
|
+
log('Activate: Deleting out of date cache:', cacheName);
|
|
304
|
+
await caches.delete(cacheName);
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
await activateCallback({namespace, files, basePath, log});
|
|
309
|
+
log('Activate: Database changes completed');
|
|
310
|
+
|
|
311
|
+
log(`Activate: Posting finished message to clients`);
|
|
312
|
+
// Signal phase complete to all clients
|
|
313
|
+
post({type: 'finishedActivate'});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// @ts-expect-error Ok
|
|
317
|
+
const params = new URL(location).searchParams;
|
|
318
|
+
const pathToUserJSON = params.get('pathToUserJSON');
|
|
319
|
+
const stylesheets = JSON.parse(params.get('stylesheets') || '[]');
|
|
320
|
+
|
|
321
|
+
console.log('sw info', pathToUserJSON);
|
|
322
|
+
console.log('sw stylesheets', stylesheets);
|
|
323
|
+
|
|
324
|
+
self.addEventListener('install', (e) => {
|
|
325
|
+
self.skipWaiting();
|
|
326
|
+
e.waitUntil(tryAndRetry(install, 5 * minutes, 'Error installing'));
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
self.addEventListener('activate', (e) => {
|
|
330
|
+
// Erring is of no present use here:
|
|
331
|
+
// https://github.com/w3c/ServiceWorker/issues/659#issuecomment-384919053
|
|
332
|
+
e.waitUntil(tryAndRetry(activate, 5 * minutes, 'Error activating'));
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// We cannot make this async as `e.respondWith` must be called synchronously
|
|
336
|
+
self.addEventListener('fetch', (e) => {
|
|
337
|
+
// DevTools opening will trigger these o-i-c requests
|
|
338
|
+
const {request} = e;
|
|
339
|
+
const {cache, mode, url} = request;
|
|
340
|
+
if (cache === 'only-if-cached' &&
|
|
341
|
+
mode !== 'same-origin') {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
console.log('fetching', url);
|
|
345
|
+
e.respondWith((async () => {
|
|
346
|
+
const cached = await caches.match(request);
|
|
347
|
+
if (!cached) {
|
|
348
|
+
console.log('no cached found', url);
|
|
349
|
+
}
|
|
350
|
+
return cached || fetch(request);
|
|
351
|
+
})());
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export default swHelper;
|
package/package.json
CHANGED
package/resources/index.js
CHANGED
|
@@ -477,10 +477,14 @@ class TextBrowser {
|
|
|
477
477
|
} else {
|
|
478
478
|
const worker = r.installing || r.waiting || r.active;
|
|
479
479
|
if (!worker) {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
480
|
+
console.warn('Worker registration returned with no worker; retrying registration.');
|
|
481
|
+
try {
|
|
482
|
+
await r.unregister();
|
|
483
|
+
} catch (err) {
|
|
484
|
+
console.warn('Unregister failed during retry', err);
|
|
485
|
+
}
|
|
486
|
+
Templates.permissions.main({siteI18n});
|
|
487
|
+
await prepareForServiceWorker.call(this);
|
|
484
488
|
return;
|
|
485
489
|
}
|
|
486
490
|
|