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
|
lunarPhaseSymbol
|
||||||
} from './date-utils.js'
|
} from './date-utils.js'
|
||||||
import { EventManager } from './event-manager.js'
|
import { EventManager } from './event-manager.js'
|
||||||
|
import { JogwheelManager } from './jogwheel.js'
|
||||||
|
|
||||||
class InfiniteCalendar {
|
class InfiniteCalendar {
|
||||||
constructor(config = {}) {
|
constructor(config = {}) {
|
||||||
@ -33,10 +34,11 @@ class InfiniteCalendar {
|
|||||||
this.viewport = document.getElementById('calendar-viewport')
|
this.viewport = document.getElementById('calendar-viewport')
|
||||||
this.content = document.getElementById('calendar-content')
|
this.content = document.getElementById('calendar-content')
|
||||||
this.header = document.getElementById('calendar-header')
|
this.header = document.getElementById('calendar-header')
|
||||||
this.jogwheelViewport = document.getElementById('jogwheel-viewport')
|
|
||||||
this.jogwheelContent = document.getElementById('jogwheel-content')
|
|
||||||
this.selectedDateInput = document.getElementById('selected-date')
|
this.selectedDateInput = document.getElementById('selected-date')
|
||||||
|
|
||||||
|
// Initialize jogwheel manager after DOM elements are available
|
||||||
|
this.jogwheelManager = new JogwheelManager(this)
|
||||||
|
|
||||||
this.rowHeight = this.computeRowHeight()
|
this.rowHeight = this.computeRowHeight()
|
||||||
this.visibleWeeks = new Map()
|
this.visibleWeeks = new Map()
|
||||||
this.baseDate = new Date(2024, 0, 1) // 2024 begins with Monday
|
this.baseDate = new Date(2024, 0, 1) // 2024 begins with Monday
|
||||||
@ -45,7 +47,6 @@ class InfiniteCalendar {
|
|||||||
} init() {
|
} init() {
|
||||||
this.createHeader()
|
this.createHeader()
|
||||||
this.setupScrollListener()
|
this.setupScrollListener()
|
||||||
this.setupJogwheel()
|
|
||||||
this.setupYearScroll()
|
this.setupYearScroll()
|
||||||
this.setupSelectionInput()
|
this.setupSelectionInput()
|
||||||
this.setupCurrentDate()
|
this.setupCurrentDate()
|
||||||
@ -63,7 +64,7 @@ class InfiniteCalendar {
|
|||||||
this.totalVirtualWeeks = this.maxVirtualWeek - this.minVirtualWeek + 1
|
this.totalVirtualWeeks = this.maxVirtualWeek - this.minVirtualWeek + 1
|
||||||
|
|
||||||
this.content.style.height = `${this.totalVirtualWeeks * this.rowHeight}px`
|
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
|
const initial = this.config.initial || this.today
|
||||||
this.navigateTo(fromLocalString(initial))
|
this.navigateTo(fromLocalString(initial))
|
||||||
}
|
}
|
||||||
@ -149,11 +150,7 @@ class InfiniteCalendar {
|
|||||||
else this.viewport.scrollTop = targetScrollTop
|
else this.viewport.scrollTop = targetScrollTop
|
||||||
|
|
||||||
const mainScrollable = Math.max(0, this.content.scrollHeight - this.viewport.clientHeight)
|
const mainScrollable = Math.max(0, this.content.scrollHeight - this.viewport.clientHeight)
|
||||||
const jogScrollable = Math.max(0, this.jogwheelContent.scrollHeight - this.jogwheelViewport.clientHeight)
|
this.jogwheelManager.scrollTo(targetScrollTop, mainScrollable, smooth)
|
||||||
const jogwheelTarget = mainScrollable > 0 ? (targetScrollTop / mainScrollable) * jogScrollable : 0
|
|
||||||
|
|
||||||
if (smooth) this.jogwheelViewport.scrollTo({ top: jogwheelTarget, behavior: 'smooth' })
|
|
||||||
else this.jogwheelViewport.scrollTop = jogwheelTarget
|
|
||||||
|
|
||||||
if (forceUpdate) this.updateVisibleWeeks()
|
if (forceUpdate) this.updateVisibleWeeks()
|
||||||
return true
|
return true
|
||||||
@ -415,27 +412,6 @@ class InfiniteCalendar {
|
|||||||
return weekDiv
|
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() {
|
setupSelectionInput() {
|
||||||
if (this.config.select_days === 0) {
|
if (this.config.select_days === 0) {
|
||||||
this.selectedDateInput.style.display = 'none'
|
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