Now.js Framework Documentation

Now.js Framework Documentation

EventSystemManager - DOM Event System

TH 31 Oct 2025 01:08

EventSystemManager - DOM Event System

เอกสารสำหรับ EventSystemManager ซึ่งเป็นระบบจัดการ DOM Events แบบ High-Performance

📋 สารบัญ

  1. ภาพรวม
  2. การติดตั้งและนำเข้า
  3. การใช้งานพื้นฐาน
  4. Event Delegation
  5. Keyboard Events
  6. Window Events
  7. Performance Optimization
  8. Memory Management
  9. Priority System
  10. Configuration
  11. ตัวอย่างการใช้งาน
  12. API Reference
  13. Best Practices

ภาพรวม

EventSystemManager เป็นระบบจัดการ DOM Events ที่ออกแบบมาเพื่อประสิทธิภาพสูงสุด พร้อมคุณสมบัติขั้นสูงเหนือกว่า addEventListener ปกติ

คุณสมบัติหลัก

  • Event Delegation: จัดการ events แบบ centralized
  • Auto Cleanup: ลบ handlers อัตโนมัติเมื่อ element ถูกลบ
  • Memory Management: ตรวจสอบและจัดการหน่วยความจำ
  • Priority System: กำหนดลำดับการทำงานของ handlers
  • UI Event Optimization: ใช้ requestAnimationFrame สำหรับ UI events
  • Keyboard Event Enhancement: ข้อมูล keyboard event ที่ครบถ้วน
  • Throttle/Debounce: จำกัดอัตราการทำงานของ events
  • Component Integration: เชื่อมต่อกับ Now.js Components
  • MutationObserver: ติดตาม DOM changes
  • Performance Monitoring: วัดและติดตามประสิทธิภาพ

ความแตกต่างจาก EventManager

คุณสมบัติ EventSystemManager EventManager
จุดประสงค์ DOM Events Application Events
API หลัก addHandler(), removeHandler() on(), emit(), off()
Event Types DOM events (click, submit, etc.) Custom events
Target DOM elements Application logic
Event Delegation ✅ รองรับ ❌ ไม่รองรับ
Auto Cleanup ✅ รองรับ ⚠️ Manual
Memory Monitoring ✅ รองรับ ❌ ไม่รองรับ
UI Optimization ✅ requestAnimationFrame ❌ ไม่รองรับ

เมื่อใดควรใช้ EventSystemManager

ใช้ EventSystemManager เมื่อ:

  • ต้องการจัดการ DOM Events (click, submit, input, etc.)
  • ต้องการ Event Delegation
  • ต้องการ Auto Cleanup เมื่อ element ถูกลบ
  • ต้องการ Performance Optimization
  • ต้องการ Memory Management อัตโนมัติ
  • ต้องการ Priority-based event handling

อย่าใช้ EventSystemManager เมื่อ:

  • ต้องการ Custom Application Events (ใช้ EventManager)
  • ต้องการ Pattern Matching (ใช้ EventManager)
  • ต้องการ Middleware (ใช้ EventManager)
  • ต้องการ Event Groups (ใช้ EventManager)

การติดตั้งและนำเข้า

EventSystemManager โหลดพร้อมกับ Now.js Framework และเริ่มต้นอัตโนมัติ:

// ไม่ต้อง import - พร้อมใช้งานทันที
console.log(window.EventSystemManager); // EventSystemManager object

// เข้าถึงผ่าน Now.js
const eventSystem = Now.getManager('eventsystem');

Dependencies

EventSystemManager ต้องการ dependencies เหล่านี้:

  • ErrorManager - สำหรับจัดการข้อผิดพลาด

การเริ่มต้นใช้งาน

EventSystemManager เริ่มต้นอัตโนมัติเมื่อโหลด Now.js:

// Auto-initialized
EventSystemManager.init();

// หรือ init พร้อม custom config
EventSystemManager.init({
  delegation: {
    enabled: true,
    maxDelegationDepth: 10
  },
  memoryManagement: {
    maxHandlersPerElement: 100,
    maxCacheSize: 1000
  }
});

