5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-02 21:29:09 +08:00
wails/v3/internal/runtime/desktop/events.js
2023-03-31 20:37:50 +11:00

192 lines
5.1 KiB
JavaScript

/*
_ __ _ __
| | / /___ _(_) /____
| | /| / / __ `/ / / ___/
| |/ |/ / /_/ / / (__ )
|__/|__/\__,_/_/_/____/
The electron alternative for Go
(c) Lea Anthony 2019-present
*/
/* jshint esversion: 9 */
/**
* @typedef {import("./api/types").CustomEvent} CustomEvent
*/
import {newRuntimeCaller} from "./runtime";
let call = newRuntimeCaller("events");
/**
* The Listener class defines a listener! :-)
*
* @class Listener
*/
class Listener {
/**
* Creates an instance of Listener.
* @param {string} eventName
* @param {function} callback
* @param {number} maxCallbacks
* @memberof Listener
*/
constructor(eventName, callback, maxCallbacks) {
this.eventName = eventName;
// Default of -1 means infinite
this.maxCallbacks = maxCallbacks || -1;
// Callback invokes the callback with the given data
// Returns true if this listener should be destroyed
this.Callback = (data) => {
callback(data);
// If maxCallbacks is infinite, return false (do not destroy)
if (this.maxCallbacks === -1) {
return false;
}
// Decrement maxCallbacks. Return true if now 0, otherwise false
this.maxCallbacks -= 1;
return this.maxCallbacks === 0;
};
}
}
/**
* CustomEvent defines a custom event. It is passed to event listeners.
*
* @class CustomEvent
*/
export class CustomEvent {
/**
* Creates an instance of CustomEvent.
* @param {string} name - Name of the event
* @param {any} data - Data associated with the event
* @memberof CustomEvent
*/
constructor(name, data) {
this.name = name;
this.data = data;
}
}
export const eventListeners = new Map();
/**
* Registers an event listener that will be invoked `maxCallbacks` times before being destroyed
*
* @export
* @param {string} eventName
* @param {function(CustomEvent): void} callback
* @param {number} maxCallbacks
* @returns {function} A function to cancel the listener
*/
export function OnMultiple(eventName, callback, maxCallbacks) {
let listeners = eventListeners.get(eventName) || [];
const thisListener = new Listener(eventName, callback, maxCallbacks);
listeners.push(thisListener);
eventListeners.set(eventName, listeners);
return () => listenerOff(thisListener);
}
/**
* Registers an event listener that will be invoked every time the event is emitted
*
* @export
* @param {string} eventName
* @param {function(CustomEvent): void} callback
* @returns {function} A function to cancel the listener
*/
export function On(eventName, callback) {
return OnMultiple(eventName, callback, -1);
}
/**
* Registers an event listener that will be invoked once then destroyed
*
* @export
* @param {string} eventName
* @param {function(CustomEvent): void} callback
@returns {function} A function to cancel the listener
*/
export function Once(eventName, callback) {
return OnMultiple(eventName, callback, 1);
}
/**
* listenerOff unregisters a listener previously registered with On
*
* @param {Listener} listener
*/
function listenerOff(listener) {
const eventName = listener.eventName;
// Remove local listener
let listeners = eventListeners.get(eventName).filter(l => l !== listener);
if (listeners.length === 0) {
eventListeners.delete(eventName);
} else {
eventListeners.set(eventName, listeners);
}
}
/**
* dispatches an event to all listeners
*
* @export
* @param {CustomEvent} event
*/
export function dispatchCustomEvent(event) {
console.log("dispatching event: ", {event});
let listeners = eventListeners.get(event.name);
if (listeners) {
// iterate listeners and call callback. If callback returns true, remove listener
let toRemove = [];
listeners.forEach(listener => {
let remove = listener.Callback(event);
if (remove) {
toRemove.push(listener);
}
});
// remove listeners
if (toRemove.length > 0) {
listeners = listeners.filter(l => !toRemove.includes(l));
if (listeners.length === 0) {
eventListeners.delete(event.name);
} else {
eventListeners.set(event.name, listeners);
}
}
}
}
/**
* Off unregisters a listener previously registered with On,
* optionally multiple listeners can be unregistered via `additionalEventNames`
*
[v3 CHANGE] Off only unregisters listeners within the current window
*
* @param {string} eventName
* @param {...string} additionalEventNames
*/
export function Off(eventName, ...additionalEventNames) {
let eventsToRemove = [eventName, ...additionalEventNames];
eventsToRemove.forEach(eventName => {
eventListeners.delete(eventName);
});
}
/**
* OffAll unregisters all listeners
* [v3 CHANGE] OffAll only unregisters listeners within the current window
*
*/
export function OffAll() {
eventListeners.clear();
}
/**
* Emit an event
* @param {CustomEvent} event The event to emit
*/
export function Emit(event) {
void call("Emit", event);
}