// jogwheel.js — Jogwheel synchronization for calendar scrolling export class JogwheelManager { constructor(calendar) { this.calendar = calendar this.viewport = null this.content = null this.syncLock = null this.init() } init() { this.viewport = document.getElementById('jogwheel-viewport') this.content = document.getElementById('jogwheel-content') if (!this.viewport || !this.content) { console.warn('Jogwheel elements not found - jogwheel functionality disabled') return } this.setupScrollSync() } setupScrollSync() { // Check if calendar viewport is available if (!this.calendar.viewport || !this.calendar.content) { console.warn('Calendar viewport not available - jogwheel sync disabled') return } // Bind sync function to maintain proper context const sync = this.sync.bind(this) this.viewport.addEventListener('scroll', () => sync(this.viewport, this.calendar.viewport, this.content, this.calendar.content) ) this.calendar.viewport.addEventListener('scroll', () => sync(this.calendar.viewport, this.viewport, this.calendar.content, this.content) ) } sync(fromEl, toEl, fromContent, toContent) { if (this.syncLock === toEl) return this.syncLock = fromEl const fromScrollable = Math.max(0, fromContent.scrollHeight - fromEl.clientHeight) const toScrollable = Math.max(0, toContent.scrollHeight - toEl.clientHeight) const ratio = fromScrollable > 0 ? fromEl.scrollTop / fromScrollable : 0 toEl.scrollTop = ratio * toScrollable setTimeout(() => { if (this.syncLock === fromEl) this.syncLock = null }, 50) } updateHeight(totalVirtualWeeks, rowHeight) { if (this.content) { this.content.style.height = `${(totalVirtualWeeks * rowHeight) / 10}px` } } scrollTo(targetScrollTop, mainScrollable, smooth = false) { if (!this.viewport || !this.content) return const jogScrollable = Math.max(0, this.content.scrollHeight - this.viewport.clientHeight) const jogwheelTarget = mainScrollable > 0 ? (targetScrollTop / mainScrollable) * jogScrollable : 0 if (smooth) { this.viewport.scrollTo({ top: jogwheelTarget, behavior: 'smooth' }) } else { this.viewport.scrollTop = jogwheelTarget } } isAvailable() { return !!(this.viewport && this.content) } }