aboutsummaryrefslogtreecommitdiffstats
path: root/packages/main
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-03-28 23:37:15 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-05-16 00:54:56 +0200
commit04555cc62c9cded08c3090288fa372d961c50737 (patch)
tree4566893892216446dfe24490c98881316b97cb41 /packages/main
parentdesign: Increase location bar UI density (diff)
downloadsophie-04555cc62c9cded08c3090288fa372d961c50737.tar.gz
sophie-04555cc62c9cded08c3090288fa372d961c50737.tar.zst
sophie-04555cc62c9cded08c3090288fa372d961c50737.zip
feat: New window banner
* Add renderer code for notification banners with buttons * Handle new window open requests by denying them and displaying a notification Signed-off-by: Kristóf Marussy <kristof@marussy.com>
Diffstat (limited to 'packages/main')
-rw-r--r--packages/main/src/infrastructure/electron/impl/ElectronServiceView.ts10
-rw-r--r--packages/main/src/stores/Service.ts51
2 files changed, 61 insertions, 0 deletions
diff --git a/packages/main/src/infrastructure/electron/impl/ElectronServiceView.ts b/packages/main/src/infrastructure/electron/impl/ElectronServiceView.ts
index edcf758..089e63a 100644
--- a/packages/main/src/infrastructure/electron/impl/ElectronServiceView.ts
+++ b/packages/main/src/infrastructure/electron/impl/ElectronServiceView.ts
@@ -136,6 +136,16 @@ export default class ElectronServiceView implements ServiceView {
136 const { reason, exitCode } = details; 136 const { reason, exitCode } = details;
137 service.setCrashed(reason, exitCode); 137 service.setCrashed(reason, exitCode);
138 }); 138 });
139
140 webContents.setWindowOpenHandler(({ url }) => {
141 // TODO Add filtering (allowlist) by URL.
142 // TODO Handle `new-window` disposition where the service wants an object returned by
143 // `window.open`.
144 // TODO Handle downloads with `save-to-disk` disposition.
145 // TODO Handle POST bodies where the window must be allowed to open or the data is lost.
146 service.addBlockedPopup(url);
147 return { action: 'deny' };
148 });
139 } 149 }
140 150
141 get webContentsId(): number { 151 get webContentsId(): number {
diff --git a/packages/main/src/stores/Service.ts b/packages/main/src/stores/Service.ts
index 26e3517..0a35114 100644
--- a/packages/main/src/stores/Service.ts
+++ b/packages/main/src/stores/Service.ts
@@ -105,6 +105,27 @@ const Service = defineServiceModel(ServiceSettings)
105 } 105 }
106 getEnv(self).openURLInExternalBrowser(self.currentUrl); 106 getEnv(self).openURLInExternalBrowser(self.currentUrl);
107 }, 107 },
108 addBlockedPopup(url: string): void {
109 const index = self.popups.indexOf(url);
110 if (index >= 0) {
111 // Move existing popup to the end of the array,
112 // because later popups have precedence over earlier ones.
113 self.popups.splice(index, 1);
114 }
115 self.popups.push(url);
116 },
117 dismissPopup(url: string): boolean {
118 const index = self.popups.indexOf(url);
119 if (index < 0) {
120 log.warn('Service', self.id, 'has no pending popup', url);
121 return false;
122 }
123 self.popups.splice(index, 1);
124 return true;
125 },
126 dismissAllPopups(): void {
127 self.popups.splice(0);
128 },
108 })) 129 }))
109 .actions((self) => { 130 .actions((self) => {
110 function setState(state: ServiceStateSnapshotIn): void { 131 function setState(state: ServiceStateSnapshotIn): void {
@@ -190,6 +211,21 @@ const Service = defineServiceModel(ServiceSettings)
190 self.state.trust = 'accepted'; 211 self.state.trust = 'accepted';
191 self.reload(); 212 self.reload();
192 }, 213 },
214 followPopup(url: string): void {
215 if (self.dismissPopup(url)) {
216 self.go(url);
217 }
218 },
219 openPopupInExternalBrowser(url: string): void {
220 if (self.dismissPopup(url)) {
221 getEnv(self).openURLInExternalBrowser(url);
222 }
223 },
224 openAllPopupsInExternalBrowser(): void {
225 const env = getEnv(self);
226 self.popups.forEach((popup) => env.openURLInExternalBrowser(popup));
227 self.dismissAllPopups();
228 },
193 })) 229 }))
194 .actions((self) => ({ 230 .actions((self) => ({
195 dispatch(action: ServiceAction): void { 231 dispatch(action: ServiceAction): void {
@@ -218,6 +254,21 @@ const Service = defineServiceModel(ServiceSettings)
218 case 'open-current-url-in-external-browser': 254 case 'open-current-url-in-external-browser':
219 self.openCurrentURLInExternalBrowser(); 255 self.openCurrentURLInExternalBrowser();
220 break; 256 break;
257 case 'follow-popup':
258 self.followPopup(action.url);
259 break;
260 case 'open-popup-in-external-browser':
261 self.openPopupInExternalBrowser(action.url);
262 break;
263 case 'open-all-popups-in-external-browser':
264 self.openAllPopupsInExternalBrowser();
265 break;
266 case 'dismiss-popup':
267 self.dismissPopup(action.url);
268 break;
269 case 'dismiss-all-popups':
270 self.dismissAllPopups();
271 break;
221 default: 272 default:
222 log.error('Unknown action to dispatch', action); 273 log.error('Unknown action to dispatch', action);
223 break; 274 break;