/**
* 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 : {}))));