Refactor jogwheel to its own module.
This commit is contained in:
parent
b8b8575c6d
commit
a92ef0479a
36
calendar.js
36
calendar.js
@ -15,6 +15,7 @@ import {
|
||||
lunarPhaseSymbol
|
||||
} from './date-utils.js'
|
||||
import { EventManager } from './event-manager.js'
|
||||
import { JogwheelManager } from './jogwheel.js'
|
||||
|
||||
class InfiniteCalendar {
|
||||
constructor(config = {}) {
|
||||
@ -33,10 +34,11 @@ class InfiniteCalendar {
|
||||
this.viewport = document.getElementById('calendar-viewport')
|
||||
this.content = document.getElementById('calendar-content')
|
||||
this.header = document.getElementById('calendar-header')
|
||||
this.jogwheelViewport = document.getElementById('jogwheel-viewport')
|
||||
this.jogwheelContent = document.getElementById('jogwheel-content')
|
||||
this.selectedDateInput = document.getElementById('selected-date')
|
||||
|
||||
// Initialize jogwheel manager after DOM elements are available
|
||||
this.jogwheelManager = new JogwheelManager(this)
|
||||
|
||||
this.rowHeight = this.computeRowHeight()
|
||||
this.visibleWeeks = new Map()
|
||||
this.baseDate = new Date(2024, 0, 1) // 2024 begins with Monday
|
||||
@ -45,7 +47,6 @@ class InfiniteCalendar {
|
||||
} init() {
|
||||
this.createHeader()
|
||||
this.setupScrollListener()
|
||||
this.setupJogwheel()
|
||||
this.setupYearScroll()
|
||||
this.setupSelectionInput()
|
||||
this.setupCurrentDate()
|
||||
@ -63,7 +64,7 @@ class InfiniteCalendar {
|
||||
this.totalVirtualWeeks = this.maxVirtualWeek - this.minVirtualWeek + 1
|
||||
|
||||
this.content.style.height = `${this.totalVirtualWeeks * this.rowHeight}px`
|
||||
this.jogwheelContent.style.height = `${(this.totalVirtualWeeks * this.rowHeight) / 10}px`
|
||||
this.jogwheelManager.updateHeight(this.totalVirtualWeeks, this.rowHeight)
|
||||
const initial = this.config.initial || this.today
|
||||
this.navigateTo(fromLocalString(initial))
|
||||
}
|
||||
@ -149,11 +150,7 @@ class InfiniteCalendar {
|
||||
else this.viewport.scrollTop = targetScrollTop
|
||||
|
||||
const mainScrollable = Math.max(0, this.content.scrollHeight - this.viewport.clientHeight)
|
||||
const jogScrollable = Math.max(0, this.jogwheelContent.scrollHeight - this.jogwheelViewport.clientHeight)
|
||||
const jogwheelTarget = mainScrollable > 0 ? (targetScrollTop / mainScrollable) * jogScrollable : 0
|
||||
|
||||
if (smooth) this.jogwheelViewport.scrollTo({ top: jogwheelTarget, behavior: 'smooth' })
|
||||
else this.jogwheelViewport.scrollTop = jogwheelTarget
|
||||
this.jogwheelManager.scrollTo(targetScrollTop, mainScrollable, smooth)
|
||||
|
||||
if (forceUpdate) this.updateVisibleWeeks()
|
||||
return true
|
||||
@ -415,27 +412,6 @@ class InfiniteCalendar {
|
||||
return weekDiv
|
||||
}
|
||||
|
||||
setupJogwheel() {
|
||||
let lock = null
|
||||
const sync = (fromEl, toEl, fromContent, toContent) => {
|
||||
if (lock === toEl) return
|
||||
lock = 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 (lock === fromEl) lock = null }, 50)
|
||||
}
|
||||
|
||||
this.jogwheelViewport.addEventListener('scroll', () =>
|
||||
sync(this.jogwheelViewport, this.viewport, this.jogwheelContent, this.content)
|
||||
)
|
||||
|
||||
this.viewport.addEventListener('scroll', () =>
|
||||
sync(this.viewport, this.jogwheelViewport, this.content, this.jogwheelContent)
|
||||
)
|
||||
}
|
||||
|
||||
setupSelectionInput() {
|
||||
if (this.config.select_days === 0) {
|
||||
this.selectedDateInput.style.display = 'none'
|
||||
|
79
jogwheel.js
Normal file
79
jogwheel.js
Normal file
@ -0,0 +1,79 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user