การใช้งานพื้นฐาน

1. Add Event Handler

// พื้นฐาน
const element = document.querySelector('#my-button');
const handlerId = EventSystemManager.addHandler(element, 'click', (event) => {
  console.log('Button clicked!', event);
});

// พร้อม options
const id = EventSystemManager.addHandler(element, 'click', (event) => {
  console.log('Clicked:', event.target);
}, {
  capture: false,
  once: false,
  passive: true,
  priority: 10
});

2. Remove Event Handler

// ลบโดยใช้ handler ID
EventSystemManager.removeHandler(handlerId);

// ลบทุก handlers ของ component
EventSystemManager.removeComponentHandlers('my-component-id');

3. Window Events

// Window events จัดการอัตโนมัติ
EventSystemManager.addHandler(window, 'resize', (event) => {
  console.log('Window resized');
});

EventSystemManager.addHandler(window, 'scroll', (event) => {
  console.log('Window scrolled');
});

4. Document Events

// Document events
EventSystemManager.addHandler(document, 'click', (event) => {
  console.log('Document clicked');
});

Event Delegation

Event Delegation ช่วยให้จัดการ events ของ child elements ได้จาก parent

Basic Delegation

// จับ click บน child elements ที่ตรงกับ selector
const container = document.querySelector('#container');

EventSystemManager.addHandler(container, 'click', (event) => {
  console.log('Button clicked:', event.delegateTarget);
}, {
  selector: '.item-button' // จะทำงานเฉพาะ .item-button ภายใน container
});

Use Cases สำหรับ Delegation

1. Dynamic Lists

// List ที่มี items เพิ่ม-ลบได้
const list = document.querySelector('#todo-list');

// จัดการ click บน delete buttons
EventSystemManager.addHandler(list, 'click', (event) => {
  const item = event.delegateTarget;
  const itemId = item.dataset.id;
  deleteItem(itemId);
}, {
  selector: '.delete-button'
});

// จัดการ click บน checkbox
EventSystemManager.addHandler(list, 'click', (event) => {
  const checkbox = event.delegateTarget;
  toggleItemComplete(checkbox);
}, {
  selector: '.item-checkbox'
});

2. Tables

// จัดการ click บน table rows
const table = document.querySelector('#data-table');

EventSystemManager.addHandler(table, 'click', (event) => {
  const row = event.delegateTarget;
  const rowId = row.dataset.id;
  showRowDetails(rowId);
}, {
  selector: 'tbody tr'
});

// จัดการ click บน edit buttons
EventSystemManager.addHandler(table, 'click', (event) => {
  const button = event.delegateTarget;
  const rowId = button.closest('tr').dataset.id;
  editRow(rowId);
}, {
  selector: '.edit-button'
});

3. Modal/Dialog

// จัดการ click บน backdrop เพื่อปิด modal
EventSystemManager.addHandler(document.body, 'click', (event) => {
  if (event.delegateTarget.classList.contains('modal-backdrop')) {
    closeModal();
  }
}, {
  selector: '.modal-backdrop'
});

Keyboard Events

EventSystemManager มี keyboard event enhancement พิเศษ

Enhanced Keyboard Events

EventSystemManager.addHandler(input, 'keydown', (event) => {
  const enhanced = event.originalEvent._enhanced;

  console.log('Key:', enhanced.key);
  console.log('Code:', enhanced.code);

  // Helper properties
  if (enhanced.isEnter) {
    console.log('Enter pressed');
  }

  if (enhanced.isShiftEnter) {
    console.log('Shift+Enter pressed');
  }

  if (enhanced.isCtrlEnter) {
    console.log('Ctrl+Enter pressed');
  }

  if (enhanced.isTab) {
    console.log('Tab pressed');
  }

  if (enhanced.isShiftTab) {
    console.log('Shift+Tab pressed');
  }

  if (enhanced.isArrowKey) {
    console.log('Arrow key pressed:', enhanced.key);
  }

  // Modifiers
  if (enhanced.ctrlKey) console.log('Ctrl is held');
  if (enhanced.altKey) console.log('Alt is held');
  if (enhanced.shiftKey) console.log('Shift is held');
  if (enhanced.metaKey) console.log('Meta/Cmd is held');
});

