1// ÐлеменÑÑ DOM 2const openModalBtn = document.querySelectorAll('.openModal'); 3const closeModalBtn = document.getElementById('closeModal'); 4const modal = document.getElementById('dateModal'); 5const showToursBtn = document.getElementById('showTours'); 6const setDate = document.getElementById('setDate'); 7const resetBtn = document.getElementById('resetBtn'); 8const calendarsContainer = document.getElementById('calendarsContainer'); 9let target = null; 10 11// СоÑÑоÑние вÑбÑаннÑÑ Ð´Ð°Ñ 12let selectedDates = []; 13 14// ÐÐ°Ð·Ð²Ð°Ð½Ð¸Ñ Ð¼ÐµÑÑÑев 15const monthNames = [ 16 'ЯнваÑÑ', 'ФевÑалÑ', 'ÐаÑÑ', 'ÐпÑелÑ', 'Ðай', 'ÐÑнÑ', 17 'ÐÑлÑ', 'ÐвгÑÑÑ', 'СенÑÑбÑÑ', 'ÐкÑÑбÑÑ', 'ÐоÑбÑÑ', 'ÐекабÑÑ' 18]; 19 20// ÐÑкÑÑÑие модалÑного окна 21openModalBtn.forEach(e => e.addEventListener('click', (event) => { 22 event.preventDefault(); 23 modal.classList.add('active'); 24 target = event.target.closest('.openModal')?.dataset?.field || null; 25 if (target) { 26 generateCalendars(); 27 showToursBtn.style.display = "none"; 28 setDate.style.display = "block"; 29 } else { 30 generateCalendars(); 31 showToursBtn.style.display = "block"; 32 setDate.style.display = "none"; 33 } 34 document.body.style.overflow = 'hidden'; 35})); 36 37// ÐакÑÑÑие модалÑного окна 38closeModalBtn.addEventListener('click', closeModal); 39showToursBtn.addEventListener('click', showTours); 40resetBtn.addEventListener('click', resetDates); 41setDate.addEventListener('click', insertDate); 42 43// ÐакÑÑÑие по ÐºÐ»Ð¸ÐºÑ Ð½Ð° Ñон 44modal.addEventListener('click', (e) => { 45 if (e.target === modal) { 46 closeModal(); 47 } 48}); 49 50function closeModal() { 51 modal.classList.remove('active'); 52 document.body.style.overflow = 'auto'; 53} 54 55// ФоÑмаÑиÑование даÑÑ Ð´Ð»Ñ URL (YYYY-MM-DD) 56function formatDateForUrl(date) { 57 const year = date.getFullYear();
58 const month = String(date.getMonth() + 1).padStart(2, '0'); 59 const day = String(date.getDate()).padStart(2, '0'); 60 return `${year}-${month}-${day}`; 61} 62 63// ÐеÑÐµÑ Ð¾Ð´ на ÑÑÑаниÑÑ Ñ ÑкÑкÑÑÑиÑми 64function insertDate() { 65 if (target) { 66 document.querySelector(`input[name=${target}`).value = formatDateForUrl(selectedDates[0]); 67 closeModal(); 68 } 69} 70 71// ÐеÑÐµÑ Ð¾Ð´ на ÑÑÑаниÑÑ Ñ ÑкÑкÑÑÑиÑми 72function showTours() { 73 // ÐÑли даÑÑ Ð½Ðµ вÑбÑÐ°Ð½Ñ - оÑкÑÑваем ÑÑÑаниÑÑ Ð±ÐµÐ· паÑамеÑÑов 74 if (selectedDates.length === 0) { 75 window.location.href = '/tours/all'; 76 return; 77 } 78 79 let url = '/tours/'; 80 81 if (selectedDates.length === 1) { 82 // Ðдна даÑа 83 url += `all?date=${formatDateForUrl(selectedDates[0])}`; 84 } else if (selectedDates.length === 2) { 85 // Ðиапазон Ð´Ð°Ñ 86 url += `interval?date-in=${formatDateForUrl(selectedDates[0])}&date-out=${formatDateForUrl(selectedDates[1])}`; 87 } 88 89 // ÐеÑÐµÑ Ð¾Ð´ на ÑÑÑаниÑÑ Ñ ÑкÑкÑÑÑиÑми 90 window.location.href = url; 91} 92 93// СбÑÐ¾Ñ Ð²ÑбÑаннÑÑ Ð´Ð°Ñ 94function resetDates() { 95 selectedDates = []; 96 clearAllSelections(); 97 updateResetButton(); 98} 99 100// Ðбновление ÑоÑÑоÑÐ½Ð¸Ñ ÐºÐ½Ð¾Ð¿ÐºÐ¸ "СбÑоÑиÑÑ" 101function updateResetButton() { 102 if (selectedDates.length === 0) { 103 resetBtn.disabled = true; 104 } else { 105 resetBtn.disabled = false; 106 } 107} 108 109// ÐенеÑаÑÐ¸Ñ ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñей 110function generateCalendars() { 111 const today = new Date(); 112 calendarsContainer.innerHTML = ''; 113 114 let monthes = 12; 115 if (target) monthes = 12; 116 117 for (let i = 0; i < monthes; i++) { 118 const currentMonth = new Date(today.getFullYear(), today.getMonth() + i, 1); 119 const monthDiv = createMonthCalendar(currentMonth); 120 calendarsContainer.appendChild(monthDiv); 121 } 122} 123 124// Создание календаÑÑ Ð½Ð° один меÑÑÑ 125function createMonthCalendar(date) { 126 const monthDiv = document.createElement('div'); 127 monthDiv.className = 'month-calendar'; 128 129 // Ðаголовок меÑÑÑа 130 const monthTitle = document.createElement('div'); 131 monthTitle.className = 'month-title'; 132 monthTitle.textContent = `${monthNames[date.getMonth()]} ${date.getFullYear()}`; 133 monthDiv.appendChild(monthTitle); 134 135 // СеÑка календаÑÑ 136 const calendarGrid = document.createElement('div'); 137 calendarGrid.className = 'calendar-grid'; 138 139 const year = date.getFullYear();
140 const month = date.getMonth(); 141 142 // ÐеÑвÑй Ð´ÐµÐ½Ñ Ð¼ÐµÑÑÑа и колиÑеÑÑво дней 143 const firstDay = new Date(year, month, 1); 144 const lastDay = new Date(year, month + 1, 0); 145 const daysInMonth = lastDay.getDate(); 146 147 // ÐпÑеделÑем Ð´ÐµÐ½Ñ Ð½ÐµÐ´ÐµÐ»Ð¸ (понеделÑник = 0, воÑкÑеÑенÑе = 6) 148 let firstDayOfWeek = firstDay.getDay() - 1; 149 if (firstDayOfWeek === -1) firstDayOfWeek = 6; 150 151 // ÐÑÑÑÑе ÑÑейки до наÑала меÑÑÑа 152 for (let i = 0; i < firstDayOfWeek; i++) { 153 const emptyDay = document.createElement('div'); 154 emptyDay.className = 'calendar-day empty'; 155 calendarGrid.appendChild(emptyDay); 156 } 157 158 // Ðни меÑÑÑа 159 const today = new Date(); 160 today.setHours(0, 0, 0, 0); 161 162 for (let day = 1; day <= daysInMonth; day++) { 163 const dayDiv = document.createElement('div'); 164 dayDiv.className = 'calendar-day'; 165 dayDiv.textContent = day; 166 167 const currentDate = new Date(year, month, day); 168 currentDate.setHours(0, 0, 0, 0); 169 170 // ÐÑовеÑка на вÑÑ Ð¾Ð´Ð½Ñе (ÑÑббоÑа = 6, воÑкÑеÑенÑе = 0) 171 const dayOfWeek = currentDate.getDay(); 172 if (dayOfWeek === 0 || dayOfWeek === 6) { 173 dayDiv.classList.add('weekend'); 174 } 175 176 // ÐÑклÑÑаем пÑоÑедÑие даÑÑ 177 if (currentDate < today) { 178 dayDiv.classList.add('disabled'); 179 } else { 180 dayDiv.addEventListener('click', () => selectDate(currentDate, dayDiv)); 181 // ÐобавлÑем обÑабоÑÑик Ð½Ð°Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¿ÑевÑÑ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð° 182 dayDiv.addEventListener('mouseenter', () => previewRange(currentDate)); 183 } 184 185 // Ð¡Ð¾Ñ ÑанÑем даÑÑ Ð² аÑÑибÑÑе 186 dayDiv.dataset.date = currentDate.toISOString(); 187 188 calendarGrid.appendChild(dayDiv); 189 } 190 191 monthDiv.appendChild(calendarGrid); 192 return monthDiv; 193} 194 195// ÐÑÐ±Ð¾Ñ Ð´Ð°ÑÑ 196function selectDate(date, element) { 197 const dateStr = date.toISOString(); 198 199 if (selectedDates.length === 0) { 200 // ÐеÑÐ²Ð°Ñ Ð´Ð°Ñа 201 selectedDates.push(date); 202 element.classList.add('selected'); 203 } else if (selectedDates.length === 1) { 204 // ÐÑоÑÐ°Ñ Ð´Ð°Ñа 205 const firstDate = selectedDates[0]; 206 207 if (date.getTime() === firstDate.getTime()) { 208 // Ðлик на ÑÑ Ð¶Ðµ даÑÑ - ÑбÑÐ¾Ñ 209 selectedDates = []; 210 clearAllSelections(); 211 } else { 212 // ÐобавлÑем вÑоÑÑÑ Ð´Ð°ÑÑ Ð¸ ÑоÑÑиÑÑем 213 selectedDates.push(date); 214 selectedDates.sort((a, b) => a - b); 215 updateCalendarDisplay(); 216 } 217 } else { 218 // СбÑÐ¾Ñ Ð¸ вÑÐ±Ð¾Ñ Ð½Ð¾Ð²Ð¾Ð¹ даÑÑ 219 selectedDates = [date]; 220 clearAllSelections(); 221 element.classList.add('selected'); 222 } 223 224 // ÐбновлÑем ÑоÑÑоÑние кнопки "СбÑоÑиÑÑ" 225 updateResetButton(); 226} 227 228// Ðбновление оÑобÑÐ°Ð¶ÐµÐ½Ð¸Ñ ÐºÐ°Ð»ÐµÐ½Ð´Ð°ÑÑ 229function updateCalendarDisplay() { 230 clearAllSelections(); 231 232 if (selectedDates.length === 0) return; 233 234 const allDays = document.querySelectorAll('.calendar-day:not(.empty):not(.disabled)'); 235 236 allDays.forEach(dayDiv => { 237 const dayDate = new Date(dayDiv.dataset.date); 238 dayDate.setHours(0, 0, 0, 0); 239 240 if (selectedDates.length === 1) { 241 // ТолÑко одна даÑа 242 if (dayDate.getTime() === selectedDates[0].getTime()) { 243 dayDiv.classList.add('selected'); 244 } 245 } else if (selectedDates.length === 2) { 246 const startDate = selectedDates[0]; 247 const endDate = selectedDates[1]; 248 249 if (dayDate.getTime() === startDate.getTime() || dayDate.getTime() === endDate.getTime()) { 250 dayDiv.classList.add('selected'); 251 } else if (dayDate > startDate && dayDate < endDate) { 252 dayDiv.classList.add('in-range'); 253 } 254 } 255 }); 256} 257 258// ÐÑиÑÑка вÑÐµÑ Ð²Ñделений 259function clearAllSelections() { 260 const allDays = document.querySelectorAll('.calendar-day'); 261 allDays.forEach(day => { 262 day.classList.remove('selected', 'in-range', 'preview-range'); 263 }); 264} 265 266// ÐÑевÑÑ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð° пÑи наведении 267function previewRange(hoverDate) { 268 // ÐоказÑваем пÑевÑÑ ÑолÑко еÑли вÑбÑана одна даÑа 269 if (selectedDates.length !== 1) return; 270 271 const firstDate = selectedDates[0]; 272 273 // ÐÑиÑаем ÑолÑко пÑевÑÑ, ÑÐ¾Ñ ÑанÑÑ selected 274 const allDays = document.querySelectorAll('.calendar-day'); 275 allDays.forEach(day => { 276 day.classList.remove('preview-range'); 277 }); 278 279 // ÐÑли наведение на ÑÑ Ð¶Ðµ даÑÑ, ÑÑо Ñже вÑбÑана - не показÑваем пÑевÑÑ 280 if (hoverDate.getTime() === firstDate.getTime()) return; 281 282 // ÐпÑеделÑем наÑалÑнÑÑ Ð¸ конеÑнÑÑ Ð´Ð°ÑÑ Ð´Ð»Ñ Ð¿ÑевÑÑ 283 const startDate = hoverDate < firstDate ? hoverDate : firstDate; 284 const endDate = hoverDate > firstDate ? hoverDate : firstDate; 285 286 // ÐÑименÑем пÑевÑÑ Ðº даÑам в диапазоне 287 allDays.forEach(dayDiv => { 288 if (dayDiv.classList.contains('empty') || dayDiv.classList.contains('disabled')) return; 289 290 const dayDate = new Date(dayDiv.dataset.date); 291 dayDate.setHours(0, 0, 0, 0); 292 293 // ÐобавлÑем пÑевÑÑ Ð´Ð»Ñ Ð´Ð°Ñ Ð¼ÐµÐ¶Ð´Ñ Ð²ÑбÑанной и ÑекÑÑей 294 if (dayDate > startDate && dayDate < endDate) { 295 dayDiv.classList.add('preview-range'); 296 } 297 }); 298} 299 300// ÐÑиÑÑка пÑевÑÑ Ð¿Ñи ÑÑ Ð¾Ð´Ðµ кÑÑÑоÑа Ñ ÐºÐ°Ð»ÐµÐ½Ð´Ð°ÑÑ 301function clearPreview() { 302 // ÐÑиÑаем пÑевÑÑ ÑолÑко еÑли вÑбÑана одна даÑа 303 if (selectedDates.length === 1) { 304 const allDays = document.querySelectorAll('.calendar-day'); 305 allDays.forEach(day => { 306 day.classList.remove('preview-range'); 307 }); 308 } 309} 310 311// ÐобавлÑем обÑабоÑÑик ÑÑ Ð¾Ð´Ð° кÑÑÑоÑа Ñ ÐºÐ¾Ð½ÑейнеÑа календаÑей 312calendarsContainer.addEventListener('mouseleave', clearPreview); 313 314// ÐниÑиализаÑÐ¸Ñ ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñей пÑи загÑÑзке 315generateCalendars();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.