- Extract UI components into separate JS files - Centralize configuration values in config.js - Introduce a dedicated logger module - Improve file tree drag-and-drop and undo functionality - Refactor modal handling to a single manager - Add URL routing support for SPA navigation - Implement view mode for read-only access
		
			
				
	
	
		
			127 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			127 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * Event Bus Module
 | |
|  * Provides a centralized event system for application-wide communication
 | |
|  * Allows components to communicate without tight coupling
 | |
|  */
 | |
| 
 | |
| class EventBus {
 | |
|     constructor() {
 | |
|         /**
 | |
|          * Map of event names to arrays of listener functions
 | |
|          * @type {Object.<string, Function[]>}
 | |
|          */
 | |
|         this.listeners = {};
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Register an event listener
 | |
|      * @param {string} event - The event name to listen for
 | |
|      * @param {Function} callback - The function to call when the event is dispatched
 | |
|      * @returns {Function} A function to unregister this listener
 | |
|      */
 | |
|     on(event, callback) {
 | |
|         if (!this.listeners[event]) {
 | |
|             this.listeners[event] = [];
 | |
|         }
 | |
|         this.listeners[event].push(callback);
 | |
| 
 | |
|         // Return unsubscribe function
 | |
|         return () => this.off(event, callback);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Register a one-time event listener
 | |
|      * The listener will be automatically removed after being called once
 | |
|      * @param {string} event - The event name to listen for
 | |
|      * @param {Function} callback - The function to call when the event is dispatched
 | |
|      * @returns {Function} A function to unregister this listener
 | |
|      */
 | |
|     once(event, callback) {
 | |
|         const onceWrapper = (data) => {
 | |
|             callback(data);
 | |
|             this.off(event, onceWrapper);
 | |
|         };
 | |
|         return this.on(event, onceWrapper);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Unregister an event listener
 | |
|      * @param {string} event - The event name
 | |
|      * @param {Function} callback - The callback function to remove
 | |
|      */
 | |
|     off(event, callback) {
 | |
|         if (!this.listeners[event]) {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         this.listeners[event] = this.listeners[event].filter(
 | |
|             listener => listener !== callback
 | |
|         );
 | |
| 
 | |
|         // Clean up empty listener arrays
 | |
|         if (this.listeners[event].length === 0) {
 | |
|             delete this.listeners[event];
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Dispatch an event to all registered listeners
 | |
|      * @param {string} event - The event name to dispatch
 | |
|      * @param {any} data - The data to pass to the listeners
 | |
|      */
 | |
|     dispatch(event, data) {
 | |
|         if (!this.listeners[event]) {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         // Create a copy of the listeners array to avoid issues if listeners are added/removed during dispatch
 | |
|         const listeners = [...this.listeners[event]];
 | |
|         
 | |
|         listeners.forEach(callback => {
 | |
|             try {
 | |
|                 callback(data);
 | |
|             } catch (error) {
 | |
|                 Logger.error(`Error in event listener for "${event}":`, error);
 | |
|             }
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Remove all listeners for a specific event
 | |
|      * If no event is specified, removes all listeners for all events
 | |
|      * @param {string} [event] - The event name (optional)
 | |
|      */
 | |
|     clear(event) {
 | |
|         if (event) {
 | |
|             delete this.listeners[event];
 | |
|         } else {
 | |
|             this.listeners = {};
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get the number of listeners for an event
 | |
|      * @param {string} event - The event name
 | |
|      * @returns {number} The number of listeners
 | |
|      */
 | |
|     listenerCount(event) {
 | |
|         return this.listeners[event] ? this.listeners[event].length : 0;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get all event names that have listeners
 | |
|      * @returns {string[]} Array of event names
 | |
|      */
 | |
|     eventNames() {
 | |
|         return Object.keys(this.listeners);
 | |
|     }
 | |
| }
 | |
| 
 | |
| // Create and export the global event bus instance
 | |
| const eventBus = new EventBus();
 | |
| 
 | |
| // Make it globally available
 | |
| window.eventBus = eventBus;
 | |
| window.EventBus = EventBus;
 | |
| 
 |