sync

Synced navigation between two card stacks — source stack navigation drives target stack to same index

Sync JS Generator

Generates a standalone JS snippet that syncs a target card stack to the source card stack’s focused index. When enabled, any navigation in the source stack triggers htmx.ajax('POST', targetUrl, ...) to navigate the target stack to the same index.

The sync uses an htmx:afterSettle handler that reads the source stack’s hidden focused_index input by ID on each event. This deferred lookup works even if the source stack hasn’t initialized when the JS first runs.

Out-of-range indices are clamped server-side by nav_to_index.

Listener cleanup

Uses a keyed window reference pattern to remove previous handlers on re-render, preventing accumulation across step navigation.


source

generate_card_stack_sync_js


def generate_card_stack_sync_js(
    source_input_id:str, # ID of source stack's focused_index hidden input
    target_nav_url:str, # URL for target stack's nav_to_index route
    toggle_fn_name:str='toggleSyncedNav', # Name for window toggle function
    sync_key:str='_cardStackSync', # Window key for state + cleanup
)->str: # Standalone JS snippet (not inside any IIFE)

Generate JS for synced navigation between two card stacks.

Source stack navigation drives target stack to the same focused index. Toggle on/off via windowtoggle_fn_name or toolbar button.

The settle handler and source input lookup are deferred — they work even if the source stack hasn’t initialized when this JS first runs. Out-of-range indices are clamped server-side by nav_to_index.

Tests

# Test basic generation
js = generate_card_stack_sync_js(
    source_input_id="seg-focused-index",
    target_nav_url="/align/nav_to_index",
    toggle_fn_name="toggleSyncedNav",
    sync_key="_segAlignSync",
)

# Verify key elements are present
assert 'toggleSyncedNav' in js
assert '_segAlignSync' in js
assert 'seg-focused-index' in js
assert '/align/nav_to_index' in js
assert 'htmx.ajax' in js
assert 'state.enabled' in js
assert 'afterSettle' in js
assert 'lastSyncedIndex' in js  # Dedup guard
assert 'removeEventListener' in js  # Cleanup

# Verify settle handler is registered unconditionally (no sourceInput gate)
assert 'document.body.addEventListener' in js

print('Sync JS generator tests passed')