@eclipse-docks/extension-pwa 0.7.78
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/dist/i18n.de-Dls2qCix.js +11 -0
- package/dist/i18n.de-Dls2qCix.js.map +1 -0
- package/dist/i18n.en-DZPstBWw.js +11 -0
- package/dist/i18n.en-DZPstBWw.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/install-prompt-capture-fZikSCg3.js +26 -0
- package/dist/install-prompt-capture-fZikSCg3.js.map +1 -0
- package/dist/install-prompt-capture.d.ts +18 -0
- package/dist/install-prompt-capture.d.ts.map +1 -0
- package/dist/pwa-extension-B3u-NX-p.js +199 -0
- package/dist/pwa-extension-B3u-NX-p.js.map +1 -0
- package/dist/pwa-extension.d.ts +1 -0
- package/dist/pwa-extension.d.ts.map +1 -0
- package/dist/pwa-install-button.d.ts +18 -0
- package/dist/pwa-install-button.d.ts.map +1 -0
- package/dist/sw-update-indicator.d.ts +34 -0
- package/dist/sw-update-indicator.d.ts.map +1 -0
- package/package.json +32 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/i18n.de.json
|
|
2
|
+
var EXT_PWA_NAME = "PWA";
|
|
3
|
+
var EXT_PWA_DESC = "Service-Worker-Update und Installationshinweis in der unteren Symbolleiste, wenn der Browser das unterstützt.";
|
|
4
|
+
var i18n_de_default = {
|
|
5
|
+
EXT_PWA_NAME: "PWA",
|
|
6
|
+
EXT_PWA_DESC
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
9
|
+
export { EXT_PWA_DESC, EXT_PWA_NAME, i18n_de_default as default };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=i18n.de-Dls2qCix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.de-Dls2qCix.js","names":[],"sources":["../src/i18n.de.json"],"sourcesContent":["{\n \"EXT_PWA_NAME\": \"PWA\",\n \"EXT_PWA_DESC\": \"Service-Worker-Update und Installationshinweis in der unteren Symbolleiste, wenn der Browser das unterstützt.\"\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/i18n.en.json
|
|
2
|
+
var EXT_PWA_NAME = "PWA";
|
|
3
|
+
var EXT_PWA_DESC = "Service worker update control and install prompt in the bottom toolbar when the browser supports them.";
|
|
4
|
+
var i18n_en_default = {
|
|
5
|
+
EXT_PWA_NAME: "PWA",
|
|
6
|
+
EXT_PWA_DESC
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
9
|
+
export { EXT_PWA_DESC, EXT_PWA_NAME, i18n_en_default as default };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=i18n.en-DZPstBWw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.en-DZPstBWw.js","names":[],"sources":["../src/i18n.en.json"],"sourcesContent":["{\n \"EXT_PWA_NAME\": \"PWA\",\n \"EXT_PWA_DESC\": \"Service worker update control and install prompt in the bottom toolbar when the browser supports them.\"\n}\n"],"mappings":""}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,0BAA0B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import "./install-prompt-capture-fZikSCg3.js";
|
|
2
|
+
import { extensionRegistry, i18n } from "@eclipse-docks/core";
|
|
3
|
+
import pkg from "../package.json";
|
|
4
|
+
//#region src/index.ts
|
|
5
|
+
var t = await i18n(/* @__PURE__ */ Object.assign({
|
|
6
|
+
"./i18n.de.json": () => import("./i18n.de-Dls2qCix.js"),
|
|
7
|
+
"./i18n.en.json": () => import("./i18n.en-DZPstBWw.js")
|
|
8
|
+
}), true);
|
|
9
|
+
extensionRegistry.registerExtension({
|
|
10
|
+
id: pkg.name,
|
|
11
|
+
name: t.EXT_PWA_NAME,
|
|
12
|
+
description: t.EXT_PWA_DESC,
|
|
13
|
+
loader: () => import("./pwa-extension-B3u-NX-p.js"),
|
|
14
|
+
icon: "download"
|
|
15
|
+
});
|
|
16
|
+
//#endregion
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import './install-prompt-capture';\nimport { extensionRegistry, i18n } from '@eclipse-docks/core';\nimport pkg from '../package.json';\n\nconst t = await i18n(import.meta.glob('./i18n*.json'), true);\n\nextensionRegistry.registerExtension({\n id: pkg.name,\n name: t.EXT_PWA_NAME,\n description: t.EXT_PWA_DESC,\n loader: () => import('./pwa-extension'),\n icon: 'download',\n});\n"],"mappings":";;;;AAIA,IAAM,IAAI,MAAM,KAAK,uBAAA,OAAA;CAAA,wBAAA,OAAA;CAAA,wBAAA,OAAA;CAAA,CAAgC,EAAE,KAAK;AAE5D,kBAAkB,kBAAkB;CAClC,IAAI,IAAI;CACR,MAAM,EAAE;CACR,aAAa,EAAE;CACf,cAAc,OAAO;CACrB,MAAM;CACP,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/install-prompt-capture.ts
|
|
2
|
+
var PWA_INSTALL_PROMPT_AVAILABLE = "docks-pwa-install-prompt-available";
|
|
3
|
+
var captured = null;
|
|
4
|
+
function peekInstallPrompt() {
|
|
5
|
+
return captured;
|
|
6
|
+
}
|
|
7
|
+
function clearInstallPromptCapture() {
|
|
8
|
+
captured = null;
|
|
9
|
+
}
|
|
10
|
+
function isStandaloneShell() {
|
|
11
|
+
if (typeof window === "undefined") return true;
|
|
12
|
+
return window.matchMedia("(display-mode: standalone)").matches || window.matchMedia("(display-mode: window-controls-overlay)").matches || window.navigator.standalone === true;
|
|
13
|
+
}
|
|
14
|
+
function init() {
|
|
15
|
+
if (typeof window === "undefined" || isStandaloneShell()) return;
|
|
16
|
+
window.addEventListener("beforeinstallprompt", (e) => {
|
|
17
|
+
e.preventDefault();
|
|
18
|
+
captured = e;
|
|
19
|
+
window.dispatchEvent(new CustomEvent(PWA_INSTALL_PROMPT_AVAILABLE));
|
|
20
|
+
}, { passive: false });
|
|
21
|
+
}
|
|
22
|
+
init();
|
|
23
|
+
//#endregion
|
|
24
|
+
export { clearInstallPromptCapture as n, peekInstallPrompt as r, PWA_INSTALL_PROMPT_AVAILABLE as t };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=install-prompt-capture-fZikSCg3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-prompt-capture-fZikSCg3.js","names":[],"sources":["../src/install-prompt-capture.ts"],"sourcesContent":["/**\n * Chromium fires `beforeinstallprompt` at most once; listeners must be registered early.\n * This module runs from `index.ts` when the package is first imported—before the lazy\n * extension loader and before `extensionRegistry.registerExtension` order matters.\n * App authors should static-import `@eclipse-docks/extension-pwa` ahead of heavy\n * extension entries (or in `main.ts` first) so this runs before top-level `await`\n * chains in other extensions delay evaluation.\n */\nexport interface PwaInstallPromptEvent extends Event {\n prompt(): Promise<void>;\n readonly userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>;\n}\n\nexport const PWA_INSTALL_PROMPT_AVAILABLE = 'docks-pwa-install-prompt-available';\n\nlet captured: PwaInstallPromptEvent | null = null;\n\nexport function peekInstallPrompt(): PwaInstallPromptEvent | null {\n return captured;\n}\n\nexport function clearInstallPromptCapture(): void {\n captured = null;\n}\n\nfunction isStandaloneShell(): boolean {\n if (typeof window === 'undefined') {\n return true;\n }\n return (\n window.matchMedia('(display-mode: standalone)').matches ||\n window.matchMedia('(display-mode: window-controls-overlay)').matches ||\n (window.navigator as Navigator & { standalone?: boolean }).standalone === true\n );\n}\n\nfunction init(): void {\n if (typeof window === 'undefined' || isStandaloneShell()) {\n return;\n }\n window.addEventListener(\n 'beforeinstallprompt',\n (e) => {\n e.preventDefault();\n captured = e as PwaInstallPromptEvent;\n window.dispatchEvent(new CustomEvent(PWA_INSTALL_PROMPT_AVAILABLE));\n },\n { passive: false },\n );\n}\n\ninit();\n"],"mappings":";AAaA,IAAa,+BAA+B;AAE5C,IAAI,WAAyC;AAE7C,SAAgB,oBAAkD;AAChE,QAAO;;AAGT,SAAgB,4BAAkC;AAChD,YAAW;;AAGb,SAAS,oBAA6B;AACpC,KAAI,OAAO,WAAW,YACpB,QAAO;AAET,QACE,OAAO,WAAW,6BAA6B,CAAC,WAChD,OAAO,WAAW,0CAA0C,CAAC,WAC5D,OAAO,UAAmD,eAAe;;AAI9E,SAAS,OAAa;AACpB,KAAI,OAAO,WAAW,eAAe,mBAAmB,CACtD;AAEF,QAAO,iBACL,wBACC,MAAM;AACL,IAAE,gBAAgB;AAClB,aAAW;AACX,SAAO,cAAc,IAAI,YAAY,6BAA6B,CAAC;IAErE,EAAE,SAAS,OAAO,CACnB;;AAGH,MAAM"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chromium fires `beforeinstallprompt` at most once; listeners must be registered early.
|
|
3
|
+
* This module runs from `index.ts` when the package is first imported—before the lazy
|
|
4
|
+
* extension loader and before `extensionRegistry.registerExtension` order matters.
|
|
5
|
+
* App authors should static-import `@eclipse-docks/extension-pwa` ahead of heavy
|
|
6
|
+
* extension entries (or in `main.ts` first) so this runs before top-level `await`
|
|
7
|
+
* chains in other extensions delay evaluation.
|
|
8
|
+
*/
|
|
9
|
+
export interface PwaInstallPromptEvent extends Event {
|
|
10
|
+
prompt(): Promise<void>;
|
|
11
|
+
readonly userChoice: Promise<{
|
|
12
|
+
outcome: 'accepted' | 'dismissed';
|
|
13
|
+
}>;
|
|
14
|
+
}
|
|
15
|
+
export declare const PWA_INSTALL_PROMPT_AVAILABLE = "docks-pwa-install-prompt-available";
|
|
16
|
+
export declare function peekInstallPrompt(): PwaInstallPromptEvent | null;
|
|
17
|
+
export declare function clearInstallPromptCapture(): void;
|
|
18
|
+
//# sourceMappingURL=install-prompt-capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-prompt-capture.d.ts","sourceRoot":"","sources":["../src/install-prompt-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAsB,SAAQ,KAAK;IAClD,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;QAAE,OAAO,EAAE,UAAU,GAAG,WAAW,CAAA;KAAE,CAAC,CAAC;CACrE;AAED,eAAO,MAAM,4BAA4B,uCAAuC,CAAC;AAIjF,wBAAgB,iBAAiB,IAAI,qBAAqB,GAAG,IAAI,CAEhE;AAED,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { n as clearInstallPromptCapture, r as peekInstallPrompt, t as PWA_INSTALL_PROMPT_AVAILABLE } from "./install-prompt-capture-fZikSCg3.js";
|
|
2
|
+
import { DocksElement, TOOLBAR_BOTTOM, contributionRegistry } from "@eclipse-docks/core";
|
|
3
|
+
import { html } from "lit";
|
|
4
|
+
import { customElement, state } from "lit/decorators.js";
|
|
5
|
+
import _decorate from "@oxc-project/runtime/helpers/decorate";
|
|
6
|
+
//#region src/sw-update-indicator.ts
|
|
7
|
+
var DocksSwUpdateIndicator = class DocksSwUpdateIndicator extends DocksElement {
|
|
8
|
+
constructor(..._args) {
|
|
9
|
+
super(..._args);
|
|
10
|
+
this.updateAvailable = false;
|
|
11
|
+
this.pendingReload = false;
|
|
12
|
+
this.registration = null;
|
|
13
|
+
this.periodicInterval = null;
|
|
14
|
+
this.pollInterval = null;
|
|
15
|
+
this.pollAttempts = 0;
|
|
16
|
+
this.attachAbort = null;
|
|
17
|
+
this.onControllerChange = () => {
|
|
18
|
+
if (!this.pendingReload) return;
|
|
19
|
+
window.location.reload();
|
|
20
|
+
};
|
|
21
|
+
this.onUpdateFound = () => {
|
|
22
|
+
const registration = this.registration;
|
|
23
|
+
if (!registration) return;
|
|
24
|
+
const installing = registration.installing;
|
|
25
|
+
if (!installing) return;
|
|
26
|
+
const signal = this.attachAbort?.signal;
|
|
27
|
+
if (!signal) return;
|
|
28
|
+
installing.addEventListener("statechange", () => {
|
|
29
|
+
if (installing.state !== "installed") return;
|
|
30
|
+
if (!navigator.serviceWorker.controller) return;
|
|
31
|
+
this.syncUpdateState(registration);
|
|
32
|
+
}, { signal });
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
connectedCallback() {
|
|
36
|
+
super.connectedCallback();
|
|
37
|
+
if (!("serviceWorker" in navigator)) return;
|
|
38
|
+
navigator.serviceWorker.addEventListener("controllerchange", this.onControllerChange);
|
|
39
|
+
this.findOrAttachRegistration();
|
|
40
|
+
}
|
|
41
|
+
disconnectedCallback() {
|
|
42
|
+
super.disconnectedCallback();
|
|
43
|
+
navigator.serviceWorker.removeEventListener("controllerchange", this.onControllerChange);
|
|
44
|
+
this.teardownAttachment();
|
|
45
|
+
}
|
|
46
|
+
async findOrAttachRegistration() {
|
|
47
|
+
const existing = await navigator.serviceWorker.getRegistration();
|
|
48
|
+
if (existing) {
|
|
49
|
+
this.attach(existing);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.pollInterval = window.setInterval(async () => {
|
|
53
|
+
this.pollAttempts += 1;
|
|
54
|
+
const reg = await navigator.serviceWorker.getRegistration();
|
|
55
|
+
if (reg) {
|
|
56
|
+
this.clearPoll();
|
|
57
|
+
this.attach(reg);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (this.pollAttempts >= 30) this.clearPoll();
|
|
61
|
+
}, 1e3);
|
|
62
|
+
}
|
|
63
|
+
clearPoll() {
|
|
64
|
+
if (this.pollInterval !== null) {
|
|
65
|
+
window.clearInterval(this.pollInterval);
|
|
66
|
+
this.pollInterval = null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
teardownAttachment() {
|
|
70
|
+
this.clearPoll();
|
|
71
|
+
if (this.periodicInterval !== null) {
|
|
72
|
+
window.clearInterval(this.periodicInterval);
|
|
73
|
+
this.periodicInterval = null;
|
|
74
|
+
}
|
|
75
|
+
this.attachAbort?.abort();
|
|
76
|
+
this.attachAbort = null;
|
|
77
|
+
this.registration = null;
|
|
78
|
+
this.updateAvailable = false;
|
|
79
|
+
}
|
|
80
|
+
syncUpdateState(registration) {
|
|
81
|
+
this.updateAvailable = Boolean(registration.waiting);
|
|
82
|
+
}
|
|
83
|
+
attach(registration) {
|
|
84
|
+
if (this.registration === registration) return;
|
|
85
|
+
this.attachAbort?.abort();
|
|
86
|
+
this.attachAbort = new AbortController();
|
|
87
|
+
const signal = this.attachAbort.signal;
|
|
88
|
+
this.registration = registration;
|
|
89
|
+
this.syncUpdateState(registration);
|
|
90
|
+
registration.addEventListener("updatefound", this.onUpdateFound, { signal });
|
|
91
|
+
registration.update().catch(() => {});
|
|
92
|
+
this.periodicInterval = window.setInterval(() => {
|
|
93
|
+
registration.update().catch(() => {});
|
|
94
|
+
}, 3600 * 1e3);
|
|
95
|
+
}
|
|
96
|
+
onActivateClick() {
|
|
97
|
+
const w = this.registration?.waiting;
|
|
98
|
+
if (w) {
|
|
99
|
+
this.pendingReload = true;
|
|
100
|
+
w.postMessage({ type: "SKIP_WAITING" });
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
window.location.reload();
|
|
104
|
+
}
|
|
105
|
+
render() {
|
|
106
|
+
if (!this.updateAvailable) return html``;
|
|
107
|
+
return html`
|
|
108
|
+
<wa-button
|
|
109
|
+
appearance="plain"
|
|
110
|
+
title="A new version is available. Click to reload."
|
|
111
|
+
aria-label="A new version is available. Reload to update."
|
|
112
|
+
@click=${this.onActivateClick}
|
|
113
|
+
>
|
|
114
|
+
<wa-icon name="arrows-rotate" label=""></wa-icon>
|
|
115
|
+
</wa-button>
|
|
116
|
+
`;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
_decorate([state()], DocksSwUpdateIndicator.prototype, "updateAvailable", void 0);
|
|
120
|
+
DocksSwUpdateIndicator = _decorate([customElement("docks-sw-update-indicator")], DocksSwUpdateIndicator);
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/pwa-install-button.ts
|
|
123
|
+
function isRunningAsInstalledPwa() {
|
|
124
|
+
return window.matchMedia("(display-mode: standalone)").matches || window.matchMedia("(display-mode: window-controls-overlay)").matches || window.navigator.standalone === true;
|
|
125
|
+
}
|
|
126
|
+
var DocksPwaInstall = class DocksPwaInstall extends DocksElement {
|
|
127
|
+
constructor(..._args) {
|
|
128
|
+
super(..._args);
|
|
129
|
+
this.showInstall = false;
|
|
130
|
+
this.deferredPrompt = null;
|
|
131
|
+
this.onPromptAvailable = () => {
|
|
132
|
+
this.applyCapturedPrompt();
|
|
133
|
+
};
|
|
134
|
+
this.onAppInstalled = () => {
|
|
135
|
+
clearInstallPromptCapture();
|
|
136
|
+
this.deferredPrompt = null;
|
|
137
|
+
this.showInstall = false;
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
applyCapturedPrompt() {
|
|
141
|
+
const p = peekInstallPrompt();
|
|
142
|
+
if (!p) return;
|
|
143
|
+
this.deferredPrompt = p;
|
|
144
|
+
this.showInstall = true;
|
|
145
|
+
}
|
|
146
|
+
connectedCallback() {
|
|
147
|
+
super.connectedCallback();
|
|
148
|
+
if (isRunningAsInstalledPwa()) return;
|
|
149
|
+
this.applyCapturedPrompt();
|
|
150
|
+
window.addEventListener(PWA_INSTALL_PROMPT_AVAILABLE, this.onPromptAvailable);
|
|
151
|
+
window.addEventListener("appinstalled", this.onAppInstalled);
|
|
152
|
+
}
|
|
153
|
+
disconnectedCallback() {
|
|
154
|
+
super.disconnectedCallback();
|
|
155
|
+
window.removeEventListener(PWA_INSTALL_PROMPT_AVAILABLE, this.onPromptAvailable);
|
|
156
|
+
window.removeEventListener("appinstalled", this.onAppInstalled);
|
|
157
|
+
}
|
|
158
|
+
async onInstallClick() {
|
|
159
|
+
const promptEvent = this.deferredPrompt;
|
|
160
|
+
if (!promptEvent) return;
|
|
161
|
+
await promptEvent.prompt();
|
|
162
|
+
await promptEvent.userChoice.catch(() => {});
|
|
163
|
+
clearInstallPromptCapture();
|
|
164
|
+
this.deferredPrompt = null;
|
|
165
|
+
this.showInstall = false;
|
|
166
|
+
}
|
|
167
|
+
render() {
|
|
168
|
+
if (!this.showInstall) return html``;
|
|
169
|
+
return html`
|
|
170
|
+
<wa-button
|
|
171
|
+
appearance="plain"
|
|
172
|
+
title="Install this app on your device"
|
|
173
|
+
aria-label="Install app"
|
|
174
|
+
@click=${() => void this.onInstallClick()}
|
|
175
|
+
>
|
|
176
|
+
<wa-icon name="download" label=""></wa-icon>
|
|
177
|
+
</wa-button>
|
|
178
|
+
`;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
_decorate([state()], DocksPwaInstall.prototype, "showInstall", void 0);
|
|
182
|
+
DocksPwaInstall = _decorate([customElement("docks-pwa-install")], DocksPwaInstall);
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region src/pwa-extension.ts
|
|
185
|
+
var TOOLBAR_SW_UPDATE = "toolbar.swUpdate";
|
|
186
|
+
var TOOLBAR_PWA_INSTALL = "toolbar.pwaInstall";
|
|
187
|
+
contributionRegistry.registerContribution(TOOLBAR_BOTTOM, {
|
|
188
|
+
name: TOOLBAR_SW_UPDATE,
|
|
189
|
+
label: "App update",
|
|
190
|
+
component: `<docks-sw-update-indicator></docks-sw-update-indicator>`
|
|
191
|
+
});
|
|
192
|
+
contributionRegistry.registerContribution(TOOLBAR_BOTTOM, {
|
|
193
|
+
name: TOOLBAR_PWA_INSTALL,
|
|
194
|
+
label: "Install app",
|
|
195
|
+
component: `<docks-pwa-install></docks-pwa-install>`
|
|
196
|
+
});
|
|
197
|
+
//#endregion
|
|
198
|
+
|
|
199
|
+
//# sourceMappingURL=pwa-extension-B3u-NX-p.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pwa-extension-B3u-NX-p.js","names":[],"sources":["../src/sw-update-indicator.ts","../src/pwa-install-button.ts","../src/pwa-extension.ts"],"sourcesContent":["import { html } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\n\nimport { DocksElement } from '@eclipse-docks/core';\n\n/**\n * Shows a toolbar icon when a new service worker is waiting (vite-plugin-pwa injectManifest + SKIP_WAITING message).\n * Hidden when there is no update or when service workers are unavailable.\n *\n * Safe when the extension loads late: attaches via `getRegistration()`, reads `registration.waiting`,\n * and subscribes to `updatefound` for subsequent updates.\n */\n@customElement('docks-sw-update-indicator')\nexport class DocksSwUpdateIndicator extends DocksElement {\n @state()\n private updateAvailable = false;\n\n private pendingReload = false;\n private registration: ServiceWorkerRegistration | null = null;\n private periodicInterval: number | null = null;\n private pollInterval: number | null = null;\n private pollAttempts = 0;\n private attachAbort: AbortController | null = null;\n\n private readonly onControllerChange = (): void => {\n if (!this.pendingReload) {\n return;\n }\n window.location.reload();\n };\n\n connectedCallback(): void {\n super.connectedCallback();\n if (!('serviceWorker' in navigator)) {\n return;\n }\n navigator.serviceWorker.addEventListener('controllerchange', this.onControllerChange);\n void this.findOrAttachRegistration();\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n navigator.serviceWorker.removeEventListener('controllerchange', this.onControllerChange);\n this.teardownAttachment();\n }\n\n private async findOrAttachRegistration(): Promise<void> {\n const existing = await navigator.serviceWorker.getRegistration();\n if (existing) {\n this.attach(existing);\n return;\n }\n\n this.pollInterval = window.setInterval(async () => {\n this.pollAttempts += 1;\n const reg = await navigator.serviceWorker.getRegistration();\n if (reg) {\n this.clearPoll();\n this.attach(reg);\n return;\n }\n if (this.pollAttempts >= 30) {\n this.clearPoll();\n }\n }, 1000);\n }\n\n private clearPoll(): void {\n if (this.pollInterval !== null) {\n window.clearInterval(this.pollInterval);\n this.pollInterval = null;\n }\n }\n\n private teardownAttachment(): void {\n this.clearPoll();\n if (this.periodicInterval !== null) {\n window.clearInterval(this.periodicInterval);\n this.periodicInterval = null;\n }\n this.attachAbort?.abort();\n this.attachAbort = null;\n this.registration = null;\n this.updateAvailable = false;\n }\n\n private syncUpdateState(registration: ServiceWorkerRegistration): void {\n this.updateAvailable = Boolean(registration.waiting);\n }\n\n private readonly onUpdateFound = (): void => {\n const registration = this.registration;\n if (!registration) {\n return;\n }\n const installing = registration.installing;\n if (!installing) {\n return;\n }\n const signal = this.attachAbort?.signal;\n if (!signal) {\n return;\n }\n installing.addEventListener(\n 'statechange',\n () => {\n if (installing.state !== 'installed') {\n return;\n }\n if (!navigator.serviceWorker.controller) {\n return;\n }\n this.syncUpdateState(registration);\n },\n { signal },\n );\n };\n\n private attach(registration: ServiceWorkerRegistration): void {\n if (this.registration === registration) {\n return;\n }\n this.attachAbort?.abort();\n this.attachAbort = new AbortController();\n const signal = this.attachAbort.signal;\n\n this.registration = registration;\n this.syncUpdateState(registration);\n\n registration.addEventListener('updatefound', this.onUpdateFound, { signal });\n\n void registration.update().catch(() => {});\n this.periodicInterval = window.setInterval(() => {\n void registration.update().catch(() => {});\n }, 60 * 60 * 1000);\n }\n\n private onActivateClick(): void {\n const w = this.registration?.waiting;\n if (w) {\n this.pendingReload = true;\n w.postMessage({ type: 'SKIP_WAITING' });\n return;\n }\n window.location.reload();\n }\n\n protected render() {\n if (!this.updateAvailable) {\n return html``;\n }\n\n return html`\n <wa-button\n appearance=\"plain\"\n title=\"A new version is available. Click to reload.\"\n aria-label=\"A new version is available. Reload to update.\"\n @click=${this.onActivateClick}\n >\n <wa-icon name=\"arrows-rotate\" label=\"\"></wa-icon>\n </wa-button>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'docks-sw-update-indicator': DocksSwUpdateIndicator;\n }\n}\n","import { html } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\n\nimport { DocksElement } from '@eclipse-docks/core';\n\nimport {\n clearInstallPromptCapture,\n peekInstallPrompt,\n PWA_INSTALL_PROMPT_AVAILABLE,\n type PwaInstallPromptEvent,\n} from './install-prompt-capture';\n\nfunction isRunningAsInstalledPwa(): boolean {\n return (\n window.matchMedia('(display-mode: standalone)').matches ||\n window.matchMedia('(display-mode: window-controls-overlay)').matches ||\n (window.navigator as Navigator & { standalone?: boolean }).standalone === true\n );\n}\n\n@customElement('docks-pwa-install')\nexport class DocksPwaInstall extends DocksElement {\n @state()\n private showInstall = false;\n\n private deferredPrompt: PwaInstallPromptEvent | null = null;\n\n private readonly onPromptAvailable = (): void => {\n this.applyCapturedPrompt();\n };\n\n private readonly onAppInstalled = (): void => {\n clearInstallPromptCapture();\n this.deferredPrompt = null;\n this.showInstall = false;\n };\n\n private applyCapturedPrompt(): void {\n const p = peekInstallPrompt();\n if (!p) {\n return;\n }\n this.deferredPrompt = p;\n this.showInstall = true;\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n if (isRunningAsInstalledPwa()) {\n return;\n }\n this.applyCapturedPrompt();\n window.addEventListener(PWA_INSTALL_PROMPT_AVAILABLE, this.onPromptAvailable);\n window.addEventListener('appinstalled', this.onAppInstalled);\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener(PWA_INSTALL_PROMPT_AVAILABLE, this.onPromptAvailable);\n window.removeEventListener('appinstalled', this.onAppInstalled);\n }\n\n private async onInstallClick(): Promise<void> {\n const promptEvent = this.deferredPrompt;\n if (!promptEvent) {\n return;\n }\n await promptEvent.prompt();\n await promptEvent.userChoice.catch(() => {});\n clearInstallPromptCapture();\n this.deferredPrompt = null;\n this.showInstall = false;\n }\n\n protected render() {\n if (!this.showInstall) {\n return html``;\n }\n\n return html`\n <wa-button\n appearance=\"plain\"\n title=\"Install this app on your device\"\n aria-label=\"Install app\"\n @click=${() => void this.onInstallClick()}\n >\n <wa-icon name=\"download\" label=\"\"></wa-icon>\n </wa-button>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'docks-pwa-install': DocksPwaInstall;\n }\n}\n","import { contributionRegistry, type HTMLContribution } from '@eclipse-docks/core';\nimport { TOOLBAR_BOTTOM } from '@eclipse-docks/core';\nimport './sw-update-indicator';\nimport './pwa-install-button';\n\nconst TOOLBAR_SW_UPDATE = 'toolbar.swUpdate';\nconst TOOLBAR_PWA_INSTALL = 'toolbar.pwaInstall';\n\ncontributionRegistry.registerContribution(TOOLBAR_BOTTOM, {\n name: TOOLBAR_SW_UPDATE,\n label: 'App update',\n component: `<docks-sw-update-indicator></docks-sw-update-indicator>`,\n} as HTMLContribution);\n\ncontributionRegistry.registerContribution(TOOLBAR_BOTTOM, {\n name: TOOLBAR_PWA_INSTALL,\n label: 'Install app',\n component: `<docks-pwa-install></docks-pwa-install>`,\n} as HTMLContribution);\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=pwa-extension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pwa-extension.d.ts","sourceRoot":"","sources":["../src/pwa-extension.ts"],"names":[],"mappings":"AAEA,OAAO,uBAAuB,CAAC;AAC/B,OAAO,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { DocksElement } from '@eclipse-docks/core';
|
|
2
|
+
export declare class DocksPwaInstall extends DocksElement {
|
|
3
|
+
private showInstall;
|
|
4
|
+
private deferredPrompt;
|
|
5
|
+
private readonly onPromptAvailable;
|
|
6
|
+
private readonly onAppInstalled;
|
|
7
|
+
private applyCapturedPrompt;
|
|
8
|
+
connectedCallback(): void;
|
|
9
|
+
disconnectedCallback(): void;
|
|
10
|
+
private onInstallClick;
|
|
11
|
+
protected render(): import('lit-html').TemplateResult<1>;
|
|
12
|
+
}
|
|
13
|
+
declare global {
|
|
14
|
+
interface HTMLElementTagNameMap {
|
|
15
|
+
'docks-pwa-install': DocksPwaInstall;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=pwa-install-button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pwa-install-button.d.ts","sourceRoot":"","sources":["../src/pwa-install-button.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAiBnD,qBACa,eAAgB,SAAQ,YAAY;IAE/C,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,cAAc,CAAsC;IAE5D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAEhC;IAEF,OAAO,CAAC,QAAQ,CAAC,cAAc,CAI7B;IAEF,OAAO,CAAC,mBAAmB;IAS3B,iBAAiB,IAAI,IAAI;IAUzB,oBAAoB,IAAI,IAAI;YAMd,cAAc;IAY5B,SAAS,CAAC,MAAM;CAgBjB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,mBAAmB,EAAE,eAAe,CAAC;KACtC;CACF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { DocksElement } from '@eclipse-docks/core';
|
|
2
|
+
/**
|
|
3
|
+
* Shows a toolbar icon when a new service worker is waiting (vite-plugin-pwa injectManifest + SKIP_WAITING message).
|
|
4
|
+
* Hidden when there is no update or when service workers are unavailable.
|
|
5
|
+
*
|
|
6
|
+
* Safe when the extension loads late: attaches via `getRegistration()`, reads `registration.waiting`,
|
|
7
|
+
* and subscribes to `updatefound` for subsequent updates.
|
|
8
|
+
*/
|
|
9
|
+
export declare class DocksSwUpdateIndicator extends DocksElement {
|
|
10
|
+
private updateAvailable;
|
|
11
|
+
private pendingReload;
|
|
12
|
+
private registration;
|
|
13
|
+
private periodicInterval;
|
|
14
|
+
private pollInterval;
|
|
15
|
+
private pollAttempts;
|
|
16
|
+
private attachAbort;
|
|
17
|
+
private readonly onControllerChange;
|
|
18
|
+
connectedCallback(): void;
|
|
19
|
+
disconnectedCallback(): void;
|
|
20
|
+
private findOrAttachRegistration;
|
|
21
|
+
private clearPoll;
|
|
22
|
+
private teardownAttachment;
|
|
23
|
+
private syncUpdateState;
|
|
24
|
+
private readonly onUpdateFound;
|
|
25
|
+
private attach;
|
|
26
|
+
private onActivateClick;
|
|
27
|
+
protected render(): import('lit-html').TemplateResult<1>;
|
|
28
|
+
}
|
|
29
|
+
declare global {
|
|
30
|
+
interface HTMLElementTagNameMap {
|
|
31
|
+
'docks-sw-update-indicator': DocksSwUpdateIndicator;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=sw-update-indicator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sw-update-indicator.d.ts","sourceRoot":"","sources":["../src/sw-update-indicator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD;;;;;;GAMG;AACH,qBACa,sBAAuB,SAAQ,YAAY;IAEtD,OAAO,CAAC,eAAe,CAAS;IAEhC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAA0C;IAC9D,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,WAAW,CAAgC;IAEnD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAKjC;IAEF,iBAAiB,IAAI,IAAI;IASzB,oBAAoB,IAAI,IAAI;YAMd,wBAAwB;IAqBtC,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,QAAQ,CAAC,aAAa,CA0B5B;IAEF,OAAO,CAAC,MAAM;IAmBd,OAAO,CAAC,eAAe;IAUvB,SAAS,CAAC,MAAM;CAgBjB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,2BAA2B,EAAE,sBAAsB,CAAC;KACrD;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@eclipse-docks/extension-pwa",
|
|
3
|
+
"version": "0.7.78",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@eclipse-docks/core": "*"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"typescript": "^6.0.0",
|
|
17
|
+
"vite": "^8.0.0",
|
|
18
|
+
"vite-plugin-dts": "^4.5.4"
|
|
19
|
+
},
|
|
20
|
+
"module": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "vite build"
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/eclipse-docks/core"
|
|
31
|
+
}
|
|
32
|
+
}
|