Keyboard Shortcuts

// Submit form with Ctrl+Enter
EventSystemManager.addHandler(textarea, 'keydown', (event) => {
  const enhanced = event.originalEvent._enhanced;

  if (enhanced.isCtrlEnter) {
    event.preventDefault();
    submitForm();
  }
});

// Tab navigation with Shift+Tab
EventSystemManager.addHandler(form, 'keydown', (event) => {
  const enhanced = event.originalEvent._enhanced;

  if (enhanced.isShiftTab) {
    // Custom tab navigation
    navigateToPreviousField();
  }
});

// Close on Escape
EventSystemManager.addHandler(document, 'keydown', (event) => {
  if (event.key === 'Escape') {
    closeAllModals();
  }
});

Window Events

จัดการ window-level events เช่น resize, scroll, popstate

Supported Window Events

// Resize
EventSystemManager.addHandler(window, 'resize', (event) => {
  console.log('Window resized');
  handleResize();
});

// Scroll
EventSystemManager.addHandler(window, 'scroll', (event) => {
  console.log('Window scrolled');
  handleScroll();
});

// Popstate (history navigation)
EventSystemManager.addHandler(window, 'popstate', (event) => {
  console.log('History state changed');
  handlePopState(event);
});

// Hashchange
EventSystemManager.addHandler(window, 'hashchange', (event) => {
  console.log('Hash changed');
  handleHashChange();
});

// Load
EventSystemManager.addHandler(window, 'load', (event) => {
  console.log('Window loaded');
  initialize();
});

// Online/Offline
EventSystemManager.addHandler(window, 'online', (event) => {
  console.log('Connection restored');
  syncData();
});

EventSystemManager.addHandler(window, 'offline', (event) => {
  console.log('Connection lost');
  showOfflineMessage();
});

Performance Optimization

EventSystemManager มีกลไกเพิ่มประสิทธิภาพหลายอย่าง

UI Event Optimization

UI events (resize, scroll, mousemove) ใช้ requestAnimationFrame:

// Optimized automatically
EventSystemManager.addHandler(window, 'scroll', (event) => {
  // ทำงานใน requestAnimationFrame
  updateScrollPosition();
});

EventSystemManager.addHandler(window, 'resize', (event) => {
  // Batched ใน requestAnimationFrame
  recalculateLayout();
});

EventSystemManager.addHandler(element, 'mousemove', (event) => {
  // Queued และประมวลผลรวมกัน
  updateMousePosition(event);
});

Throttle และ Debounce

// Throttle - จำกัดอัตราการทำงาน
let lastTime = 0;
EventSystemManager.addHandler(window, 'scroll', (event) => {
  const now = Date.now();
  if (now - lastTime < 100) return; // throttle 100ms

  lastTime = now;
  handleScroll();
});

// Debounce - รอให้หยุดแล้วค่อยทำงาน
let debounceTimer;
EventSystemManager.addHandler(window, 'resize', (event) => {
  clearTimeout(debounceTimer);
  debounceTimer = setTimeout(() => {
    handleResize();
  }, 200); // debounce 200ms
});

Event Filtering

EventSystemManager มี built-in event filtering:

// Configuration
EventSystemManager.config.filtering = {
  enabled: true,
  maxThrottleRate: 60, // events per second
  debounceWait: 100,
  highFrequencyEvents: new Set([
    'mousemove',
    'scroll',
    'resize',
    'touchmove',
    'pointermove'
  ])
};

Memory Management

EventSystemManager จัดการหน่วยความจำอัตโนมัติ

Auto Cleanup

