5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-02 05:11:29 +08:00
wails/v2/internal/frontend/runtime/desktop/events.js
2025-02-16 16:13:00 +11:00

215 lines
5.8 KiB
JavaScript

/*
_ __ _ __
| | / /___ _(_) /____
| | /| / / __ `/ / / ___/
| |/ |/ / /_/ / / (__ )
|__/|__/\__,_/_/_/____/
The electron alternative for Go
(c) Lea Anthony 2019-present
*/
/* jshint esversion: 6 */
// Defines a single listener with a maximum number of times to callback
/**
* 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.apply(null, 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;
};
}
}
export const eventListeners = {};
/**
* Registers an event listener that will be invoked `maxCallbacks` times before being destroyed
*
* @export
* @param {string} eventName
* @param {function} callback
* @param {number} maxCallbacks
* @returns {function} A function to cancel the listener
*/
export function EventsOnMultiple(eventName, callback, maxCallbacks) {
eventListeners[eventName] = eventListeners[eventName] || [];
const thisListener = new Listener(eventName, callback, maxCallbacks);
eventListeners[eventName].push(thisListener);
return () => listenerOff(thisListener);
}
/**
* Registers an event listener that will be invoked every time the event is emitted
*
* @export
* @param {string} eventName
* @param {function} callback
* @returns {function} A function to cancel the listener
*/
export function EventsOn(eventName, callback) {
return EventsOnMultiple(eventName, callback, -1);
}
/**
* Registers an event listener that will be invoked once then destroyed
*
* @export
* @param {string} eventName
* @param {function} callback
* @returns {function} A function to cancel the listener
*/
export function EventsOnce(eventName, callback) {
return EventsOnMultiple(eventName, callback, 1);
}
function notifyListeners(eventData) {
// Get the event name
let eventName = eventData.name;
// Keep a list of listener indexes to destroy
const newEventListenerList = eventListeners[eventName]?.slice() || [];
// Check if we have any listeners for this event
if (newEventListenerList.length) {
// Iterate listeners
for (let count = newEventListenerList.length - 1; count >= 0; count -= 1) {
// Get next listener
const listener = newEventListenerList[count];
let data = eventData.data;
// Do the callback
const destroy = listener.Callback(data);
if (destroy) {
// if the listener indicated to destroy itself, add it to the destroy list
newEventListenerList.splice(count, 1);
}
}
// Update callbacks with new list of listeners
if (newEventListenerList.length === 0) {
removeListener(eventName);
} else {
eventListeners[eventName] = newEventListenerList;
}
}
}
/**
* Notify informs frontend listeners that an event was emitted with the given data
*
* @export
* @param {string} notifyMessage - encoded notification message
*/
export function EventsNotify(notifyMessage) {
// Parse the message
let message;
try {
message = JSON.parse(notifyMessage);
} catch (e) {
const error = 'Invalid JSON passed to Notify: ' + notifyMessage;
throw new Error(error);
}
notifyListeners(message);
}
/**
* Emit an event with the given name and data
*
* @export
* @param {string} eventName
*/
export function EventsEmit(eventName) {
const payload = {
name: eventName,
data: [].slice.apply(arguments).slice(1),
};
// Notify JS listeners
notifyListeners(payload);
// Notify Go listeners
window.WailsInvoke('EE' + JSON.stringify(payload));
}
function removeListener(eventName) {
// Remove local listeners
delete eventListeners[eventName];
// Notify Go listeners
window.WailsInvoke('EX' + eventName);
}
/**
* Off unregisters a listener previously registered with On,
* optionally multiple listeneres can be unregistered via `additionalEventNames`
*
* @param {string} eventName
* @param {...string} additionalEventNames
*/
export function EventsOff(eventName, ...additionalEventNames) {
removeListener(eventName)
if (additionalEventNames.length > 0) {
additionalEventNames.forEach(eventName => {
removeListener(eventName)
})
}
}
/**
* Off unregisters all event listeners previously registered with On
*/
export function EventsOffAll() {
const eventNames = Object.keys(eventListeners);
for (let i = 0; i !== eventNames.length; i++) {
removeListener(eventNames[i]);
}
}
/**
* listenerOff unregisters a listener previously registered with EventsOn
*
* @param {Listener} listener
*/
function listenerOff(listener) {
const eventName = listener.eventName;
if (eventListeners[eventName] === undefined) return;
// Remove local listener
eventListeners[eventName] = eventListeners[eventName].filter(l => l !== listener);
// Clean up if there are no event listeners left
if (eventListeners[eventName].length === 0) {
removeListener(eventName);
}
}