github.com/secoba/wails/v2@v2.6.4/internal/frontend/runtime/desktop/events.js (about) 1 /* 2 _ __ _ __ 3 | | / /___ _(_) /____ 4 | | /| / / __ `/ / / ___/ 5 | |/ |/ / /_/ / / (__ ) 6 |__/|__/\__,_/_/_/____/ 7 The electron alternative for Go 8 (c) Lea Anthony 2019-present 9 */ 10 /* jshint esversion: 6 */ 11 12 // Defines a single listener with a maximum number of times to callback 13 14 /** 15 * The Listener class defines a listener! :-) 16 * 17 * @class Listener 18 */ 19 class Listener { 20 /** 21 * Creates an instance of Listener. 22 * @param {string} eventName 23 * @param {function} callback 24 * @param {number} maxCallbacks 25 * @memberof Listener 26 */ 27 constructor(eventName, callback, maxCallbacks) { 28 this.eventName = eventName; 29 // Default of -1 means infinite 30 this.maxCallbacks = maxCallbacks || -1; 31 // Callback invokes the callback with the given data 32 // Returns true if this listener should be destroyed 33 this.Callback = (data) => { 34 callback.apply(null, data); 35 // If maxCallbacks is infinite, return false (do not destroy) 36 if (this.maxCallbacks === -1) { 37 return false; 38 } 39 // Decrement maxCallbacks. Return true if now 0, otherwise false 40 this.maxCallbacks -= 1; 41 return this.maxCallbacks === 0; 42 }; 43 } 44 } 45 46 export const eventListeners = {}; 47 48 /** 49 * Registers an event listener that will be invoked `maxCallbacks` times before being destroyed 50 * 51 * @export 52 * @param {string} eventName 53 * @param {function} callback 54 * @param {number} maxCallbacks 55 * @returns {function} A function to cancel the listener 56 */ 57 export function EventsOnMultiple(eventName, callback, maxCallbacks) { 58 eventListeners[eventName] = eventListeners[eventName] || []; 59 const thisListener = new Listener(eventName, callback, maxCallbacks); 60 eventListeners[eventName].push(thisListener); 61 return () => listenerOff(thisListener); 62 } 63 64 /** 65 * Registers an event listener that will be invoked every time the event is emitted 66 * 67 * @export 68 * @param {string} eventName 69 * @param {function} callback 70 * @returns {function} A function to cancel the listener 71 */ 72 export function EventsOn(eventName, callback) { 73 return EventsOnMultiple(eventName, callback, -1); 74 } 75 76 /** 77 * Registers an event listener that will be invoked once then destroyed 78 * 79 * @export 80 * @param {string} eventName 81 * @param {function} callback 82 * @returns {function} A function to cancel the listener 83 */ 84 export function EventsOnce(eventName, callback) { 85 return EventsOnMultiple(eventName, callback, 1); 86 } 87 88 function notifyListeners(eventData) { 89 90 // Get the event name 91 let eventName = eventData.name; 92 93 // Check if we have any listeners for this event 94 if (eventListeners[eventName]) { 95 96 // Keep a list of listener indexes to destroy 97 const newEventListenerList = eventListeners[eventName].slice(); 98 99 // Iterate listeners 100 for (let count = eventListeners[eventName].length - 1; count >= 0; count -= 1) { 101 102 // Get next listener 103 const listener = eventListeners[eventName][count]; 104 105 let data = eventData.data; 106 107 // Do the callback 108 const destroy = listener.Callback(data); 109 if (destroy) { 110 // if the listener indicated to destroy itself, add it to the destroy list 111 newEventListenerList.splice(count, 1); 112 } 113 } 114 115 // Update callbacks with new list of listeners 116 if (newEventListenerList.length === 0) { 117 removeListener(eventName); 118 } else { 119 eventListeners[eventName] = newEventListenerList; 120 } 121 } 122 } 123 124 /** 125 * Notify informs frontend listeners that an event was emitted with the given data 126 * 127 * @export 128 * @param {string} notifyMessage - encoded notification message 129 130 */ 131 export function EventsNotify(notifyMessage) { 132 // Parse the message 133 let message; 134 try { 135 message = JSON.parse(notifyMessage); 136 } catch (e) { 137 const error = 'Invalid JSON passed to Notify: ' + notifyMessage; 138 throw new Error(error); 139 } 140 notifyListeners(message); 141 } 142 143 /** 144 * Emit an event with the given name and data 145 * 146 * @export 147 * @param {string} eventName 148 */ 149 export function EventsEmit(eventName) { 150 151 const payload = { 152 name: eventName, 153 data: [].slice.apply(arguments).slice(1), 154 }; 155 156 // Notify JS listeners 157 notifyListeners(payload); 158 159 // Notify Go listeners 160 window.WailsInvoke('EE' + JSON.stringify(payload)); 161 } 162 163 function removeListener(eventName) { 164 // Remove local listeners 165 delete eventListeners[eventName]; 166 167 // Notify Go listeners 168 window.WailsInvoke('EX' + eventName); 169 } 170 171 /** 172 * Off unregisters a listener previously registered with On, 173 * optionally multiple listeneres can be unregistered via `additionalEventNames` 174 * 175 * @param {string} eventName 176 * @param {...string} additionalEventNames 177 */ 178 export function EventsOff(eventName, ...additionalEventNames) { 179 removeListener(eventName) 180 181 if (additionalEventNames.length > 0) { 182 additionalEventNames.forEach(eventName => { 183 removeListener(eventName) 184 }) 185 } 186 } 187 188 /** 189 * Off unregisters all event listeners previously registered with On 190 */ 191 export function EventsOffAll() { 192 const eventNames = Object.keys(eventListeners); 193 for (let i = 0; i !== eventNames.length; i++) { 194 removeListener(eventNames[i]); 195 } 196 } 197 198 /** 199 * listenerOff unregisters a listener previously registered with EventsOn 200 * 201 * @param {Listener} listener 202 */ 203 function listenerOff(listener) { 204 const eventName = listener.eventName; 205 // Remove local listener 206 eventListeners[eventName] = eventListeners[eventName].filter(l => l !== listener); 207 208 // Clean up if there are no event listeners left 209 if (eventListeners[eventName].length === 0) { 210 removeListener(eventName); 211 } 212 }