// Handlers ถูกลบอัตโนมัติเมื่อ element ถูกลบจาก DOM
const element = document.createElement('div');
document.body.appendChild(element);

const id = EventSystemManager.addHandler(element, 'click', handler);

// ลบ element - handler ถูกลบอัตโนมัติ
element.remove();

Manual Cleanup

// ลบ handler เฉพาะ
EventSystemManager.removeHandler(handlerId);

// ลบทุก handlers ของ component
EventSystemManager.removeComponentHandlers('component-id');

// Cleanup ทั้งหมด
EventSystemManager.cleanup();

// Destroy
EventSystemManager.destroy();

Memory Monitoring

// ตรวจสอบ memory usage
const stats = EventSystemManager.gatherMemoryStats();
console.log('Handlers:', stats.handlerCount);
console.log('Cache size:', stats.cacheSize);
console.log('WeakMap size:', stats.weakMapSize);

// Memory stats
console.log(EventSystemManager.state.memoryStats);
// {
//   handlerCount: 42,
//   cacheSize: 15,
//   weakMapSize: 8,
//   lastGC: 1698765432100,
//   peakMemoryUsage: 50,
//   memoryWarnings: 0
// }

Garbage Collection

// Manual GC trigger
EventSystemManager.performGC();

// Auto GC configuration
EventSystemManager.config.memoryManagement = {
  checkInterval: 30000,      // ตรวจสอบทุก 30 วินาที
  maxHandlersPerElement: 100, // handlers สูงสุดต่อ element
  maxCacheSize: 1000,        // cache size สูงสุด
  gcThreshold: 0.8,          // trigger GC ที่ 80%
  detailedTracking: true     // เปิด detailed logging
};

Priority System

กำหนดลำดับการทำงานของ handlers

Priority Values

// Priority สูง - ทำก่อน
EventSystemManager.addHandler(element, 'click', validationHandler, {
  priority: 100
});

// Priority กลาง
EventSystemManager.addHandler(element, 'click', transformHandler, {
  priority: 50
});

// Priority ต่ำ - ทำหลัง
EventSystemManager.addHandler(element, 'click', submitHandler, {
  priority: 10
});

// Default priority (0) - ทำหลังสุด
EventSystemManager.addHandler(element, 'click', loggingHandler);

Use Cases สำหรับ Priority

1. Form Validation Pipeline

// Validate ก่อน
EventSystemManager.addHandler(form, 'submit', (event) => {
  if (!validateForm()) {
    event.preventDefault();
    event.stopImmediatePropagation();
  }
}, {priority: 100});

// Transform data
EventSystemManager.addHandler(form, 'submit', (event) => {
  transformFormData();
}, {priority: 50});

// Submit - ทำหลังสุด
EventSystemManager.addHandler(form, 'submit', (event) => {
  submitFormData();
}, {priority: 10});

2. Click Handlers

// Check permissions ก่อน
EventSystemManager.addHandler(button, 'click', (event) => {
  if (!hasPermission()) {
    event.preventDefault();
    event.stopPropagation();
    showPermissionError();
  }
}, {priority: 100});

// Actual action
EventSystemManager.addHandler(button, 'click', (event) => {
  performAction();
}, {priority: 50});

Configuration

Configuration Options

const config = {
  cleanupInterval: 600000,    // Cleanup interval (ms)
  maxMemoryUsage: 52428800,   // Max memory (50MB)

  delegation: {
    enabled: true,
    matchingStrategy: 'closestFirst',
    maxDelegationDepth: 10,
    optimizeSelectors: true,
    rootElement: document.body
  },

  memoryManagement: {
    checkInterval: 30000,
    maxHandlersPerElement: 100,
    maxCacheSize: 1000,
    gcThreshold: 0.8,
    detailedTracking: true
  },

  filtering: {
    enabled: true,
    maxThrottleRate: 60,
    debounceWait: 100,
    highFrequencyEvents: null  // Set หรือ null
  }
};

Update Configuration

