refactor: split serve.py and index.html into single-responsibility modules
Backend:
- path_validator.py: PathValidator-Klasse für Pfad-Validierung
- file_ops.py: read_file, write_file, directory_exists, file_exists
- content_types.py: get_content_type mit EXTENSION_MAP
- handler.py: Handler-Klasse mit do_GET/do_PUT, nutzt above modules
- serve.py: Entry-Point (main, find_free_port), setzt Handler.validator/directory
Frontend:
- css/variables.css: CSS-Variablen (--bg-*, --text-*, --accent, etc.)
- css/styles.css: Alle CSS-Regeln (modal, card, template-grid, etc.)
- js/utils.js: esc, showToast, copyContentToClipboard
- js/modal.js: showModal, closeModal, closeEditModal, wasViewModalOpen
- js/editor.js: editModalContent, createJsonEditUI, extractJsonFromForm
- js/api.js: viewTemplate, copyContent, loadTemplates, saveEditedContent
- js/templates.js: renderTemplates, applyFilters, parseTypeFromHash
- js/main.js: Event-Listener, Hash-Filter, Initialisierung
- index.html: Inline-CSS/JS entfernt, <link>/<script src>-Tags hinzugefügt
Smoke test: SO_REUSEADDR für schnelle Port-Wiederverwendung
2026-05-03 14:40:44 +02:00
|
|
|
/**
|
|
|
|
|
* Haupt-Initialisierung: Event-Listener, Hash-Filter, App-Start.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
let allTemplates = [];
|
|
|
|
|
|
|
|
|
|
// Search-Event
|
|
|
|
|
document.getElementById('search').addEventListener('input', (e) => {
|
|
|
|
|
currentQuery = e.target.value.toLowerCase();
|
|
|
|
|
applyFilters();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Close modal on overlay click
|
|
|
|
|
document.getElementById('modal').addEventListener('click', (e) => {
|
|
|
|
|
if (e.target === e.currentTarget) closeModal();
|
|
|
|
|
});
|
2026-05-03 20:09:36 +02:00
|
|
|
document.getElementById('edit-modal').addEventListener('click', (e) => {
|
|
|
|
|
if (e.target === e.currentTarget) closeEditModal();
|
|
|
|
|
});
|
|
|
|
|
document.getElementById('tune-modal').addEventListener('click', (e) => {
|
|
|
|
|
if (e.target === e.currentTarget) closeTuneModal();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Focus trap for edit-modal
|
|
|
|
|
document.getElementById('edit-modal').addEventListener('keydown', function(e) {
|
|
|
|
|
if (e.key === 'Tab') { _trapFocus(e, document.getElementById('edit-modal')); }
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Focus trap for tune-modal
|
|
|
|
|
document.getElementById('tune-modal').addEventListener('keydown', function(e) {
|
|
|
|
|
if (e.key === 'Tab') { _trapFocus(e, document.getElementById('tune-modal')); }
|
|
|
|
|
});
|
refactor: split serve.py and index.html into single-responsibility modules
Backend:
- path_validator.py: PathValidator-Klasse für Pfad-Validierung
- file_ops.py: read_file, write_file, directory_exists, file_exists
- content_types.py: get_content_type mit EXTENSION_MAP
- handler.py: Handler-Klasse mit do_GET/do_PUT, nutzt above modules
- serve.py: Entry-Point (main, find_free_port), setzt Handler.validator/directory
Frontend:
- css/variables.css: CSS-Variablen (--bg-*, --text-*, --accent, etc.)
- css/styles.css: Alle CSS-Regeln (modal, card, template-grid, etc.)
- js/utils.js: esc, showToast, copyContentToClipboard
- js/modal.js: showModal, closeModal, closeEditModal, wasViewModalOpen
- js/editor.js: editModalContent, createJsonEditUI, extractJsonFromForm
- js/api.js: viewTemplate, copyContent, loadTemplates, saveEditedContent
- js/templates.js: renderTemplates, applyFilters, parseTypeFromHash
- js/main.js: Event-Listener, Hash-Filter, Initialisierung
- index.html: Inline-CSS/JS entfernt, <link>/<script src>-Tags hinzugefügt
Smoke test: SO_REUSEADDR für schnelle Port-Wiederverwendung
2026-05-03 14:40:44 +02:00
|
|
|
|
|
|
|
|
// Escape key closes modal
|
|
|
|
|
document.addEventListener('keydown', (e) => {
|
2026-05-03 20:09:36 +02:00
|
|
|
if (e.key === 'Escape') { closeEditModal(); closeModal(); closeTuneModal(); }
|
refactor: split serve.py and index.html into single-responsibility modules
Backend:
- path_validator.py: PathValidator-Klasse für Pfad-Validierung
- file_ops.py: read_file, write_file, directory_exists, file_exists
- content_types.py: get_content_type mit EXTENSION_MAP
- handler.py: Handler-Klasse mit do_GET/do_PUT, nutzt above modules
- serve.py: Entry-Point (main, find_free_port), setzt Handler.validator/directory
Frontend:
- css/variables.css: CSS-Variablen (--bg-*, --text-*, --accent, etc.)
- css/styles.css: Alle CSS-Regeln (modal, card, template-grid, etc.)
- js/utils.js: esc, showToast, copyContentToClipboard
- js/modal.js: showModal, closeModal, closeEditModal, wasViewModalOpen
- js/editor.js: editModalContent, createJsonEditUI, extractJsonFromForm
- js/api.js: viewTemplate, copyContent, loadTemplates, saveEditedContent
- js/templates.js: renderTemplates, applyFilters, parseTypeFromHash
- js/main.js: Event-Listener, Hash-Filter, Initialisierung
- index.html: Inline-CSS/JS entfernt, <link>/<script src>-Tags hinzugefügt
Smoke test: SO_REUSEADDR für schnelle Port-Wiederverwendung
2026-05-03 14:40:44 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Hash -> type filter
|
|
|
|
|
window.addEventListener('hashchange', () => {
|
|
|
|
|
currentType = parseTypeFromHash();
|
|
|
|
|
applyFilters();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Nav clicks set the hash; hashchange drives filtering
|
|
|
|
|
document.querySelectorAll('.nav a').forEach(link => {
|
|
|
|
|
link.addEventListener('click', (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
const target = link.getAttribute('href') || '#';
|
|
|
|
|
if (window.location.hash === target || (target === '#' && window.location.hash === '')) {
|
|
|
|
|
return; // same target, no hashchange would fire
|
|
|
|
|
}
|
|
|
|
|
window.location.hash = target;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2026-05-03 20:09:36 +02:00
|
|
|
// Set initial aria-hidden on all modals
|
|
|
|
|
_setAriaHidden('modal', true);
|
|
|
|
|
_setAriaHidden('edit-modal', true);
|
|
|
|
|
_setAriaHidden('tune-modal', true);
|
|
|
|
|
|
refactor: split serve.py and index.html into single-responsibility modules
Backend:
- path_validator.py: PathValidator-Klasse für Pfad-Validierung
- file_ops.py: read_file, write_file, directory_exists, file_exists
- content_types.py: get_content_type mit EXTENSION_MAP
- handler.py: Handler-Klasse mit do_GET/do_PUT, nutzt above modules
- serve.py: Entry-Point (main, find_free_port), setzt Handler.validator/directory
Frontend:
- css/variables.css: CSS-Variablen (--bg-*, --text-*, --accent, etc.)
- css/styles.css: Alle CSS-Regeln (modal, card, template-grid, etc.)
- js/utils.js: esc, showToast, copyContentToClipboard
- js/modal.js: showModal, closeModal, closeEditModal, wasViewModalOpen
- js/editor.js: editModalContent, createJsonEditUI, extractJsonFromForm
- js/api.js: viewTemplate, copyContent, loadTemplates, saveEditedContent
- js/templates.js: renderTemplates, applyFilters, parseTypeFromHash
- js/main.js: Event-Listener, Hash-Filter, Initialisierung
- index.html: Inline-CSS/JS entfernt, <link>/<script src>-Tags hinzugefügt
Smoke test: SO_REUSEADDR für schnelle Port-Wiederverwendung
2026-05-03 14:40:44 +02:00
|
|
|
// Initial load
|
|
|
|
|
loadTemplates().then(t => {
|
|
|
|
|
allTemplates = t;
|
|
|
|
|
window.allTemplates = t;
|
|
|
|
|
currentType = parseTypeFromHash();
|
|
|
|
|
applyFilters();
|
|
|
|
|
}).catch(e => {
|
|
|
|
|
console.error('Failed to load templates:', e);
|
|
|
|
|
allTemplates = [];
|
|
|
|
|
window.allTemplates = [];
|
|
|
|
|
applyFilters();
|
|
|
|
|
});
|