enhance: use EventName on window's once and remove listener before calling handler (#10246)

* Refactor

* Revert event => void

* Change file
This commit is contained in:
Tony 2024-07-11 00:59:01 +08:00 committed by GitHub
parent 57612ab249
commit 080b6e1272
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 51 additions and 31 deletions

View File

@ -0,0 +1,5 @@
---
'@tauri-apps/api': 'patch:bug'
---
Fix `once` doesn't detached after one callback if event handler throws

View File

@ -0,0 +1,5 @@
---
'@tauri-apps/api': 'patch:enhance'
---
Use `EventName` on `Window`, `Webview` and `WebviewWindow`'s `once` so you can get auto complete for tauri's built-in events

File diff suppressed because one or more lines are too long

View File

@ -152,8 +152,9 @@ async function once<T>(
return listen<T>(
event,
(eventData) => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
_unlisten(event, eventData.id)
handler(eventData)
_unlisten(event, eventData.id).catch(() => {})
},
options
)

View File

@ -225,11 +225,11 @@ class Webview {
handler: EventCallback<T>
): Promise<UnlistenFn> {
if (this._handleTauriEvent(event, handler)) {
return Promise.resolve(() => {
return () => {
// eslint-disable-next-line security/detect-object-injection
const listeners = this.listeners[event]
listeners.splice(listeners.indexOf(handler), 1)
})
}
}
return listen(event, handler, {
target: { kind: 'Webview', label: this.label }
@ -255,13 +255,16 @@ class Webview {
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
async once<T>(event: string, handler: EventCallback<T>): Promise<UnlistenFn> {
async once<T>(
event: EventName,
handler: EventCallback<T>
): Promise<UnlistenFn> {
if (this._handleTauriEvent(event, handler)) {
return Promise.resolve(() => {
return () => {
// eslint-disable-next-line security/detect-object-injection
const listeners = this.listeners[event]
listeners.splice(listeners.indexOf(handler), 1)
})
}
}
return once(event, handler, {
target: { kind: 'Webview', label: this.label }
@ -290,7 +293,7 @@ class Webview {
payload
})
}
return Promise.resolve()
return
}
return emit(event, payload)
}
@ -322,7 +325,7 @@ class Webview {
payload
})
}
return Promise.resolve()
return
}
return emitTo(target, event, payload)
}
@ -331,10 +334,10 @@ class Webview {
_handleTauriEvent<T>(event: string, handler: EventCallback<T>): boolean {
if (localTauriEvents.includes(event)) {
if (!(event in this.listeners)) {
// eslint-disable-next-line
// eslint-disable-next-line security/detect-object-injection
this.listeners[event] = [handler]
} else {
// eslint-disable-next-line
// eslint-disable-next-line security/detect-object-injection
this.listeners[event].push(handler)
}
return true

View File

@ -155,11 +155,11 @@ class WebviewWindow {
handler: EventCallback<T>
): Promise<UnlistenFn> {
if (this._handleTauriEvent(event, handler)) {
return Promise.resolve(() => {
return () => {
// eslint-disable-next-line security/detect-object-injection
const listeners = this.listeners[event]
listeners.splice(listeners.indexOf(handler), 1)
})
}
}
return listen(event, handler, {
target: { kind: 'WebviewWindow', label: this.label }
@ -185,13 +185,16 @@ class WebviewWindow {
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
async once<T>(event: string, handler: EventCallback<T>): Promise<UnlistenFn> {
async once<T>(
event: EventName,
handler: EventCallback<T>
): Promise<UnlistenFn> {
if (this._handleTauriEvent(event, handler)) {
return Promise.resolve(() => {
return () => {
// eslint-disable-next-line security/detect-object-injection
const listeners = this.listeners[event]
listeners.splice(listeners.indexOf(handler), 1)
})
}
}
return once(event, handler, {
target: { kind: 'WebviewWindow', label: this.label }

View File

@ -105,7 +105,7 @@ class CloseRequestedEvent {
id: number
private _preventDefault = false
constructor(event: Event<null>) {
constructor(event: Event<unknown>) {
this.event = event.event
this.id = event.id
}
@ -373,11 +373,11 @@ class Window {
handler: EventCallback<T>
): Promise<UnlistenFn> {
if (this._handleTauriEvent(event, handler)) {
return Promise.resolve(() => {
return () => {
// eslint-disable-next-line security/detect-object-injection
const listeners = this.listeners[event]
listeners.splice(listeners.indexOf(handler), 1)
})
}
}
return listen(event, handler, {
target: { kind: 'Window', label: this.label }
@ -403,13 +403,16 @@ class Window {
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
async once<T>(event: string, handler: EventCallback<T>): Promise<UnlistenFn> {
async once<T>(
event: EventName,
handler: EventCallback<T>
): Promise<UnlistenFn> {
if (this._handleTauriEvent(event, handler)) {
return Promise.resolve(() => {
return () => {
// eslint-disable-next-line security/detect-object-injection
const listeners = this.listeners[event]
listeners.splice(listeners.indexOf(handler), 1)
})
}
}
return once(event, handler, {
target: { kind: 'Window', label: this.label }
@ -437,7 +440,7 @@ class Window {
payload
})
}
return Promise.resolve()
return
}
return emit(event, payload)
}
@ -460,7 +463,7 @@ class Window {
payload?: unknown
): Promise<void> {
if (localTauriEvents.includes(event)) {
// eslint-disable-next-line
// eslint-disable-next-line security/detect-object-injection
for (const handler of this.listeners[event] || []) {
handler({
event,
@ -468,7 +471,7 @@ class Window {
payload
})
}
return Promise.resolve()
return
}
return emitTo(target, event, payload)
}
@ -1710,14 +1713,14 @@ class Window {
async onCloseRequested(
handler: (event: CloseRequestedEvent) => void | Promise<void>
): Promise<UnlistenFn> {
return this.listen<null>(TauriEvent.WINDOW_CLOSE_REQUESTED, (event) => {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
return this.listen(TauriEvent.WINDOW_CLOSE_REQUESTED, async (event) => {
const evt = new CloseRequestedEvent(event)
void Promise.resolve(handler(evt)).then(() => {
await handler(evt)
if (!evt.isPreventDefault()) {
return this.destroy()
await this.destroy()
}
})
})
}
/**