@samitouri / QOSami-HFS / commits / 95a5ef7f

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)