Fix date selection position preservation in calendar carousel

This commit is contained in:
2025-11-07 20:31:19 +03:00
parent 7670a375ec
commit ed2647e45c

View File

@@ -36,10 +36,46 @@ class DateCarousel {
this.maxInputId = maxInputId;
this.minInput = document.getElementById(minInputId);
this.maxInput = document.getElementById(maxInputId);
this.centerDate = new Date(); // Центральная дата (по умолчанию сегодня)
this.today = new Date();
this.today.setHours(0, 0, 0, 0);
this.daysCount = 0; // Будет рассчитано динамически
// Загружаем сохранённую дату из localStorage или устанавливаем сегодня
const savedData = this.loadSavedCenterDate();
if (savedData) {
// Если есть смещение, это означает, что дата была выбрана пользователем
if (savedData.offset !== 0) {
// Проверяем, есть ли выбранная дата в фильтрах
if (this.minInput && this.minInput.value && this.maxInput.value &&
this.minInput.value === this.maxInput.value) {
// Получаем выбранную дату из фильтра
const parts = this.minInput.value.split('-');
if (parts.length === 3) {
const selectedDate = new Date(
parseInt(parts[0]),
parseInt(parts[1]) - 1,
parseInt(parts[2])
);
selectedDate.setHours(0, 0, 0, 0);
// Вычисляем центральную дату: выбранная дата минус смещение
this.centerDate = new Date(selectedDate);
this.centerDate.setDate(this.centerDate.getDate() - savedData.offset);
} else {
// Если дата в фильтре некорректна, используем сохранённую центральную дату
this.centerDate = savedData.centerDate;
}
} else {
// Если нет фильтра с одной датой, используем сохранённую центральную дату
this.centerDate = savedData.centerDate;
}
} else {
// Если смещения нет, используем сохранённую центральную дату
this.centerDate = savedData.centerDate;
}
} else {
this.centerDate = new Date();
}
}
/**
@@ -48,6 +84,44 @@ class DateCarousel {
init() {
this.calculateDaysCount();
this.loadSelectedDate(); // Загрузить выбранную дату из фильтра
// Если в localStorage есть сохраненные данные
const savedData = this.loadSavedCenterDate();
if (savedData) {
// Если есть смещение, это означает, что дата была выбрана пользователем
if (savedData.offset !== 0) {
// Проверяем, есть ли выбранная дата в фильтрах
if (this.minInput.value && this.maxInput.value &&
this.minInput.value === this.maxInput.value) {
// Получаем выбранную дату из фильтра
const parts = this.minInput.value.split('-');
if (parts.length === 3) {
const selectedDate = new Date(
parseInt(parts[0]),
parseInt(parts[1]) - 1,
parseInt(parts[2])
);
selectedDate.setHours(0, 0, 0, 0);
// Вычисляем центральную дату: выбранная дата минус смещение
// (т.к. смещение показывает, на сколько дней выбранная дата
// смещена вправо от центра)
this.centerDate = new Date(selectedDate);
this.centerDate.setDate(this.centerDate.getDate() - savedData.offset);
} else {
// Если дата в фильтре некорректна, используем сохранённую центральную дату
this.centerDate = savedData.centerDate;
}
} else {
// Если нет фильтра с одной датой, используем сохранённую центральную дату
this.centerDate = savedData.centerDate;
}
} else {
// Если смещения нет, используем сохранённую центральную дату
this.centerDate = savedData.centerDate;
}
}
this.render();
this.attachNavHandlers();
}
@@ -56,7 +130,7 @@ class DateCarousel {
* Загрузка выбранной даты из скрытых полей фильтра
*/
loadSelectedDate() {
// Если есть выбранная дата в фильтре, центрируем на ней, чтобы она была видна
// Если есть выбранная дата в фильтре
if (this.minInput.value && this.maxInput.value &&
this.minInput.value === this.maxInput.value) {
const parts = this.minInput.value.split('-');
@@ -68,9 +142,17 @@ class DateCarousel {
);
selectedDate.setHours(0, 0, 0, 0);
// Центрируем на выбранной дате, чтобы она всегда была видна
this.centerDate = selectedDate;
console.log(`Centering on selected date: ${this.formatDate(selectedDate)}`);
// Устанавливаем центральную дату на выбранную дату только если фильтр отличается от сегодняшней даты
// Это позволяет определить, был ли фильтр установлен до посещения страницы
const todayFormatted = this.formatDate(this.today);
if (this.minInput.value !== todayFormatted) {
// Возможно, фильтр уже был установлен, но мы всё равно не хотим центрировать
// для согласованности с поведением после выбора даты
console.log(`Selected date in filter: ${this.formatDate(selectedDate)}, keeping current view`);
} else {
// Если фильтр равен сегодняшней дате, можно центрировать на сегодня
console.log(`Filter is today: ${this.formatDate(selectedDate)}, keeping current view`);
}
}
} else {
// Если фильтра нет, центрируем на сегодняшнем дне
@@ -252,18 +334,19 @@ class DateCarousel {
this.minInput.value = formattedDate;
this.maxInput.value = formattedDate;
// Обновляем центральную дату, чтобы выбранная дата была в центре
this.centerDate = new Date(date);
this.centerDate.setHours(0, 0, 0, 0);
// Вычисляем смещение выбранной даты от центра
const offset = this.calculateDateOffset(date);
// Сохраняем центральную дату и смещение перед отправкой формы
this.saveCenterDate(offset);
// Визуальная обратная связь
btn.classList.add('clicked');
setTimeout(() => btn.classList.remove('clicked'), 300);
// Обновление визуального состояния
// Обновление визуального состояния (без изменения центральной даты)
this.render();
console.log(`Selected date: ${formattedDate}`);
console.log(`Selected date: ${formattedDate}, offset: ${offset}`);
// Автоматическая отправка формы
const form = this.minInput.closest('form');
@@ -287,12 +370,82 @@ class DateCarousel {
nextBtn.addEventListener('click', () => this.shiftDays(1));
}
}
/**
* Сохранение центральной даты и смещения в localStorage
*/
saveCenterDate(offset = 0) {
const key = `date_carousel_center_${this.minInputId}`;
const centerDateStr = this.centerDate.toISOString().split('T')[0]; // Формат YYYY-MM-DD
const saveData = {
centerDate: centerDateStr,
offset: offset
};
localStorage.setItem(key, JSON.stringify(saveData));
}
/**
* Загрузка центральной даты из localStorage
*/
loadSavedCenterDate() {
const key = `date_carousel_center_${this.minInputId}`;
const savedDataStr = localStorage.getItem(key);
if (savedDataStr) {
try {
const savedData = JSON.parse(savedDataStr);
const savedDate = new Date(savedData.centerDate);
savedDate.setHours(0, 0, 0, 0);
return {
centerDate: savedDate,
offset: savedData.offset || 0
};
} catch (e) {
console.error('Error parsing saved date data', e);
// В случае ошибки возвращаем старый формат для совместимости
const savedDateStr = localStorage.getItem(key);
if (savedDateStr && !savedDateStr.includes('{')) {
const savedDate = new Date(savedDateStr);
savedDate.setHours(0, 0, 0, 0);
return {
centerDate: savedDate,
offset: 0
};
}
return null;
}
}
return null;
}
/**
* Вычисление смещения выбранной даты от центральной
*/
calculateDateOffset(selectedDate) {
// Генерируем дни с текущей центральной датой
const days = this.generateDays();
// Находим индекс выбранной даты
const selectedIndex = days.findIndex(day =>
day.date.getTime() === selectedDate.getTime()
);
if (selectedIndex !== -1) {
// Находим центральный индекс
const centerIndex = Math.floor(this.daysCount / 2);
// Вычисляем смещение от центра
return selectedIndex - centerIndex;
}
return 0; // Если дата не найдена, возвращаем 0
}
/**
* Сдвиг диапазона дней на N дней
*/
shiftDays(offset) {
this.centerDate.setDate(this.centerDate.getDate() + offset);
this.saveCenterDate(); // Сохраняем новую центральную дату (без смещения для прокрутки)
this.render();
}
}