if (typeof isWasmEnv2 === 'undefined') { var isWasmEnv2 = typeof isGoerpWasm !== 'undefined' && isGoerpWasm; } if (!isWasmEnv2) { document.addEventListener("DOMContentLoaded", function () { const todayTranslation = document.getElementById('datepicker--today-translation')?.value || 'Today'; const accountFormat = document.getElementById('datepicker--date-format')?.value || '02.01.2006'; /* ------------- Calendar Modal ---------------------------*/ document.querySelectorAll('.calendar-container').forEach((el) => { const calendarEl = el.querySelector('.customTimeframe-modal'); if (!calendarEl) return; // if modal is missing const isSingleMode = calendarEl.classList.contains('datepicker--single'); const calendarOpenButton = el.querySelector('.open-customTimeframe-modal'); const calendarCloseButton = el.querySelector('.customTimeframe-close'); const customDateTimePrev = calendarEl.querySelector('.customDatepicker-previous'); const customDateTimeNext = calendarEl.querySelector('.customDatepicker-next'); const customMonthSelector = calendarEl.querySelector('.customMonth-selector'); const customYearSelector = calendarEl.querySelector('.customYear-selector'); const displayEl = calendarEl.querySelector('.customSelected-range-display'); let selectedYear = parseInt(customYearSelector.value, 10); let selectedMonth = parseInt(customMonthSelector.value, 10); let isStartDateSelected = false; // Closing button calendarCloseButton?.addEventListener('click', () => { calendarEl.classList.add('hidden'); }) // Open modal calendarOpenButton?.addEventListener('click', () => { calendarEl.classList.remove('hidden'); }) // Close if clicked outside of modal document.addEventListener('click', function (event) { if (calendarEl && !calendarEl.contains(event.target) && event.target !== calendarOpenButton && !event.target.matches('.customDatepicker-table-date')) { calendarEl.classList.add('hidden'); } }); // Generate calendar on load generateCalendar(selectedYear, selectedMonth, calendarEl, customMonthSelector, customYearSelector); updateDisplay(displayEl, calendarEl.querySelector('.customStart-input').value, calendarEl.querySelector('.customEnd-input').value); // Previous month button customDateTimePrev?.addEventListener('click', () => { selectedMonth--; if (selectedMonth < 0) { selectedMonth = 11; selectedYear--; } generateCalendar(selectedYear, selectedMonth, calendarEl, customMonthSelector, customYearSelector); updateNavButtons(customDateTimePrev, customDateTimeNext, selectedYear, selectedMonth, customYearSelector, customMonthSelector); }); // Next month button customDateTimeNext?.addEventListener('click', () => { selectedMonth++; if (selectedMonth > 11) { selectedMonth = 0; selectedYear++; } generateCalendar(selectedYear, selectedMonth, calendarEl, customMonthSelector, customYearSelector); updateNavButtons(customDateTimePrev, customDateTimeNext, selectedYear, selectedMonth, customYearSelector, customMonthSelector); }); // Handle manual change in select inputs customMonthSelector?.addEventListener('change', () => { selectedMonth = parseInt(customMonthSelector.value, 10); generateCalendar(selectedYear, selectedMonth, calendarEl, customMonthSelector, customYearSelector); updateNavButtons(customDateTimePrev, customDateTimeNext, selectedYear, selectedMonth, customYearSelector, customMonthSelector); }); customYearSelector?.addEventListener('change', () => { selectedYear = parseInt(customYearSelector.value, 10); generateCalendar(selectedYear, selectedMonth, calendarEl, customMonthSelector, customYearSelector); updateNavButtons(customDateTimePrev, customDateTimeNext, selectedYear, selectedMonth, customYearSelector, customMonthSelector); }); // On clicking on calendar date calendarEl.querySelector('.customCalendar')?.addEventListener('click', (e) => { if (e.target.classList.contains('customDatepicker-table-date')) { let selectedDate = e.target.getAttribute('data-date'); if (isSingleMode) { // SINGLE DATE MODE: Only one date is selectable at a time calendarEl.querySelector('.customStart-input').value = selectedDate; if (calendarEl.querySelector('.customEnd-input')) { calendarEl.querySelector('.customEnd-input').value = ""; // Clear end input } isStartDateSelected = true; // Force UI update by removing and adding the selected class calendarEl.querySelectorAll('.customDatepicker-table-date').forEach(dateCell => { dateCell.classList.remove('customDate-selected'); }); e.target.classList.add('customDate-selected'); // Add selected class to the clicked date // Ensure the displayed date updates immediately updateDisplay(displayEl, selectedDate, null); } else { let selectedDate = e.target.getAttribute('data-date'); let startDate = calendarEl.querySelector('.customStart-input'); let endDate = calendarEl.querySelector('.customEnd-input'); let selectedDateObj = new Date(selectedDate); let startDateObj = new Date(startDate.value); let endDateObj = new Date(endDate.value); // If none is selected if (!isStartDateSelected) { startDate.value = selectedDate; endDate.value = selectedDate; isStartDateSelected = true; } // If range is selected and end date is LESS than selected date - extend range else if (startDate.value && endDate.value && selectedDateObj > endDateObj) { endDate.value = selectedDate; } // If range is selected and start date is BIGGER than selected date - extend range // Or // If range is selected and end date is selected again - set start date as end date else if ( startDate.value && endDate.value && selectedDateObj < startDateObj || startDate.value && endDate.value && selectedDate == endDate.value ) { startDate.value = selectedDate; } // If selected date inside the selected date range else { endDate.value = selectedDate; } generateCalendar(selectedYear, selectedMonth, calendarEl, customMonthSelector, customYearSelector); updateDisplay(displayEl, startDate.value, endDate.value); calendarEl.querySelector(`[tabindex="${e.target.getAttribute('tabindex')}"]`)?.focus(); } } }); function formatDateByAccountFormat(dateObj) { const dd = String(dateObj.getDate()).padStart(2, "0"); const mm = String(dateObj.getMonth() + 1).padStart(2, "0"); const yyyy = dateObj.getFullYear(); const tokenMap = { "02": dd, "01": mm, "2006": yyyy }; // Replace tokens in ONE pass, longest first return accountFormat.replace(/2006|02|01/g, token => tokenMap[token]); } function getDateFormatByAccountFormat() { const tokenMap = { "02": "dd", "01": "mm", "2006": "yyyy" }; // Replace tokens in ONE pass, longest first return accountFormat.replace(/2006|02|01/g, token => tokenMap[token]); } function updateDisplay(displayEl, startDate, endDate) { if (!startDate && !endDate) { displayEl.innerText = getDateFormatByAccountFormat(); calendarOpenButton.innerText = getDateFormatByAccountFormat(); return; } const startDateObj = new Date(startDate); const endDateObj = new Date(endDate); // Invalid date check if (isNaN(startDateObj.getTime()) && !endDate) { displayEl.innerText = startDate; calendarOpenButton.innerText = startDate; return; } const startFormatted = formatDateByAccountFormat(startDateObj); let date = startFormatted; if ( endDate && startDateObj.toDateString() !== endDateObj.toDateString() ) { const endFormatted = formatDateByAccountFormat(endDateObj); date += " - " + endFormatted; } displayEl.innerText = date; calendarOpenButton.innerText = date; } const today = new Date(); const yesterday = new Date(today); yesterday.setDate(today.getDate() - 1); // This week const weekStart = new Date(today); weekStart.setDate(today.getDate() - today.getDay() + 1); // Monday const weekEnd = new Date(weekStart); weekEnd.setDate(weekStart.getDate() + 6); // Sunday // This month const monthStart = new Date(today.getFullYear(), today.getMonth(), 1); const monthEnd = new Date(today.getFullYear(), today.getMonth() + 1, 0); // Previous week const prevWeekEnd = new Date(weekStart); prevWeekEnd.setDate(weekStart.getDate() - 1); // Last Sunday const prevWeekStart = new Date(prevWeekEnd); prevWeekStart.setDate(prevWeekEnd.getDate() - 6); // Monday // Previous month const prevMonthEnd = new Date(today.getFullYear(), today.getMonth(), 0); const prevMonthStart = new Date(today.getFullYear(), today.getMonth() - 1, 1); // Reset const resetButton = calendarEl.querySelector('.customDatepicker-reset'); if (resetButton) { resetButton.addEventListener('click', () => { clearDateRange(); }); resetButton.addEventListener('keydown', (event) => { if (event.key === 'Enter' || event.key === ' ') { clearDateRange(); } }); } // Add functionality to datepicker buttons const dateButtons = [ { selector: '.customDatepick-today', dateRange: [formatDate(today), formatDate(today)] }, { selector: '.customDatepick-yesterday', dateRange: [formatDate(yesterday), formatDate(yesterday)] }, { selector: '.customDatepick-week', dateRange: [formatDate(weekStart), formatDate(weekEnd)] }, { selector: '.customDatepick-month', dateRange: [formatDate(monthStart), formatDate(monthEnd)] }, { selector: '.customDatepick-prevweek', dateRange: [formatDate(prevWeekStart), formatDate(prevWeekEnd)] }, { selector: '.customDatepick-prevmonth', dateRange: [formatDate(prevMonthStart), formatDate(prevMonthEnd)] } ]; // Add the clearDateRange function function clearDateRange() { calendarEl.querySelector('.customStart-input').value = ''; calendarEl.querySelector('.customEnd-input').value = ''; // Update display to show placeholder or empty state if (displayEl) { displayEl.innerText = getDateFormatByAccountFormat(); } if (calendarOpenButton) { calendarOpenButton.innerText = getDateFormatByAccountFormat(); } // Regenerate to remove selected styling and reset to allow new selection generateCalendar(selectedYear, selectedMonth, calendarEl, customMonthSelector, customYearSelector); isStartDateSelected = false; } dateButtons.forEach(({ selector, dateRange }) => { const element = calendarEl.querySelector(selector); if (element) { element.addEventListener('click', () => { setDateRange(dateRange[0], dateRange[1]); }); element.addEventListener('keydown', (event) => { if (event.key === 'Enter' || event.key === ' ') { setDateRange(dateRange[0], dateRange[1]); } }); } }); function setDateRange(startDate, endDate) { const startDateObj = new Date(startDate); calendarEl.querySelector('.customStart-input').value = startDate; calendarEl.querySelector('.customEnd-input').value = endDate; const selectedYear = startDateObj.getFullYear(); const selectedMonth = startDateObj.getMonth(); generateCalendar(selectedYear, selectedMonth, calendarEl, customMonthSelector, customYearSelector); isStartDateSelected = true; updateDisplay( displayEl, calendarEl.querySelector('.customStart-input').value, calendarEl.querySelector('.customEnd-input').value ); } }); // Generate calendar function generateCalendar(year, month, calendarEl, customMonthSelector, customYearSelector, isSingleMode) { const calendarContent = calendarEl.querySelector('.customCalendar'); calendarContent.innerHTML = ""; // Clear previous content const today = new Date(); // Adjust first day to match Monday start (shift Sunday index 0 to 6) let firstDay = new Date(year, month, 1).getDay(); firstDay = (firstDay === 0) ? 6 : firstDay - 1; const lastDate = new Date(year, month + 1, 0).getDate(); const prevLastDate = new Date(year, month, 0).getDate(); let html = ''; let dayCounter = 1; const startDateValue = calendarEl.querySelector('.customStart-input').value; const endDateValue = calendarEl.querySelector('.customEnd-input').value; let startDateObj = startDateValue ? new Date(startDateValue) : null; let endDateObj = endDateValue ? new Date(endDateValue) : null; function getCellClass(dateObj) { if ((!endDateObj && startDateObj && dateObj.toDateString() === startDateObj.toDateString()) || (endDateObj && dateObj.toDateString() === endDateObj.toDateString() && startDateObj && dateObj.toDateString() === startDateObj.toDateString())) { return "customDate-selected"; } else if (startDateObj && dateObj.toDateString() === startDateObj.toDateString()) { return "customDate-selected-start"; } else if (endDateObj && dateObj.toDateString() === endDateObj.toDateString()) { return "customDate-selected-end"; } else if (startDateObj && endDateObj && dateObj > startDateObj && dateObj < endDateObj) { return "customDate-selected-between"; } return ""; } let tabIndex = 12; // Fill previous month's overflow days for (let i = firstDay; i > 0; i--) { let prevMonth = month === 0 ? 11 : month - 1; let prevYear = month === 0 ? year - 1 : year; let prevDay = prevLastDate - i + 1; // Format month to always have two digits let formattedMonth = String(prevMonth + 1).padStart(2, '0'); let formattedDay = String(prevDay).padStart(2, '0'); let prevDateObj = new Date(prevYear, prevMonth, prevDay); let cellClass = getCellClass(prevDateObj); let isToday = prevDateObj.toDateString() === today.toDateString() ? "today" : ""; html += `
${prevDay}
`; tabIndex++; } // Fill current month's days for (let i = 1; i <= lastDate; i++, dayCounter++) { const currentDateObj = new Date(year, month, i); let cellClass = getCellClass(currentDateObj); let isToday = currentDateObj.toDateString() === today.toDateString() ? "today" : ""; let formattedMonth = String(month + 1).padStart(2, '0'); let formattedDay = String(i).padStart(2, '0'); html += `
${isToday ? todayTranslation : i}
`; if ((dayCounter + firstDay) % 7 === 0) { html += ''; } tabIndex++; } // Fill next month's overflow days let nextMonthDays = 1; while ((dayCounter + firstDay - 1) % 7 !== 0) { let nextMonth = month + 1 > 11 ? 0 : month + 1; let nextYear = month + 1 > 11 ? year + 1 : year; let nextDateObj = new Date(nextYear, nextMonth, nextMonthDays); let cellClass = getCellClass(nextDateObj); let isToday = nextDateObj.toDateString() === today.toDateString() ? "today" : ""; let formattedMonth = String(nextMonth + 1).padStart(2, '0'); let formattedDay = String(nextMonthDays).padStart(2, '0'); html += `
${nextMonthDays++}
`; dayCounter++; tabIndex++; } // Ensure proper closing of the last row if (dayCounter % 7 !== 0) { html += ''; } calendarContent.innerHTML = html; // Attach event listener calendarEl.querySelector('.customCalendar')?.addEventListener('click', (e) => { if (e.target.classList.contains('customDatepicker-table-date')) { let selectedDate = e.target.getAttribute('data-date'); if (isSingleMode) { // Now available in the scope const startInput = calendarEl.querySelector('.customStart-input'); const displayField = calendarEl.querySelector('.customStart-display'); if (startInput) startInput.value = selectedDate; if (displayField) displayField.value = selectedDate; } } }); // Update the selected month and year in the dropdowns customMonthSelector.value = month; customYearSelector.value = year; initCalendarKeyboardNavigation(calendarEl); calendarEl.querySelector('.customDatepicker-reset')?.setAttribute('tabindex', tabIndex) } function initCalendarKeyboardNavigation(calendarEl) { const dateCells = calendarEl.querySelectorAll('.customDatepicker-table-date'); if (dateCells.length === 0) return; let cellsArray = Array.from(dateCells); // Function to find the currently focused element function getFocusedIndex() { return cellsArray.findIndex(cell => cell === document.activeElement); } // Function to handle the keydown event for navigation calendarEl.querySelector('.customDatepicker-month-table')?.addEventListener('keydown', (event) => { let currentIndex = getFocusedIndex(); let nextIndex; switch (event.key) { case 'ArrowRight': nextIndex = currentIndex + 1; break; case 'ArrowLeft': nextIndex = currentIndex - 1; break; case 'ArrowDown': nextIndex = currentIndex + 7; // Move down a week break; case 'ArrowUp': nextIndex = currentIndex - 7; // Move up a week break; case 'Enter': case ' ': cellsArray[currentIndex]?.click(); return; default: return; // Exit on other keys } // Ensure the new index is within bounds if (nextIndex >= 0 && nextIndex < cellsArray.length) { cellsArray[nextIndex].focus(); event.preventDefault(); } }); } //Close with esc key document.addEventListener("keydown", function (event) { if (event.key === "Escape") { document.querySelectorAll('.customTimeframe-modal').forEach((modal) => { if (!modal.classList.contains('hidden')) { modal.classList.add('hidden'); } }); } }); function formatDate(date) { const day = String(date.getDate()).padStart(2, '0'); const month = String(date.getMonth() + 1).padStart(2, '0'); const year = date.getFullYear(); return `${year}-${month}-${day}`; } function updateNavButtons(customDateTimePrev, customDateTimeNext, selectedYear, selectedMonth, customYearSelector, customMonthSelector) { let nextMonth = selectedMonth + 1; let nextYear = selectedYear; if (nextMonth > 11) { nextMonth = 0; nextYear++; } let prevMonth = selectedMonth - 1; let prevYear = selectedYear; if (prevMonth < 0) { prevMonth = 11; prevYear--; } // Disable or enable next button based on available options if (isMonthYearAvailable(nextYear, nextMonth, customYearSelector, customMonthSelector)) { customDateTimeNext.disabled = false; } else { customDateTimeNext.disabled = true; } // Disable or enable previous button based on available options if (isMonthYearAvailable(prevYear, prevMonth, customYearSelector, customMonthSelector)) { customDateTimePrev.disabled = false; } else { customDateTimePrev.disabled = true; } } // Function to check if the given year and month exist in the dropdowns function isMonthYearAvailable(year, month, customYearSelector, customMonthSelector) { const yearOptions = Array.from(customYearSelector.options).map(opt => parseInt(opt.value, 10)); const monthOptions = Array.from(customMonthSelector.options).map(opt => parseInt(opt.value, 10)); return yearOptions.includes(year) && monthOptions.includes(month); } }); const fileInput = document.querySelector(".fileInput"); if (fileInput) { fileInput.addEventListener("change", function (event) { let fileName = event.target.files[0]?.name; if (fileName) { document.querySelector(".upload-field__text").innerHTML = `Uploaded: ${fileName}`; document.querySelector(".uploadButton").disabled = false; // Enable button } }); } }