Files
MyFastHtml/tests/html/test_keyboard_support.html
2025-11-25 23:13:47 +01:00

309 lines
8.8 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Keyboard Support Test</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 20px auto;
padding: 0 20px;
}
.test-container {
border: 2px solid #333;
padding: 20px;
margin: 20px 0;
border-radius: 5px;
}
.test-element {
background-color: #f0f0f0;
border: 2px solid #999;
padding: 30px;
text-align: center;
border-radius: 5px;
cursor: pointer;
margin: 10px 0;
}
.test-element:focus {
background-color: #e3f2fd;
border-color: #2196F3;
outline: none;
}
.log-container {
background-color: #1e1e1e;
color: #d4d4d4;
padding: 15px;
border-radius: 5px;
max-height: 400px;
overflow-y: auto;
font-family: 'Courier New', monospace;
font-size: 14px;
margin-top: 20px;
}
.log-entry {
margin: 5px 0;
padding: 5px;
border-left: 3px solid #4CAF50;
padding-left: 10px;
}
.log-entry.focus {
border-left-color: #2196F3;
}
.log-entry.no-focus {
border-left-color: #FF9800;
}
.shortcuts-list {
background-color: #fff3cd;
border: 1px solid #ffc107;
padding: 15px;
border-radius: 5px;
margin: 10px 0;
}
.shortcuts-list h3 {
margin-top: 0;
}
.shortcuts-list ul {
margin: 10px 0;
padding-left: 20px;
}
.shortcuts-list code {
background-color: #f5f5f5;
padding: 2px 6px;
border-radius: 3px;
font-family: 'Courier New', monospace;
}
.clear-button {
background-color: #f44336;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
}
.clear-button:hover {
background-color: #d32f2f;
}
h1, h2 {
color: #333;
}
</style>
</head>
<body>
<h1>Keyboard Support Test Page</h1>
<div class="shortcuts-list">
<h3>📋 Configured Shortcuts (with HTMX options)</h3>
<p><strong>Simple keys:</strong></p>
<ul>
<li><code>a</code> - Simple key A (POST to /test/key-a)</li>
<li><code>esc</code> - Escape key (POST)</li>
</ul>
<p><strong>Simultaneous combinations with HTMX options:</strong></p>
<ul>
<li><code>Ctrl+S</code> - Save (POST with swap: innerHTML)</li>
<li><code>Ctrl+C</code> - Copy (POST with target: #result, swap: outerHTML)</li>
</ul>
<p><strong>Sequences with various configs:</strong></p>
<ul>
<li><code>A B</code> - Sequence (POST with extra values: {"extra": "data"})</li>
<li><code>A B C</code> - Triple sequence (GET request)</li>
<li><code>shift shift</code> - Press Shift twice in sequence</li>
</ul>
<p><strong>Complex:</strong></p>
<ul>
<li><code>Ctrl+C C</code> - Ctrl+C then C alone</li>
<li><code>Ctrl+C Ctrl+C</code> - Ctrl+C twice</li>
</ul>
<p><strong>Tip:</strong> Check the log to see how HTMX options (target, swap, extra values) are passed!</p>
</div>
<div class="test-container">
<h2>Test Input (typing should work normally here)</h2>
<input type="text" placeholder="Try typing Ctrl+C, Ctrl+A here - should work normally" style="width: 100%; padding: 10px; font-size: 14px;">
<p style="margin-top: 10px; padding: 10px; background-color: #e3f2fd; border-left: 4px solid #2196F3; border-radius: 3px;">
<strong>Parameters Explained:</strong><br>
<code>has_focus</code>: Whether the registered element itself has focus<br>
<code>is_inside</code>: Whether the focus is on the registered element or any of its children<br>
<em>Example: If focus is on this input and its parent div is registered, has_focus=false but is_inside=true</em>
</p>
</div>
<div class="test-container">
<h2>Test Element 1</h2>
<div id="test-element" class="test-element" tabindex="0">
Click me to focus, then try keyboard shortcuts
</div>
</div>
<div class="test-container">
<h2>Test Element 2 (also listens to ESC and Shift Shift)</h2>
<div id="test-element-2" class="test-element" tabindex="0">
This element also responds to ESC and Shift Shift
</div>
<button class="clear-button" onclick="removeElement2()" style="background-color: #FF5722; margin-top: 10px;">
Remove Element 2 Keyboard Support
</button>
</div>
<div class="test-container">
<h2>Event Log</h2>
<button class="clear-button" onclick="clearLog()">Clear Log</button>
<div id="log" class="log-container"></div>
</div>
<!-- Include htmx -->
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<!-- Mock htmx.ajax for testing -->
<script>
// Store original htmx.ajax if it exists
const originalHtmxAjax = window.htmx && window.htmx.ajax;
// Override htmx.ajax for testing purposes
if (window.htmx) {
window.htmx.ajax = function(method, url, config) {
const timestamp = new Date().toLocaleTimeString();
const hasFocus = config.values.has_focus;
const isInside = config.values.is_inside;
const combination = config.values.combination;
// Build details string with all config options
const details = [
`Combination: "${combination}"`,
`Element has focus: ${hasFocus}`,
`Focus inside element: ${isInside}`
];
if (config.target) {
details.push(`Target: ${config.target}`);
}
if (config.swap) {
details.push(`Swap: ${config.swap}`);
}
if (config.values) {
const extraVals = Object.keys(config.values).filter(k => k !== 'combination' && k !== 'has_focus');
if (extraVals.length > 0) {
details.push(`Extra values: ${JSON.stringify(extraVals.reduce((obj, k) => ({...obj, [k]: config.values[k]}), {}))}`);
}
}
logEvent(
`[${timestamp}] ${method} ${url}`,
...details,
hasFocus
);
// Uncomment below to use real htmx.ajax if you have a backend
// if (originalHtmxAjax) {
// originalHtmxAjax.call(this, method, url, config);
// }
};
}
function logEvent(title, ...details) {
const log = document.getElementById('log');
const hasFocus = details[details.length - 1];
const entry = document.createElement('div');
entry.className = `log-entry ${hasFocus ? 'focus' : 'no-focus'}`;
entry.innerHTML = `
<strong>${title}</strong><br>
${details.slice(0, -1).join('<br>')}
`;
log.insertBefore(entry, log.firstChild);
}
function clearLog() {
document.getElementById('log').innerHTML = '';
}
function removeElement2() {
remove_keyboard_support('test-element-2');
logEvent('Element 2 keyboard support removed',
'ESC and Shift Shift no longer trigger for Element 2',
'Element 1 still active', false);
// Disable the button
event.target.disabled = true;
event.target.textContent = 'Keyboard Support Removed';
}
</script>
<!-- Include keyboard support script -->
<script src="keyboard_support.js"></script>
<!-- Initialize keyboard support -->
<script>
const combinations = {
"a": {
"hx-post": "/test/key-a"
},
"Ctrl+S": {
"hx-post": "/test/save",
"hx-swap": "innerHTML"
},
"Ctrl+C": {
"hx-post": "/test/copy",
"hx-target": "#result",
"hx-swap": "outerHTML"
},
"A B": {
"hx-post": "/test/sequence-ab",
"hx-vals": {"extra": "data"}
},
"A B C": {
"hx-get": "/test/sequence-abc"
},
"Ctrl+C C": {
"hx-post": "/test/complex-ctrl-c-c"
},
"Ctrl+C Ctrl+C": {
"hx-post": "/test/complex-ctrl-c-twice"
},
"shift shift": {
"hx-post": "/test/shift-shift"
},
"esc": {
"hx-post": "/test/escape"
}
};
add_keyboard_support('test-element', JSON.stringify(combinations));
// Add second element that also listens to ESC and shift shift
const combinations2 = {
"esc": {
"hx-post": "/test/escape-element2"
},
"shift shift": {
"hx-post": "/test/shift-shift-element2"
}
};
add_keyboard_support('test-element-2', JSON.stringify(combinations2));
// Log initial state
logEvent('Keyboard support initialized',
'Element 1: All shortcuts configured with HTMX options',
'Element 2: ESC and Shift Shift (will trigger simultaneously with Element 1)',
'Smart timeout enabled: waits 500ms only if longer sequence exists', false);
</script>
</body>
</html>