// Update individual settings
EventSystemManager.config.memoryManagement.maxHandlersPerElement = 200;
EventSystemManager.config.delegation.maxDelegationDepth = 15;

// Update filtering
EventSystemManager.config.filtering.enabled = true;
EventSystemManager.config.filtering.maxThrottleRate = 30;

ตัวอย่างการใช้งาน

1. Form Handling

const form = document.querySelector('#registration-form');

// Submit handler
EventSystemManager.addHandler(form, 'submit', (event) => {
  event.preventDefault();

  // Validate
  if (!validateForm(form)) {
    showErrors();
    return;
  }

  // Submit
  const formData = new FormData(form);
  submitRegistration(formData);
}, {
  priority: 50
});

// Real-time validation
const inputs = form.querySelectorAll('input');
inputs.forEach(input => {
  EventSystemManager.addHandler(input, 'blur', (event) => {
    validateField(event.target);
  });

  EventSystemManager.addHandler(input, 'input', (event) => {
    clearFieldError(event.target);
  });
});

2. Dynamic List with Delegation

const todoList = document.querySelector('#todo-list');

// Add item
EventSystemManager.addHandler(todoList, 'click', (event) => {
  const item = event.delegateTarget;
  const itemId = item.dataset.id;
  addTodoItem(itemId);
}, {
  selector: '.add-button'
});

// Toggle complete
EventSystemManager.addHandler(todoList, 'click', (event) => {
  const checkbox = event.delegateTarget;
  const itemId = checkbox.closest('.todo-item').dataset.id;
  toggleComplete(itemId, checkbox.checked);
}, {
  selector: '.todo-checkbox'
});

// Delete item
EventSystemManager.addHandler(todoList, 'click', (event) => {
  const button = event.delegateTarget;
  const itemId = button.closest('.todo-item').dataset.id;
  deleteItem(itemId);
}, {
  selector: '.delete-button'
});

// Edit item
EventSystemManager.addHandler(todoList, 'click', (event) => {
  const button = event.delegateTarget;
  const itemId = button.closest('.todo-item').dataset.id;
  editItem(itemId);
}, {
  selector: '.edit-button'
});

3. Keyboard Navigation

const searchBox = document.querySelector('#search-box');
const results = document.querySelector('#search-results');

EventSystemManager.addHandler(searchBox, 'keydown', (event) => {
  const enhanced = event.originalEvent._enhanced;

  if (enhanced.isArrowKey) {
    event.preventDefault();

    if (enhanced.key === 'ArrowDown') {
      focusNextResult();
    } else if (enhanced.key === 'ArrowUp') {
      focusPreviousResult();
    }
  }

  if (enhanced.isEnter) {
    const focused = results.querySelector('.focused');
    if (focused) {
      selectResult(focused);
    }
  }

  if (event.key === 'Escape') {
    closeResults();
  }
});

4. Scroll Handling

// Infinite scroll
let isLoading = false;
EventSystemManager.addHandler(window, 'scroll', (event) => {
  if (isLoading) return;

  const scrollPosition = window.scrollY + window.innerHeight;
  const documentHeight = document.documentElement.scrollHeight;

  if (scrollPosition >= documentHeight - 200) {
    isLoading = true;
    loadMoreContent().then(() => {
      isLoading = false;
    });
  }
});

// Sticky header
const header = document.querySelector('#header');
EventSystemManager.addHandler(window, 'scroll', (event) => {
  if (window.scrollY > 100) {
    header.classList.add('sticky');
  } else {
    header.classList.remove('sticky');
  }
});

5. Drag and Drop

const draggable = document.querySelector('.draggable');
const dropzone = document.querySelector('.dropzone');

// Drag start
EventSystemManager.addHandler(draggable, 'dragstart', (event) => {
  event.originalEvent.dataTransfer.effectAllowed = 'move';
  event.originalEvent.dataTransfer.setData('text/html', event.target.innerHTML);
  event.target.classList.add('dragging');
});

