UNPKG

ypsilon-event-handler

Version:

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

317 lines (289 loc) 14.5 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Data-Action Aliases Test - YpsilonEventHandler</title> <link rel="icon" type="image/x-icon" href="./../favicon.ico"> <style> body { background: #f8f8f8; font-family: Arial, sans-serif; margin: 2rem auto; max-width: 800px; } .btn { padding: 10px 20px; margin: 5px; background: #3b82f6; color: white; border: none; border-radius: 5px; cursor: pointer; } .btn:hover { background: #2563eb; } .btn.danger { background: #dc2626; } .btn.danger:hover { background: #b91c1c; } .btn.success { background: #16a34a; } .btn.success:hover { background: #15803d; } .input { padding: 8px; margin: 5px; border: 1px solid #ccc; border-radius: 3px; width: 200px; } .output { background: #f8f9fa; border: 1px solid #ddd; padding: 15px; margin: 20px 0; border-radius: 5px; min-height: 50px; } .section { margin: 30px 0; padding: 20px; background: #fff; border: 1px solid #eee; } h2 { color: #333; border-bottom: 2px solid #3b82f6; padding-bottom: 5px; } .code { background: #f5f5f5; padding: 10px; border-radius: 3px; font-family: monospace; } .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 10px; } </style> </head> <body> <h1><a href="./index.html" title="Back to index" style="text-decoration: none;">«</a> Data-Action Aliases Test</h1> <p>Single delegation pattern with semantic <code>data-action</code> attributes using aliases</p> <div class="section"> <h2>🎯 The Pattern</h2> <div class="code"> <strong>Single delegation setup:</strong><br><br> super({ 'body': ['click', 'input'] }, {<br> &nbsp;&nbsp;click: {<br> &nbsp;&nbsp;&nbsp;&nbsp;save: 'handleFormSave',<br> &nbsp;&nbsp;&nbsp;&nbsp;login: 'handleUserLogin',<br> &nbsp;&nbsp;&nbsp;&nbsp;delete: 'handleItemDelete'<br> &nbsp;&nbsp;},<br> &nbsp;&nbsp;input: {<br> &nbsp;&nbsp;&nbsp;&nbsp;search: 'handleSearchInput',<br> &nbsp;&nbsp;&nbsp;&nbsp;validate: 'handleFieldValidation'<br> &nbsp;&nbsp;}<br> });<br><br> <strong>HTML:</strong><br> &lt;button data-action="save"&gt;Save&lt;/button&gt; → handleFormSave()<br> &lt;input data-action="search" /&gt; → handleSearchInput() </div> </div> <div class="section"> <h2>🔘 Click Actions with Aliases</h2> <div class="grid"> <button class="btn success" data-action="save">Save Form</button> <button class="btn" data-action="login">User Login</button> <button class="btn danger" data-action="delete">Delete Item</button> <button class="btn" data-action="share">Share Content</button> <button class="btn" data-action="export">Export Data</button> <button class="btn" data-action="refresh">Refresh View</button> </div> <div class="output" id="click-output">Click any button above...</div> </div> <div class="section"> <h2>📝 Input Actions with Aliases</h2> <div class="grid"> <input class="input" name="y-demo-1" data-action="search" placeholder="Search (debounced)..." /> <input class="input" name="y-demo-2" data-action="validate" placeholder="Validate input..." /> <input class="input" name="y-demo-3" data-action="filter" placeholder="Filter data..." /> <input class="input" name="y-demo-4" data-action="autocomplete" placeholder="Autocomplete..." /> </div> <div class="output" id="input-output">Type in any input above...</div> </div> <div class="section"> <h2>📊 Mixed Actions</h2> <p>Same action names work differently based on event type:</p> <button class="btn" data-action="process">Process (click)</button> <input class="input" name="y-demo-5" data-action="process" placeholder="Process (input)..." /> <div class="output" id="mixed-output">Same action, different events...</div> </div> <div class="section"> <h2>📈 Action Log</h2> <button class="btn" data-action="clearLog">Clear Log</button> <div class="output" id="action-log" style="max-height: 200px; overflow-y: auto;">Action history will appear here...</div> </div> <script src="https://cdn.jsdelivr.net/npm/ypsilon-event-handler@1.5.0/ypsilon-event-handler.min.js"></script> <script> class DataActionAliasTest extends YpsilonEventHandler { constructor() { // Single delegation pattern with event-type scoped aliases super({ 'body': ['click', 'input'] }, { // Click event aliases - semantic action names → actual handler methods click: { save: 'handleFormSave', login: 'handleUserLogin', delete: 'handleItemDelete', share: 'handleContentShare', export: 'handleDataExport', refresh: 'handleViewRefresh', process: 'handleClickProcess', clearLog: 'handleClearLog' }, // Input event aliases - semantic action names → actual handler methods input: { search: 'handleSearchInput', validate: 'handleFieldValidation', filter: 'handleDataFilter', autocomplete: 'handleAutocomplete', process: 'handleInputProcess' } }); this.actionCount = 0; } // Universal delegation handlers handleClick(event, target) { const action = target.dataset.action; if (!action) return; // Resolve alias and call the actual handler const resolvedHandler = this.resolveMethodName(action, 'click'); if (typeof this[resolvedHandler] === 'function') { this[resolvedHandler](event, target); } } handleInput(event, target) { const action = target.dataset.action; if (!action) return; // Resolve alias and call the actual handler const resolvedHandler = this.resolveMethodName(action, 'input'); if (typeof this[resolvedHandler] === 'function') { this[resolvedHandler](event, target); } } // Actual handler methods (aliased via click actions) handleFormSave(event, target) { this.logAction('save', 'handleFormSave', 'Form saved successfully!'); document.getElementById('click-output').innerHTML = ` <strong>🎯 handleFormSave() called</strong><br> Via: data-action="save" (alias)<br> Action: Saving form data...<br> <small>Time: ${new Date().toLocaleTimeString()}</small> `; } handleUserLogin(event, target) { this.logAction('login', 'handleUserLogin', 'User authentication started'); document.getElementById('click-output').innerHTML = ` <strong>🔐 handleUserLogin() called</strong><br> Via: data-action="login" (alias)<br> Action: Authenticating user...<br> <small>Time: ${new Date().toLocaleTimeString()}</small> `; } handleItemDelete(event, target) { this.logAction('delete', 'handleItemDelete', 'Item marked for deletion'); document.getElementById('click-output').innerHTML = ` <strong>🗑️ handleItemDelete() called</strong><br> Via: data-action="delete" (alias)<br> Action: Deleting item...<br> <small>Time: ${new Date().toLocaleTimeString()}</small> `; } handleContentShare(event, target) { this.logAction('share', 'handleContentShare', 'Content shared'); document.getElementById('click-output').innerHTML = ` <strong>📤 handleContentShare() called</strong><br> Via: data-action="share" (alias)<br> <small>Time: ${new Date().toLocaleTimeString()}</small> `; } handleDataExport(event, target) { this.logAction('export', 'handleDataExport', 'Data export initiated'); document.getElementById('click-output').innerHTML = ` <strong>📊 handleDataExport() called</strong><br> Via: data-action="export" (alias)<br> <small>Time: ${new Date().toLocaleTimeString()}</small> `; } handleViewRefresh(event, target) { this.logAction('refresh', 'handleViewRefresh', 'View refreshed'); document.getElementById('click-output').innerHTML = ` <strong>🔄 handleViewRefresh() called</strong><br> Via: data-action="refresh" (alias)<br> <small>Time: ${new Date().toLocaleTimeString()}</small> `; } // Actual handler methods (aliased via input actions) handleSearchInput(event, target) { this.logAction('search', 'handleSearchInput', `Searching: "${target.value}"`); document.getElementById('input-output').innerHTML = ` <strong>🔍 handleSearchInput() called</strong><br> Via: data-action="search" (alias)<br> Query: "${target.value}"<br> <small>Time: ${new Date().toLocaleTimeString()}</small> `; } handleFieldValidation(event, target) { this.logAction('validate', 'handleFieldValidation', `Validating: "${target.value}"`); document.getElementById('input-output').innerHTML = ` <strong>✅ handleFieldValidation() called</strong><br> Via: data-action="validate" (alias)<br> Value: "${target.value}"<br> <small>Time: ${new Date().toLocaleTimeString()}</small> `; } handleDataFilter(event, target) { this.logAction('filter', 'handleDataFilter', `Filtering: "${target.value}"`); document.getElementById('input-output').innerHTML = ` <strong>🔽 handleDataFilter() called</strong><br> Via: data-action="filter" (alias)<br> Filter: "${target.value}"<br> <small>Time: ${new Date().toLocaleTimeString()}</small> `; } handleAutocomplete(event, target) { this.logAction('autocomplete', 'handleAutocomplete', `Autocomplete: "${target.value}"`); document.getElementById('input-output').innerHTML = ` <strong>💡 handleAutocomplete() called</strong><br> Via: data-action="autocomplete" (alias)<br> Input: "${target.value}"<br> <small>Time: ${new Date().toLocaleTimeString()}</small> `; } // Mixed action demonstrations (same action name, different event types) handleClickProcess(event, target) { this.logAction('process', 'handleClickProcess', 'Click processing started'); document.getElementById('mixed-output').innerHTML = ` <strong>⚡ handleClickProcess() called</strong><br> Event: click, Action: "process"<br> Different handler than input process!<br> <small>Time: ${new Date().toLocaleTimeString()}</small> `; } handleInputProcess(event, target) { this.logAction('process', 'handleInputProcess', `Input processing: "${target.value}"`); document.getElementById('mixed-output').innerHTML = ` <strong>⚡ handleInputProcess() called</strong><br> Event: input, Action: "process"<br> Value: "${target.value}"<br> Different handler than click process!<br> <small>Time: ${new Date().toLocaleTimeString()}</small> `; } handleClearLog(event, target) { document.getElementById('action-log').innerHTML = 'Action history cleared...'; this.actionCount = 0; } // Utility method logAction(action, handler, description) { this.actionCount++; const logDiv = document.getElementById('action-log'); const entry = document.createElement('div'); entry.style.cssText = 'margin: 5px 0; padding: 5px; background: #f0f0f0; border-radius: 3px;'; entry.innerHTML = ` <strong>#${this.actionCount}</strong> <code>data-action="${action}"</code> → <code>${handler}()</code><br> <small>${description} at ${new Date().toLocaleTimeString()}</small> `; logDiv.appendChild(entry); logDiv.scrollTop = logDiv.scrollHeight; } } // Initialize test const test = new DataActionAliasTest(); // Log initialization info console.log('Data-Action Aliases Test initialized!'); console.log('Click aliases:', test.aliases.click); console.log('Input aliases:', test.aliases.input); console.log('Event listeners:', test.eventListeners.size, '(should be 2: body click + body input)'); </script> </body> </html>