# Hyperscript Development Rules
## MANDATORY RULES - ALWAYS FOLLOW
### Rule 1: Code Cleanliness
**More than 3 lines of hyperscript → Move to function in file**
- Inline hyperscript in HTML should be kept minimal (≤3 lines)
- Longer logic MUST be extracted to named functions in .\_hs files
- HTML templates should be clean and readable
### Rule 2: File Structure - Organized by Category
**✅ NO def statement limit with latest hyperscript!**
**HISTORICAL NOTE** (2025-11-17): Hyperscript 0.9.12 had a 3 def limit. Latest version REMOVED this limitation.
- Test verification: `tests/mjs/9-hyperscript-def-limit.test.mjs` (all 5 def statements passed)
- Migration in progress: Moving functions from JavaScript back to hyperscript
**Current Best Practice**: Organize hyperscript functions by category in separate files
```
static/hyperscript/
├── toggles._hs # Toggle functions (CV length, icons, theme)
├── hover-sync._hs # Hover synchronization functions
├── utils._hs # Utility functions (print, scroll, etc.)
└── keyboard._hs # Keyboard shortcut handlers
```
**Benefits of Hyperscript Organization:**
- ✅ Clean separation of concerns
- ✅ Easy to locate and maintain functions
- ✅ No artificial limitations
- ✅ Server-side hypermedia pattern (functions loaded with HTML)
- ✅ Still callable from anywhere using `call functionName(args)`
### Rule 3: HTML Structure Cleanliness
**HTML must be as clean as possible regarding hyperscript**
✅ **GOOD** - Clean, readable:
```html
```
❌ **BAD** - Inline logic nightmare:
```html
```
### Rule 4: Event Handler Externalization Guidelines (2025-11-20)
**Know what CAN and CANNOT be externalized**
#### ✅ **CAN Be Externalized:**
**Simple function calls without complex event inspection:**
```html
```
**External function example:**
```hyperscript
def scrollToSection(event, sectionId)
call event.preventDefault()
set element to document.getElementById(sectionId)
if element then call element.scrollIntoView({behavior: 'smooth'}) end
end
```
#### ❌ **MUST Stay Inline:**
**Complex event handlers that inspect event properties:**
```html
```
**Why:** The `event` variable in `_=""` attributes is a hyperscript runtime variable. External `def` functions don't have direct access to this event context, causing scoping issues.
#### 🎯 **Optimization for Inline Handlers:**
**Use `then` chains to make inline code more compact:**
```hyperscript
-- Before (verbose)
if condition
do step1
do step2
do step3
end
-- After (compact with then chains)
if condition
do step1 then do step2 then do step3
end
```
**Example from body keyboard handler:**
```html
if event.key is '?' and not event.ctrlKey and not event.metaKey and not event.altKey and not isInputField
halt the event then set modal to #shortcuts-modal then if modal then call modal.showModal() end
end
```
## File Organization
```
static/hyperscript/
├── utils._hs → Core utilities (scroll, print, modals, expand/collapse)
├── toggles._hs → Toggle functions (CV length, icons, theme)
├── hover-sync._hs → Hover sync functions (PDF, print, zoom)
├── keyboard._hs → Keyboard shortcut helpers (handleToggleShortcut, openModalShortcut)
├── zoom._hs → Zoom control (slider, reset, drag handlers, visibility)
└── pdf-modal._hs → PDF modal helpers (selectPdfCard, handlePdfCardKey)
```
### Load Order in templates/index.html:
```html
```
## Required Functions
### Core Functions (utils._hs)
1. `printFriendly()` - Handle print-friendly view
2. `initScrollBehavior()` - Initialize scroll variables
3. `handleScroll()` - Manage scroll behavior and fixed button positioning
4. `closeOnBackdrop(modal, evt)` - Close modal when clicking backdrop (outside content)
5. `scrollToTop(evt)` - Smooth scroll to top of page
6. `scrollToSection(evt, sectionId)` - Smooth scroll to section with menu close
7. `expandAllSections(evt)` - Expand all `` elements
8. `collapseAllSections(evt)` - Collapse all `` elements
9. `setFooterHover(show)` - Add/remove footer-hovered class on fixed buttons
### Toggle Functions (toggles._hs)
1. `toggleCVLength(isLong)` - Switch between short/long CV
2. `toggleIcons(showIcons)` - Show/hide icons
3. `toggleTheme(isClean)` - Switch between default/clean theme
### Hover Sync Functions (hover-sync._hs)
1. `syncPdfHover(show)` - Sync hover state across PDF buttons
2. `syncPrintHover(show)` - Sync hover state across print buttons
3. `highlightZoomControl(show)` - Highlight zoom control on hover
### Zoom Functions (zoom._hs)
1. `handleZoomInput(slider)` - Handle zoom slider input changes
2. `handleZoomReset()` - Reset zoom to 100%
3. `initZoomControl(control)` - Initialize zoom control on page load
4. `showZoomControl()` - Show the zoom control panel
5. `hideZoomControl()` - Hide the zoom control panel
6. `toggleZoomControl()` - Toggle zoom control visibility
7. `isZoomDragTarget(el)` - Check if element is valid drag target (not button/input)
8. `startZoomDrag(control, clientX, clientY)` - Start dragging zoom control
9. `moveZoomDrag(control, clientX, clientY)` - Handle drag movement
10. `endZoomDrag(control)` - End drag and save position
### Navigation Functions (moved to utils._hs)
*Note: `scrollToSection` moved to utils._hs for consolidation*
## Why These Rules Exist
### Maintainability
- Functions with descriptive names are self-documenting
- Easier to test and debug
- Changes in one place instead of scattered across templates
### Performance
- Browser caches .\_hs files
- Reduces HTML payload size
- Cleaner separation of concerns
### Historical Note: Hyperscript Def Limit
- **Hyperscript 0.9.12** had a 3-def limit per file (FIXED in 0.9.14+)
- **Hyperscript 0.9.14+** has NO def limit - tested with 5+ defs
- Multi-file organization is still recommended for maintainability, not required
## Common Mistakes to Avoid
❌ **DON'T**: Write long inline hyperscript in HTML (maintainability issue)
❌ **DON'T**: Try to externalize event handlers that inspect `event.key` or `event.target`
❌ **DON'T**: Forget to test after refactoring (syntax errors look like bugs)
❌ **DON'T**: Use `target` as a parameter name - it's a reserved word!
✅ **DO**: Split functions across multiple .\_hs files for organization
✅ **DO**: Keep HTML clean with function calls
✅ **DO**: Test all keyboard shortcuts after any hyperscript changes
✅ **DO**: Use `el` instead of `target` when passing DOM elements to functions
### Reserved Words in Hyperscript
The following are reserved and reference special values in hyperscript:
- `target` → `event.target` (the element that triggered the event)
- `me` → The current element with the `_=""` attribute
- `it` → The result of the previous command
- `event` → The current event object
**Example of the `target` pitfall:**
```hyperscript
-- ❌ WRONG - 'target' is reserved, will reference event.target
def checkElement(target)
if target.tagName is 'INPUT' -- ERROR: target is null in function context
return false
end
end
-- ✅ CORRECT - use 'el' instead
def checkElement(el)
if el.tagName is 'INPUT'
return false
end
end
```
## Testing After Changes
1. Check browser console for parse errors
2. Verify all functions are defined (no "X is null" errors)
3. Test all toggles work correctly
4. Hard refresh browser (Ctrl+Shift+R) to clear cache
---
## Recent Changes
### 2025-11-30: Major Inline Hyperscript Refactoring (Phase 2)
- ✅ **REFACTORED**: Modal backdrop close (3 modals) → `closeOnBackdrop()` in `utils._hs`
- ✅ **REFACTORED**: Back-to-top button → `scrollToTop()` in `utils._hs`
- ✅ **REFACTORED**: Zoom drag handlers (~35 lines) → 4 functions in `zoom._hs`
- ✅ **ADDED**: `isZoomDragTarget()`, `startZoomDrag()`, `moveZoomDrag()`, `endZoomDrag()`
- ✅ **ADDED**: `showZoomControl()`, `hideZoomControl()`, `toggleZoomControl()`
- ✅ **MOVED**: `expandAllSections()`, `collapseAllSections()` to `utils._hs`
- ✅ **MOVED**: `scrollToSection()` to `utils._hs` with integrated menu close
- ✅ **LEARNING**: `target` is a reserved word in hyperscript (use `el` instead)
- ✅ **TESTED**: All 21 functions verified, 6 functional tests passed
### 2025-11-30: Major Inline Hyperscript Refactoring (Phase 1)
- ✅ **REFACTORED**: Body tag keyboard handlers → `keyboard._hs` helper functions
- ✅ **REFACTORED**: Zoom control handlers → `zoom._hs` helper functions
- ✅ **REFACTORED**: PDF modal card selection (3 identical blocks) → `pdf-modal._hs`
- ✅ **ADDED**: `zoom._hs` - Zoom control helpers (handleZoomInput, handleZoomReset, initZoomControl)
- ✅ **ADDED**: `pdf-modal._hs` - PDF modal helpers (selectPdfCard, handlePdfCardKey)
- ✅ **TESTED**: All functionality verified with comprehensive tests
### 2025-11-30: Multi-File Loading Bug Investigation
- ✅ **CONFIRMED**: Multiple `