UNPKG

ypsilon-event-handler

Version:

A production-ready event handling system for web applications with memory leak prevention, and method chaining support

357 lines (311 loc) â€ĸ 12.3 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Methods Object Pattern - YpsilonEventHandler</title> <meta name="description" content="Vue.js-like methods object pattern for clean handler organization"> <link rel="icon" type="image/x-icon" href="../favicon.ico"> <link rel="stylesheet" type="text/css" href="../assets/main.css"> <style> body { font-family: system-ui, sans-serif; margin: 0 auto; padding: 2rem 0; max-width: 800px; background: #f5f5f5; } .demo-section { margin: 2rem 0; padding: 1.5rem; border: 1px solid #e0e0e0; border-radius: 6px; background: #fafafa; } .demo-section h3 { margin-top: 0; color: #2c3e50; border-bottom: 2px solid #27ae60; padding-bottom: 0.5rem; } .test-button { margin: 0.5rem; padding: 0.7rem 1.2rem; border: none; border-radius: 4px; cursor: pointer; font-weight: 500; transition: all 0.2s; background: #27ae60; color: white; } .test-button:hover { background: #229954; transform: translateY(-2px); } .test-button:disabled { background: #95a5a6 !important; cursor: not-allowed !important; transform: none !important; opacity: 0.6; } .code-block { background: #2c3e50; color: #ecf0f1; padding: 1rem; border-radius: 4px; font-family: 'Courier New', monospace; font-size: 0.9rem; margin: 1rem 0; overflow-x: auto; } .output-log { background: #34495e; color: #ecf0f1; padding: 1rem; border-radius: 4px; font-family: 'Courier New', monospace; font-size: 0.9rem; max-height: 200px; overflow-y: auto; } .highlight { background: #f39c12; padding: 2px 4px; border-radius: 3px; color: #2c3e50; } .benefits { background: #e8f5e8; border-left: 4px solid #27ae60; padding: 1rem; margin: 1rem 0; } .clear-btn { background: #6c757d; color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; float: right; margin-bottom: 1rem; } .clear-btn:hover { background: #5a6268; } .logs { padding: 0; position: sticky; bottom: 0; box-shadow: 0 2px 10px rgba(69, 3, 175, 0.6); } .logs h3 { margin: 0; padding: .5rem; border: 0 none; } .logs .clear-btn { position: absolute; top: 5px; right: 5px; } </style> </head> <body> <header class="demo-container"> <h1><a href="./index.html" title="Back to index" style="text-decoration: none;">ÂĢ</a> Methods Object Pattern</h1> <p>Vue.js-inspired methods object pattern for clean handler organization and better code separation.</p> <div class="benefits"> <strong>đŸŽ¯ Benefits:</strong> <ul> <li><strong>Clean Separation:</strong> Handlers separate from class logic</li> <li><strong>Modular Design:</strong> Easy to import/export handler collections</li> <li><strong>Team Collaboration:</strong> Different developers can work on handlers vs. class setup</li> <li><strong>Testing:</strong> Handlers can be tested independently</li> <li><strong>Plugin System:</strong> Third-party handlers without class inheritance</li> </ul> </div> </header> <!-- Basic Example --> <div class="demo-section"> <h3>📝 Basic Usage</h3> <p>Define handlers in a separate object and pass to constructor:</p> <pre class="code-block">// 1. Define handlers object const myHandlers = { handleSave: (event, target) => { console.log('Saving data...'); }, handleDelete: (event, target) => { console.log('Deleting item...'); } }; // 2. Pass to constructor new YpsilonEventHandler({ body: ['click'] }, {}, { <span class="highlight">methods: myHandlers</span> });</pre> <button class="test-button" data-action="handleSave">💾 Save</button> <button class="test-button" data-action="handleDelete">đŸ—‘ī¸ Delete</button> </div> <!-- Advanced Example --> <div class="demo-section"> <h3>🔧 Advanced Patterns</h3> <p>Complex handlers with state management and async operations:</p> <button class="test-button" data-action="handleFormSubmit">📤 Submit Form</button> <button class="test-button" data-action="handleAsyncOperation">âŗ Async Operation</button> <button class="test-button" data-action="handleDataValidation">✅ Validate Data</button> </div> <!-- Module Integration --> <div class="demo-section"> <h3>📚 Module Integration</h3> <p>Import handlers from separate modules for better organization:</p> <pre class="code-block">// userHandlers.js export const userHandlers = { handleLogin: (event, target) => { /* login logic */ }, handleLogout: (event, target) => { /* logout logic */ } }; // dataHandlers.js export const dataHandlers = { handleLoad: (event, target) => { /* load logic */ }, handleSave: (event, target) => { /* save logic */ } }; // main.js import { userHandlers } from './userHandlers.js'; import { dataHandlers } from './dataHandlers.js'; const allHandlers = { ...userHandlers, ...dataHandlers }; new YpsilonEventHandler({...}, {}, { <span class="highlight">methods: allHandlers</span> });</pre> <button class="test-button" data-action="handleLogin">🔐 Login</button> <button class="test-button" data-action="handleLogout">đŸšĒ Logout</button> <button class="test-button" data-action="handleLoad">đŸ“Ĩ Load Data</button> </div> <!-- Event Log --> <div class="demo-section logs"> <h3>📋 Event Log</h3> <button class="clear-btn" onclick="clearLog()">Clear Log</button> <div class="output-log" id="event-log">Handler events will appear here...</div> </div> <!-- Navigation --> <div class="nav-container"> <nav class="main-nav"> <div> <a href="../index.html" class="btn-primary">Start</a> <a href="../basic-example.html" class="btn-secondary">Basic Example</a> <a href="../reactive-y.html" class="btn-danger">Reactive Demo</a> <a href="../single-listener-multiple-actions.html" class="btn-purple">Single Listener</a> <a href="../spa.html" class="btn-success">SPA Demo</a> <a href="../ai-reviews.html" class="btn-warning">AI Reviews</a> <a href="https://github.com/eypsilon/YpsilonEventHandler" class="btn-dark">GitHub</a> </div> </nav> </div> <script src="https://cdn.jsdelivr.net/npm/ypsilon-event-handler@1.5.0/ypsilon-event-handler.min.js"></script> <script> // Methods object with various handler patterns const methodsHandlers = { // Basic handlers handleSave: (event, target) => { logEvent('💾 Save', 'Data saved successfully'); }, handleDelete: (event, target) => { logEvent('đŸ—‘ī¸ Delete', 'Item deleted'); }, // Advanced handlers handleFormSubmit: async (event, target) => { target.disabled = true; target.textContent = '📤 Validating...'; logEvent('📤 Form Submit', 'Validating form data...'); // Simulate form validation setTimeout(() => { logEvent('📤 Form Submit', 'Form submitted successfully'); target.disabled = false; target.textContent = '📤 Submit Form'; }, 1000); }, handleAsyncOperation: async (event, target) => { target.disabled = true; target.textContent = 'âŗ Processing...'; logEvent('âŗ Async', 'Starting async operation...'); // Simulate async work try { await new Promise(resolve => setTimeout(resolve, 1500)); logEvent('âŗ Async', 'Async operation completed'); } catch (error) { logEvent('âŗ Async', 'Async operation failed'); } finally { target.disabled = false; target.textContent = 'âŗ Async Operation'; } }, handleDataValidation: (event, target) => { const isValid = Math.random() > 0.5; logEvent('✅ Validation', isValid ? 'Data is valid' : 'Data validation failed'); }, // Module-style handlers handleLogin: (event, target) => { target.disabled = true; target.textContent = '🔐 Authenticating...'; logEvent('🔐 Login', 'User authentication started'); setTimeout(() => { logEvent('🔐 Login', 'User logged in successfully'); target.disabled = false; target.textContent = '🔐 Login'; }, 800); }, handleLogout: (event, target) => { logEvent('đŸšĒ Logout', 'User logged out'); }, handleLoad: (event, target) => { target.disabled = true; target.textContent = 'đŸ“Ĩ Loading...'; logEvent('đŸ“Ĩ Load', 'Loading data from server...'); setTimeout(() => { logEvent('đŸ“Ĩ Load', 'Data loaded successfully'); target.disabled = false; target.textContent = 'đŸ“Ĩ Load Data'; }, 1200); } }; // Handler class using methods object class MethodsObjectDemo extends YpsilonEventHandler { constructor() { super({ body: ['click'] }, {}, { methods: methodsHandlers // Pass methods object }); } handleClick(event, target) { const action = target.dataset.action; if (action && this.resolveHandler(action, 'click')) { const handler = this.resolveHandler(action, 'click'); handler(event, target); } } } // Utility functions function logEvent(source, message) { const log = document.getElementById('event-log'); const timestamp = new Date().toLocaleTimeString(); const entry = `[${timestamp}] ${source}: ${message}`; if (log.textContent === 'Handler events will appear here...') { log.innerHTML = entry; } else { log.innerHTML += '<br>' + entry; } log.scrollTop = log.scrollHeight; } function clearLog() { document.getElementById('event-log').textContent = 'Handler events will appear here...'; } // Initialize the handler const handler = new MethodsObjectDemo(); // Log initialization logEvent('🚀 System', 'Methods Object Pattern initialized'); logEvent('â„šī¸ Info', 'Click buttons to test different handler patterns'); </script> </body> </html>