aggiunta calendario vanillajs in pagina html

This commit is contained in:
Alessandro Seravalli 2025-05-09 09:03:24 +02:00
parent 3f5782dea0
commit 1d65d5a0cf

View File

@ -0,0 +1,483 @@
<!DOCTYPE html>
<html lang="it">
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<meta charset="UTF-8">
<title>Datepicker Multi-Livello</title>
<style>
body {
font-family: sans-serif;
display: flex;
justify-content: center;
margin-top: 40px;
}
.calendar {
border: 1px solid #ccc;
border-radius: 10px;
padding: 15px;
/* width: 320px; */
}
.calendar-header {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.calendar-header button {
background: none;
font-size: 20px;
border-color: #eaeaea;
border-radius: 3px;
font-size: 12px;
-webkit-appearance: none;
outline: none !important;
-webkit-transition: all 0.1s;
-o-transition: all 0.1s;
transition: all 0.1s;
padding: 5px 10px;
font-size: 11px;
line-height: 1.5;
border-radius: 0;
color: #333333;
background-color: #ffffff;
border-color: #eaeaea;
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
padding: 6px 20px;
font-size: 12px;
line-height: 1.52857143;
border-radius: 0;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#prevBtn,
#nextBtn,
#monthYear {
cursor: pointer;
}
#monthYear {
font-weight: bold;
flex-grow: 1;
text-align: center;
}
.calendar-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 5px;
text-align: center;
}
.calendar-grid-7 {
grid-template-columns: repeat(7, 1fr);
}
.calendar-grid-5 {
grid-template-columns: repeat(5, 1fr);
}
.calendar-grid div {
padding: 8px;
border-radius: 5px;
cursor: pointer;
}
.calendar-grid .day {
font-weight: bold;
background-color: #eee;
cursor: default;
}
.calendar-grid .selected {
background-color: #009fe3;
color: white;
}
.calendar-grid .other-month {
color: #ccc;
}
.calendar-grid .disabled {
color: #bbb;
background: #f5f5f5;
cursor: not-allowed;
}
.calendar-actions {
margin-top: 15px;
display: flex;
justify-content: space-around;
}
.calendar-actions button {
padding: 6px 12px;
background-color: orange;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
</head>
<body>
<style>
.datepicker-wrapper {
display: inline-block;
position: relative;
margin-bottom: 8px;
}
.datepicker-input {
width: 200px;
padding: 8px 36px 8px 8px;
border-radius: 5px;
border: 1px solid #ccc;
background: #fafafa;
cursor: pointer;
font-size: 16px;
}
.datepicker-icon {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
width: 20px;
height: 20px;
fill: #888;
cursor: pointer;
pointer-events: auto;
}
.calendar-popup {
position: absolute;
z-index: 100;
display: none;
min-width: 160px;
padding: 5px 0;
margin: 2px 0 0;
list-style: none;
font-size: 12px;
text-align: left;
background-color: #ffffff;
border: 1px solid #e1e1e1;
border-radius: 0;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
background-clip: padding-box;
}
</style>
<div class="datepicker-wrapper">
<input id="dateInput" class="datepicker-input" type="text" readonly placeholder="Seleziona una data" />
<svg id="calendarIcon" class="datepicker-icon" viewBox="0 0 24 24">
<path
d="M19 4h-1V2h-2v2H8V2H6v2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V9h14v11zm0-13H5V6h14v1z" />
</svg>
<div class="calendar calendar-popup" id="calendarPopup"></div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
// Utility per posizionare il popup sotto l'input
function positionCalendarPopup() {
const input = document.getElementById('dateInput');
const popup = document.getElementById('calendarPopup');
// Sposta il popup in fondo al body (portal)
if (popup.parentNode !== document.body) {
document.body.appendChild(popup);
}
popup.style.display = 'block';
popup.style.position = 'absolute';
popup.style.zIndex = '9999';
const rect = input.getBoundingClientRect();
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
popup.style.top = (rect.bottom + scrollTop) + 'px';
popup.style.left = (rect.left + scrollLeft) + 'px';
// popup.style.minWidth = rect.width + 'px';
}
// --- CONFIGURAZIONE FORMATO DATA ---
let dateFormat = 'dd/MM/yyyy'; // Cambia qui il formato come preferisci
// --- ELEMENTI ---
const calendarPopup = document.getElementById("calendarPopup");
const dateInput = document.getElementById("dateInput");
// Questi saranno definiti dopo il rendering del calendario:
let calendarEl, monthYearEl;
let currentDate = new Date();
let selectedDate = null;
let view = 'days'; // 'days' | 'months' | 'years'
// CONFIGURAZIONE: giorni della settimana da disabilitare (0=domenica, 6=sabato)
const disabledWeekdays = [0, 6]; // es: weekend
// CONFIGURAZIONE: range di date da disabilitare (array di oggetti {start, end})
const disabledDateRanges = [
{ start: new Date(2025, 4, 10), end: new Date(2025, 4, 15) }, // 10-15 maggio 2025
// aggiungi altri range se necessario
];
// --- FORMATTAZIONE DATA ---
function pad(n) {
return n < 10 ? '0' + n : n;
}
function formatDate(date, format) {
if (!date) return '';
const pad = n => n < 10 ? '0' + n : n;
return format
.replace('dd', pad(date.getDate()))
.replace('MM', pad(date.getMonth() + 1))
.replace('yyyy', date.getFullYear())
.replace('yy', String(date.getFullYear()).slice(-2));
}
// --- MOSTRA/NASCONDI CALENDARIO ---
function showCalendar() {
positionCalendarPopup();
renderCalendar();
setTimeout(() => {
document.addEventListener('mousedown', onClickOutside);
}, 0);
}
function hideCalendar() {
calendarPopup.style.display = 'none';
document.removeEventListener('mousedown', onClickOutside);
// Resetta la vista alla schermata principale
view = 'days';
if (selectedDate) {
currentDate = new Date(selectedDate);
} else {
currentDate = new Date();
}
}
function onClickOutside(e) {
if (!calendarPopup.contains(e.target) && e.target !== dateInput) {
hideCalendar();
}
}
// --- SOVRASCRIVI RENDERING ---
function renderCalendar() {
calendarPopup.innerHTML = `<div class='calendar-header'><button id='prevBtn' class="fa fa-chevron-left"></button><div id='monthYear'></div><button id='nextBtn' class="fa fa-chevron-right"></button></div><div class='calendar-grid' id='calendar'></div><div class='calendar-actions'><button id='todayBtn'>Oggi</button><button id='clearBtn'>Cancella</button><button id='confirmBtn'>Conferma</button></div>`;
calendarEl = document.getElementById("calendar");
monthYearEl = document.getElementById("monthYear");
if (view === 'days') renderDays();
else if (view === 'months') renderMonths();
else renderYears();
// Eventi header e azioni
document.getElementById('prevBtn').onclick = prev;
document.getElementById('nextBtn').onclick = next;
document.getElementById('todayBtn').onclick = goToday;
document.getElementById('clearBtn').onclick = clearSelection;
document.getElementById('confirmBtn').onclick = confirmDate;
monthYearEl.onclick = changeView;
}
// --- LOGICA ORIGINALE (INVARIATA) ---
function isDateDisabled(date) {
// Disabilita per giorno della settimana
if (disabledWeekdays.includes(date.getDay())) return true;
// Disabilita per range
for (const range of disabledDateRanges) {
if (date >= range.start && date <= range.end) return true;
}
return false;
}
function renderDays() {
calendarEl.classList.add('calendar-grid-7');
const months = ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno',
'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'];
const daysOfWeek = ['lun', 'mar', 'mer', 'gio', 'ven', 'sab', 'dom'];
monthYearEl.textContent = `${months[currentDate.getMonth()]} ${currentDate.getFullYear()}`;
// Intestazione dei giorni della settimana
for (let day of daysOfWeek) {
const div = document.createElement("div");
div.classList.add("day");
div.textContent = day;
calendarEl.appendChild(div);
}
const year = currentDate.getFullYear();
const month = currentDate.getMonth();
const firstDayOfMonth = new Date(year, month, 1);
const startDay = (firstDayOfMonth.getDay() + 6) % 7; // Luned<65>=0, Domenica=6
const daysInCurrentMonth = new Date(year, month + 1, 0).getDate();
const daysInPrevMonth = new Date(year, month, 0).getDate();
// Giorni del mese precedente
for (let i = startDay; i > 0; i--) {
const day = daysInPrevMonth - i + 1;
const div = document.createElement("div");
div.textContent = pad(day);
div.classList.add("other-month");
const prevMonthDate = new Date(year, month - 1, day);
if (isDateDisabled(prevMonthDate)) {
div.classList.add("disabled");
} else {
div.onclick = () => {
currentDate.setMonth(month - 1);
selectedDate = prevMonthDate;
dateInput.value = formatDate(selectedDate, dateFormat); // aggiorna subito input
renderCalendar();
};
}
calendarEl.appendChild(div);
}
// Giorni del mese corrente
for (let i = 1; i <= daysInCurrentMonth; i++) {
const div = document.createElement("div");
div.textContent = pad(i);
const thisDate = new Date(year, month, i);
if (selectedDate && sameDate(selectedDate, thisDate)) div.classList.add("selected");
if (isDateDisabled(thisDate)) {
div.classList.add("disabled");
} else {
div.onclick = () => {
selectedDate = thisDate;
dateInput.value = formatDate(selectedDate, dateFormat); // aggiorna subito input
renderCalendar();
};
}
calendarEl.appendChild(div);
}
// Giorni del mese successivo
const totalCells = 42; // 7 giorni x 6 settimane
const filledCells = startDay + daysInCurrentMonth;
const nextMonthDays = totalCells - filledCells;
for (let i = 1; i <= nextMonthDays; i++) {
const div = document.createElement("div");
div.textContent = pad(i);
div.classList.add("other-month");
const nextMonthDate = new Date(year, month + 1, i);
if (isDateDisabled(nextMonthDate)) {
div.classList.add("disabled");
} else {
div.onclick = () => {
currentDate.setMonth(month + 1);
selectedDate = nextMonthDate;
dateInput.value = formatDate(selectedDate, dateFormat); // aggiorna subito input
renderCalendar();
};
}
calendarEl.appendChild(div);
}
}
function renderMonths() {
const months = ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'];
monthYearEl.textContent = currentDate.getFullYear();
months.forEach((m, idx) => {
const div = document.createElement("div");
div.textContent = m;
div.onclick = () => {
currentDate.setMonth(idx);
view = 'days';
renderCalendar();
};
calendarEl.appendChild(div);
});
}
function renderYears() {
calendarEl.classList.remove('calendar-grid-7');
calendarEl.classList.add('calendar-grid-5');
// 20 anni, 5x4
const base = Math.floor(currentDate.getFullYear() / 20) * 20;
monthYearEl.textContent = `${base} - ${base + 19}`;
for (let y = base; y < base + 20; y++) {
const div = document.createElement("div");
div.textContent = y;
if (y === currentDate.getFullYear()) div.classList.add("selected");
div.onclick = () => {
currentDate.setFullYear(y);
view = 'months';
renderCalendar();
};
calendarEl.appendChild(div);
}
}
function changeView() {
if (view === 'days') view = 'months';
else if (view === 'months') view = 'years';
renderCalendar();
}
function prev() {
if (view === 'days') currentDate.setMonth(currentDate.getMonth() - 1);
else if (view === 'months') currentDate.setFullYear(currentDate.getFullYear() - 1);
else currentDate.setFullYear(currentDate.getFullYear() - 10);
renderCalendar();
}
function next() {
if (view === 'days') currentDate.setMonth(currentDate.getMonth() + 1);
else if (view === 'months') currentDate.setFullYear(currentDate.getFullYear() + 1);
else currentDate.setFullYear(currentDate.getFullYear() + 10);
renderCalendar();
}
function goToday() {
currentDate = new Date();
selectedDate = new Date();
dateInput.value = formatDate(selectedDate, dateFormat);
view = 'days';
renderCalendar();
}
function clearSelection() {
selectedDate = null;
dateInput.value = '';
renderCalendar();
}
function confirmDate() {
hideCalendar();
}
function sameDate(d1, d2) {
return d1.getFullYear() === d2.getFullYear() &&
d1.getMonth() === d2.getMonth() &&
d1.getDate() === d2.getDate();
}
// Inizializza input (opzionale: mostra la data di oggi)
dateInput.value = selectedDate ? formatDate(selectedDate, dateFormat) : '';
// Eventi su input e icona
document.getElementById('dateInput').addEventListener('click', showCalendar);
document.getElementById('calendarIcon').addEventListener('click', showCalendar);
// Espone showCalendar globalmente solo se serve (compatibilità)
window.showCalendar = showCalendar;
});
</script>
</body>
</html>