// CV Interactive Features - CSP-Compliant External JavaScript // Extracted from inline scripts for security hardening (function() { 'use strict'; // ============================================================================= // NAVIGATION & MENU SYSTEM // ============================================================================= // Minimal menu control - CSS handles most logic, JS just bridges hamburger to menu function initMenuSystem() { const hamburgerBtn = document.querySelector('.hamburger-btn'); const menu = document.getElementById('navigation-menu'); if (!hamburgerBtn || !menu) return; // Show menu on hamburger hover - CSS handles the rest hamburgerBtn.addEventListener('mouseenter', () => menu.classList.add('menu-hover')); // Hide menu when leaving hamburger if not hovering menu hamburgerBtn.addEventListener('mouseleave', () => { setTimeout(() => { if (!menu.matches(':hover')) menu.classList.remove('menu-hover'); }, 100); }); // Hide menu when leaving menu menu.addEventListener('mouseleave', () => menu.classList.remove('menu-hover')); // Position submenu dynamically (needed because fixed positioning) const submenuTrigger = document.querySelector('.menu-item-submenu'); const submenuContent = document.querySelector('.submenu-content'); if (submenuTrigger && submenuContent) { submenuTrigger.addEventListener('mouseenter', function() { submenuContent.style.top = `${this.getBoundingClientRect().top}px`; }); } } // Flag to keep header visible after navigation let keepHeaderVisible = false; // Expand/collapse all sections utility functions window.expandAllSections = function(event) { event.preventDefault(); document.querySelectorAll('details').forEach(d => d.setAttribute('open', '')); }; window.collapseAllSections = function(event) { event.preventDefault(); document.querySelectorAll('details').forEach(d => d.removeAttribute('open')); }; // Close menu when navigation links clicked - CSS handles scrolling document.addEventListener('click', (e) => { const navLink = e.target.closest('.submenu-content a[href^="#"]'); if (navLink) { document.querySelector('.navigation-menu')?.classList.remove('menu-hover', 'menu-open'); } }); // ============================================================================= // LANGUAGE & PREFERENCES // ============================================================================= // ============================================================================= // ZOOM CONTROL - Now handled by Hyperscript in zoom-control.html // ============================================================================= // All zoom functionality moved to declarative hyperscript: // - Slider updates and real-time zoom application // - Reset button (back to 100%) // - Close/show toggle with localStorage persistence // - Keyboard shortcuts (Ctrl/Cmd +/-/0) // - Draggable positioning with bounds checking // - Mobile detection and auto-disable // - LocalStorage persistence (zoom level, visibility, position) // // Result: ~343 lines of JavaScript eliminated! // ============================================================================= // PRINT & PDF - Now handled by Hyperscript in action-buttons.html // ============================================================================= // Print function moved to inline hyperscript on print button: // - Stores current theme, length, and zoom state // - Applies clean theme + short version for printing // - Resets zoom to 100% for consistent print output // - Calls window.print() // - Restores original state after print dialog closes // - Properly restores zoom by triggering slider input event (fixes Phase 5 bug) // // Result: ~44 lines of JavaScript eliminated! // ============================================================================= // INITIALIZATION & PREFERENCES // ============================================================================= function initPreferences() { const paper = document.querySelector('.cv-paper'); // Handle language preference const urlLang = new URLSearchParams(window.location.search).get('lang'); const savedLang = localStorage.getItem('cv-language'); if (!urlLang && savedLang) { // URL is clean but we have a saved preference - redirect with lang parameter const url = new URL(window.location); url.searchParams.set('lang', savedLang); window.location.replace(url.toString()); } else if (urlLang) { // Save URL language to localStorage localStorage.setItem('cv-language', urlLang); } // Zoom control initialization now handled by hyperscript in zoom-control.html } // ============================================================================= // SCROLL BEHAVIOR - Now handled by Hyperscript on
element // ============================================================================= // Scroll behavior moved to inline hyperscript on body tag: // - Header hide/show based on scroll direction (with 100px threshold) // - Back-to-top button visibility (appears after 300px scroll) // - At-bottom positioning for fixed buttons (within 50px of page bottom) // - Menu visibility coordination when open // - State tracking: lastScroll, scrollThreshold, keepHeaderVisible // // Result: ~59 lines of JavaScript eliminated! // ============================================================================= // MODALS - Using Native