// Drag end
EventSystemManager.addHandler(draggable, 'dragend', (event) => {
  event.target.classList.remove('dragging');
});

// Drag over
EventSystemManager.addHandler(dropzone, 'dragover', (event) => {
  event.preventDefault();
  event.originalEvent.dataTransfer.dropEffect = 'move';
  dropzone.classList.add('drag-over');
});

// Drag leave
EventSystemManager.addHandler(dropzone, 'dragleave', (event) => {
  dropzone.classList.remove('drag-over');
});

// Drop
EventSystemManager.addHandler(dropzone, 'drop', (event) => {
  event.preventDefault();
  dropzone.classList.remove('drag-over');

  const data = event.originalEvent.dataTransfer.getData('text/html');
  handleDrop(data);
});

6. Modal Management

// Open modal
function openModal(modalId) {
  const modal = document.querySelector(`#${modalId}`);
  modal.classList.add('active');

  // Close on backdrop click
  const backdropId = EventSystemManager.addHandler(modal, 'click', (event) => {
    if (event.target === modal) {
      closeModal(modalId);
      EventSystemManager.removeHandler(backdropId);
    }
  });

  // Close on Escape
  const escapeId = EventSystemManager.addHandler(document, 'keydown', (event) => {
    if (event.key === 'Escape') {
      closeModal(modalId);
      EventSystemManager.removeHandler(escapeId);
    }
  });
}

function closeModal(modalId) {
  const modal = document.querySelector(`#${modalId}`);
  modal.classList.remove('active');
}

7. Context Menu

const contextMenu = document.querySelector('#context-menu');

// Show context menu
EventSystemManager.addHandler(document, 'contextmenu', (event) => {
  if (!event.target.closest('.has-context-menu')) return;

  event.preventDefault();

  contextMenu.style.left = event.originalEvent.pageX + 'px';
  contextMenu.style.top = event.originalEvent.pageY + 'px';
  contextMenu.classList.add('active');
});

// Hide context menu
EventSystemManager.addHandler(document, 'click', (event) => {
  if (!event.target.closest('#context-menu')) {
    contextMenu.classList.remove('active');
  }
});

// Context menu actions
EventSystemManager.addHandler(contextMenu, 'click', (event) => {
  const action = event.delegateTarget.dataset.action;
  handleContextMenuAction(action);
  contextMenu.classList.remove('active');
}, {
  selector: '[data-action]'
});

8. Table Sorting

const table = document.querySelector('#data-table');

EventSystemManager.addHandler(table, 'click', (event) => {
  const th = event.delegateTarget;
  const columnIndex = Array.from(th.parentElement.children).indexOf(th);
  const currentSort = th.dataset.sort || 'none';

  // Toggle sort direction
  let newSort;
  if (currentSort === 'none') newSort = 'asc';
  else if (currentSort === 'asc') newSort = 'desc';
  else newSort = 'none';

  // Update UI
  table.querySelectorAll('th').forEach(header => {
    header.dataset.sort = 'none';
  });
  th.dataset.sort = newSort;

  // Sort table
  sortTable(table, columnIndex, newSort);
}, {
  selector: 'th[data-sortable]'
});

9. File Upload with Drag and Drop

const dropzone = document.querySelector('#file-dropzone');

// Prevent default drag behaviors
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
  EventSystemManager.addHandler(dropzone, eventName, (event) => {
    event.preventDefault();
    event.stopPropagation();
  });
});

// Highlight dropzone
['dragenter', 'dragover'].forEach(eventName => {
  EventSystemManager.addHandler(dropzone, eventName, (event) => {
    dropzone.classList.add('highlight');
  });
});

['dragleave', 'drop'].forEach(eventName => {
  EventSystemManager.addHandler(dropzone, eventName, (event) => {
    dropzone.classList.remove('highlight');
  });
});

// Handle drop
EventSystemManager.addHandler(dropzone, 'drop', (event) => {
  const files = event.originalEvent.dataTransfer.files;
  handleFiles(files);
});

