/** * EventBus - ระบบจัดการเหตุการณ์ * ใช้สำหรับเชื่อมโยงการสื่อสารระหว่างโมดูลต่างๆ */ (function(global) { 'use strict'; /** * คลาส EventBus * จัดการการส่งและรับเหตุการณ์ระหว่างโมดูล */ class EventBus { constructor() { this.events = {}; this.history = []; this.maxHistorySize = 100; } /** * ลงทะเบียนฟังเหตุการณ์ * @param {string} event - ชื่อเหตุการณ์ * @param {function} callback - ฟังก์ชันที่จะเรียกเมื่อเหตุการณ์เกิดขึ้น * @param {object} context - บริบทสำหรับฟังก์ชัน (optional) * @returns {object} ออบเจกต์สำหรับยกเลิกการลงทะเบียน */ on(event, callback, context = null) { if (!this.events[event]) { this.events[event] = []; } const listener = { callback, context, id: this.generateId() }; this.events[event].push(listener); // ส่งคืนออบเจกต์สำหรับยกเลิกการลงทะเบียน return { off: () => { this.off(event, callback, context); } }; } /** * ลงทะเบียนฟังเหตุการณ์ (ครั้งเดียว) * @param {string} event - ชื่อเหตุการณ์ * @param {function} callback - ฟังก์ชันที่จะเรียกเมื่อเหตุการณ์เกิดขึ้น * @param {object} context - บริบทสำหรับฟังก์ชัน (optional) * @returns {object} ออบเจกต์สำหรับยกเลิกการลงทะเบียน */ once(event, callback, context = null) { const onceCallback = (data) => { this.off(event, onceCallback, context); callback.call(context, data); }; return this.on(event, onceCallback, context); } /** * ยกเลิกการลงทะเบียนฟังเหตุการณ์ * @param {string} event - ชื่อเหตุการณ์ * @param {function} callback - ฟังก์ชันที่จะยกเลิก * @param {object} context - บริบทสำหรับฟังก์ชัน (optional) */ off(event, callback, context = null) { if (!this.events[event]) return; this.events[event] = this.events[event].filter(listener => { return listener.callback !== callback || listener.context !== context; }); // ลบเหตุการณ์ถ้าไม่มีผู้ฟัง if (this.events[event].length === 0) { delete this.events[event]; } } /** * ส่งเหตุการณ์ * @param {string} event - ชื่อเหตุการณ์ * @param {*} data - ข้อมูลที่จะส่งไปกับเหตุการณ์ * @param {boolean} async - ส่งแบบอะซิงโครนัสหรือไม่ (default: true) */ emit(event, data = {}, async = true) { // บันทึกประวัติเหตุการณ์ this.recordEvent(event, data); if (!this.events[event]) return; const listeners = [...this.events[event]]; // สำเนาเพื่อป้องกันการแก้ไขระหว่างการวนซ้ำ if (async) { // ส่งแบบอะซิงโครนัส setTimeout(() => { listeners.forEach(listener => { try { listener.callback.call(listener.context, data); } catch (error) { console.error(`Error in event listener for '${event}':`, error); } }); }, 0); } else { // ส่งแบบซิงโครนัส listeners.forEach(listener => { try { listener.callback.call(listener.context, data); } catch (error) { console.error(`Error in event listener for '${event}':`, error); } }); } } /** * บันทึกประวัติเหตุการณ์ * @param {string} event - ชื่อเหตุการณ์ * @param {*} data - ข้อมูลที่ส่งไปกับเหตุการณ์ */ recordEvent(event, data) { this.history.push({ event, data, timestamp: new Date() }); // จำกัดขนาดประวัติ if (this.history.length > this.maxHistorySize) { this.history.shift(); } } /** * รับประวัติเหตุการณ์ * @param {string} event - ชื่อเหตุการณ์ (optional) * @returns {array} ประวัติเหตุการณ์ */ getHistory(event = null) { if (event) { return this.history.filter(item => item.event === event); } return [...this.history]; // ส่งคืนสำเนา } /** * ล้างประวัติเหตุการณ์ * @param {string} event - ชื่อเหตุการณ์ (optional) */ clearHistory(event = null) { if (event) { this.history = this.history.filter(item => item.event !== event); } else { this.history = []; } } /** * สร้าง ID สำหรับ listener * @returns {string} ID ที่ไม่ซ้ำกัน */ generateId() { return 'listener_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); } /** * รับจำนวนผู้ฟังสำหรับเหตุการณ์ * @param {string} event - ชื่อเหตุการณ์ * @returns {number} จำนวนผู้ฟัง */ listenerCount(event) { return this.events[event] ? this.events[event].length : 0; } /** * รับชื่อเหตุการณ์ทั้งหมด * @returns {array} ชื่อเหตุการณ์ทั้งหมด */ eventNames() { return Object.keys(this.events); } /** * ล้างผู้ฟังทั้งหมด * @param {string} event - ชื่อเหตุการณ์ (optional) */ removeAllListeners(event = null) { if (event) { delete this.events[event]; } else { this.events = {}; } } } // เปิดเผยคลาส EventBus ทั่วโลก global.EventBus = EventBus; })(typeof globalThis !== 'undefined' ? globalThis : (typeof window !== 'undefined' ? window : (typeof global !== 'undefined' ? global : (typeof self !== 'undefined' ? self : {}))));