fix: on firefox, click zip, click select-some-files: dialog cannot be closed, sometimes
Massimo Melina committed
Dec 5, 2024 at 15:17 UTC
95a5ef7fd827256205bf121d78b508258b241a5c
2 files changed
+10
-7
frontend/src/UserPanel.ts
+2
-2
@@ -11,7 +11,7 @@ import { formatTimestamp, hIcon, fallbackToBasicAuth, working } from './misc'
11
import { t } from './i18n'
12
13
export default function showUserPanel() {
14
- newDialog({
14
+ const { close } = newDialog({
15
title: t`User panel`,
16
className: 'user-dialog',
17
icon: () => hIcon('user'),
@@ -51,7 +51,7 @@ export default function showUserPanel() {
51
onClick() {
52
if (fallbackToBasicAuth()) // this is effective on ff52, but not on chrome125
53
return location.href = `//LOGOUT%00:@${location.host}/?get=logout` // redirect, to execute the body content
54
- logout().then(closeDialog, alertDialog)
54
+ logout().then(close, alertDialog)
55
}
56
})
57
)
shared/dialogs.ts
+8
-5
@@ -69,12 +69,13 @@ export function isDescendant(child: Node | null | undefined, parentMatch: Node |
69
return false
70
}
71
72
+let waitClosing = Promise.resolve()
73
let ignorePopState = false
74
function back() {
75
ignorePopState = true
76
let was = history.state
77
history.back()
77
- return new Promise<void>(res => {
78
+ return waitClosing = new Promise<void>(res => {
79
const h = setInterval(() => was !== history.state && res() , 10)
80
setTimeout(() => clearTimeout(h), 500)
81
})
@@ -184,17 +185,19 @@ export function newDialog(options: DialogOptions) {
185
options.ts = ts
186
if (document.activeElement)
187
options.restoreFocus ??= ref(document.activeElement)
187
- options = objSameKeys(options, x => isValidElement(x) ? ref(x) : x) as typeof options // encapsulate elements as react will try to write, but valtio makes them readonly
188
- options.$opening = setTimeout(() => { // in case dialogs were just closed, account for window.history delay. This should be harmless as ux is unaffected, and programmatically you already didn't expect this to happen immediately but at state change
188
+ options = objSameKeys(options, x => isValidElement(x) ? ref(x) : x) as typeof options // encapsulate elements as React will try to write, but valtio makes them readonly
189
+ let cancelOpening = false
190
+ waitClosing.then(() => { // in case dialogs were just closed, account for window.history delay. You already didn't expect dialog to open immediately, but at state change
191
+ if (cancelOpening) return
192
dialogs.push(options)
193
options = dialogs[dialogs.length - 1] // replace with proxy object, to stay in sync with its changes
194
if (options.closable !== false)
195
history.pushState({ $dialog: $id, ts, idx: 1 + (history.state?.idx || 0) }, '')
193
- }, 10) // 10 for firefox, chrome125 seems to be ok with 1
196
+ })
197
return { close }
198
199
function close(v?:any) {
197
- clearTimeout(options.$opening) // in case it was not open yet
200
+ cancelOpening = true // in case it was not open yet
201
const i = dialogs.findIndex(x => (x as any).$id === $id)
202
if (i < 0) return
203
if (history.state?.$dialog === $id)