// Click to upload
EventSystemManager.addHandler(dropzone, 'click', (event) => {
  const input = document.createElement('input');
  input.type = 'file';
  input.multiple = true;
  input.onchange = (e) => handleFiles(e.target.files);
  input.click();
});

10. Responsive Navigation

const nav = document.querySelector('#main-nav');
const toggle = document.querySelector('#nav-toggle');

// Toggle mobile menu
EventSystemManager.addHandler(toggle, 'click', (event) => {
  nav.classList.toggle('active');
});

// Close on outside click
EventSystemManager.addHandler(document, 'click', (event) => {
  if (!event.target.closest('#main-nav') &&
      !event.target.closest('#nav-toggle')) {
    nav.classList.remove('active');
  }
});

// Close on Escape
EventSystemManager.addHandler(document, 'keydown', (event) => {
  if (event.key === 'Escape') {
    nav.classList.remove('active');
  }
});

// Handle resize
EventSystemManager.addHandler(window, 'resize', (event) => {
  if (window.innerWidth > 768) {
    nav.classList.remove('active');
  }
});

API Reference

Configuration

{
  cleanupInterval: number,           // Cleanup interval (ms)
  maxMemoryUsage: number,           // Max memory usage (bytes)

  delegation: {
    enabled: boolean,                // Enable delegation
    matchingStrategy: string,        // 'closestFirst'
    maxDelegationDepth: number,     // Max depth
    optimizeSelectors: boolean,      // Optimize selectors
    rootElement: HTMLElement         // Root element
  },

  memoryManagement: {
    checkInterval: number,           // Check interval (ms)
    maxHandlersPerElement: number,  // Max handlers per element
    maxCacheSize: number,           // Max cache size
    gcThreshold: number,            // GC threshold (0-1)
    detailedTracking: boolean       // Detailed tracking
  },

  filtering: {
    enabled: boolean,               // Enable filtering
    maxThrottleRate: number,        // Max events per second
    debounceWait: number,          // Debounce wait (ms)
    highFrequencyEvents: Set       // High frequency events
  }
}

Methods

Core Methods

// Initialize
init(): EventSystemManager

// Add handler
addHandler(
  element: Element|Window|Document,
  type: string,
  handler: function,
  options?: {
    capture?: boolean,
    once?: boolean,
    passive?: boolean,
    priority?: number,
    componentId?: string,
    selector?: string
  }
): number

// Remove handler
removeHandler(id: number): boolean

// Remove component handlers
removeComponentHandlers(componentId: string): void

Cleanup Methods

// Manual cleanup
cleanup(): void

// Remove element handlers
removeElementHandlers(element: Element): void

// Destroy
destroy(): void

Memory Methods

// Gather memory stats
gatherMemoryStats(): object

// Check memory usage
checkMemoryUsage(): void

// Perform GC
performGC(): void

Event Object

{
  type: string,              // Event type
  key: string,               // Key (keyboard events)
  shiftKey: boolean,         // Shift key pressed
  ctrlKey: boolean,          // Ctrl key pressed
  altKey: boolean,           // Alt key pressed
  metaKey: boolean,          // Meta key pressed
  target: Element,           // Event target
  currentTarget: Element,    // Current target
  delegateTarget: Element,   // Delegate target
  timestamp: number,         // Timestamp
  originalEvent: Event,      // Original DOM event

  preventDefault(): void,
  stopPropagation(): void,
  stopImmediatePropagation(): void,
  matches(selector: string): boolean
}

Handler Options

{
  capture: boolean,      // Capture phase
  once: boolean,         // Execute once
  passive: boolean,      // Passive listener
  priority: number,      // Priority (higher = first)
  componentId: string,   // Component ID
  selector: string       // Delegation selector
}

Best Practices

1. ✅ ใช้ Event Delegation

// ❌ Bad: handler แยกต่าง element
items.forEach(item => {
  EventSystemManager.addHandler(item, 'click', handler);
});

// ✅ Good: ใช้ delegation
EventSystemManager.addHandler(container, 'click', handler, {
  selector: '.item'
});

2. ✅ Cleanup เมื่อ Destroy Component

// ✅ Good: เก็บ handler IDs
const MyComponent = {
  handlerIds: [],

  init() {
    const id1 = EventSystemManager.addHandler(this.element, 'click', handler);
    const id2 = EventSystemManager.addHandler(this.button, 'submit', handler);

    this.handlerIds.push(id1, id2);
  },

  destroy() {
    this.handlerIds.forEach(id => {
      EventSystemManager.removeHandler(id);
    });
  }
};

3. ✅ ใช้ Component ID

// ✅ Good: ใช้ componentId สำหรับ cleanup ง่าย
const componentId = 'my-component-123';

EventSystemManager.addHandler(element, 'click', handler, {
  componentId
});

// Cleanup ทั้ง component พร้อมกัน
EventSystemManager.removeComponentHandlers(componentId);

4. ✅ ใช้ Priority อย่างเหมาะสม

// ✅ Good: validation ก่อน submit
EventSystemManager.addHandler(form, 'submit', validateHandler, {
  priority: 100
});

EventSystemManager.addHandler(form, 'submit', submitHandler, {
  priority: 10
});

5. ✅ ใช้ Passive สำหรับ Scroll/Touch

// ✅ Good: passive สำหรับ better performance
EventSystemManager.addHandler(element, 'touchstart', handler, {
  passive: true
});

EventSystemManager.addHandler(window, 'scroll', handler, {
  passive: true
});

6. ✅ Throttle/Debounce UI Events

// ✅ Good: throttle scroll event
let lastTime = 0;
EventSystemManager.addHandler(window, 'scroll', (event) => {
  const now = Date.now();
  if (now - lastTime < 100) return;

  lastTime = now;
  handleScroll();
});

7. ✅ ใช้ Once สำหรับ One-time Events

// ✅ Good: once สำหรับ event ที่ทำครั้งเดียว
EventSystemManager.addHandler(button, 'click', handler, {
  once: true
});

8. ✅ จัดการ Memory อย่างระมัดระวัง

// ✅ Good: ตรวจสอบ memory usage
setInterval(() => {
  const stats = EventSystemManager.gatherMemoryStats();

  if (stats.handlerCount > 500) {
    console.warn('Too many handlers:', stats.handlerCount);
  }
}, 60000);

9. ✅ ใช้ stopPropagation อย่างระวัง

// ⚠️ Careful: stopPropagation อาจป้องกัน handlers อื่น
EventSystemManager.addHandler(button, 'click', (event) => {
  // ใช้เฉพาะเมื่อจำเป็น
  event.stopPropagation();
});

10. ✅ Test บน Multiple Devices

// ✅ Good: รองรับทั้ง mouse และ touch
EventSystemManager.addHandler(element, 'click', handleClick);
EventSystemManager.addHandler(element, 'touchend', handleClick);

สรุป

เมื่อใดควรใช้ EventSystemManager

Use Case ใช้ EventSystemManager? หมายเหตุ
จัดการ DOM Events ✅ ใช่ click, submit, input, etc.
Event Delegation ✅ ใช่ Dynamic content
Auto Cleanup ✅ ใช่ Memory management
Performance Optimization ✅ ใช่ UI events
Keyboard Handling ✅ ใช่ Enhanced keyboard events
Custom Application Events ❌ ไม่ ใช้ EventManager
Pattern Matching ❌ ไม่ ใช้ EventManager
Middleware ❌ ไม่ ใช้ EventManager

คุณสมบัติหลัก

คุณสมบัติ รองรับ หมายเหตุ
Event Delegation Selector-based
Auto Cleanup MutationObserver
Memory Management Auto GC
Priority System Ordered execution
UI Optimization requestAnimationFrame
Keyboard Enhancement Helper properties
Throttle/Debounce Built-in filtering
Component Integration Component IDs