Compare commits
4 Commits
master
...
feature/ca
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f71fa13e19 | ||
ad1bbbe327 | |||
ea27f0b91c | |||
1d65d5a0cf |
87
src/index.ts
87
src/index.ts
@ -1,48 +1,47 @@
|
|||||||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
import { XdceArchModule } from '@isp/xdce-arch-core';
|
import { XdceArchModule } from '@isp/xdce-arch-core';
|
||||||
import { NbpModule } from '@isp/xdce-widget';
|
import { NbpModule } from '@isp/xdce-widget';
|
||||||
|
|
||||||
import { NbpBreadCrumbsComponent } from './widgetfideuram/components/nbp-bread-crumbs/nbp-bread-crumbs.component';
|
|
||||||
export { NbpBreadCrumbsComponent } from './widgetfideuram/components/nbp-bread-crumbs/nbp-bread-crumbs.component';
|
|
||||||
import { NbpFidBarChartComponent } from './widgetfideuram/components/nbp-fid-bar-chart/nbp-fid-bar-chart.component';
|
|
||||||
export { NbpFidBarChartComponent } from './widgetfideuram/components/nbp-fid-bar-chart/nbp-fid-bar-chart.component';
|
|
||||||
import { NbpFidButtonBarComponent } from './widgetfideuram/components/nbp-fid-button-bar/nbp-fid-button-bar.component';
|
|
||||||
export { NbpFidButtonBarComponent } from './widgetfideuram/components/nbp-fid-button-bar/nbp-fid-button-bar.component';
|
|
||||||
import { NbpFidDonutChartComponent } from './widgetfideuram/components/nbp-fid-donut-chart/nbp-fid-donut-chart.component';
|
|
||||||
export { NbpFidDonutChartComponent } from './widgetfideuram/components/nbp-fid-donut-chart/nbp-fid-donut-chart.component';
|
|
||||||
import { NbpFidPyramidChartComponent } from './widgetfideuram/components/nbp-fid-pyramid-chart/nbp-fid-pyramid-chart.component';
|
|
||||||
export { NbpFidPyramidChartComponent } from './widgetfideuram/components/nbp-fid-pyramid-chart/nbp-fid-pyramid-chart.component';
|
|
||||||
import { NbpFidSidePopupComponent } from './widgetfideuram/components/nbp-fid-side-popup/nbp-fid-side-popup.component';
|
|
||||||
export { NbpFidSidePopupComponent } from './widgetfideuram/components/nbp-fid-side-popup/nbp-fid-side-popup.component';
|
|
||||||
import { NbpFidTableComponent } from './widgetfideuram/components/nbp-fid-table/nbp-fid-table.component';
|
|
||||||
export { NbpFidTableComponent } from './widgetfideuram/components/nbp-fid-table/nbp-fid-table.component';
|
|
||||||
import { NbpFidToggleTabComponentA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component.a11y';
|
|
||||||
export { NbpFidToggleTabComponentA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component.a11y';
|
|
||||||
import { NbpFidToggleTabComponentNOA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component.noa11y';
|
|
||||||
export { NbpFidToggleTabComponentNOA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component.noa11y';
|
|
||||||
import { NbpFidToggleTabComponent } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component';
|
|
||||||
export { NbpFidToggleTabComponent } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component';
|
|
||||||
import { NbpFidToggleTabsetComponentA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component.a11y';
|
|
||||||
export { NbpFidToggleTabsetComponentA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component.a11y';
|
|
||||||
import { NbpFidToggleTabsetComponentNOA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component.noa11y';
|
|
||||||
export { NbpFidToggleTabsetComponentNOA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component.noa11y';
|
|
||||||
import { NbpFidToggleTabsetComponent } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component';
|
|
||||||
export { NbpFidToggleTabsetComponent } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component';
|
|
||||||
import { NbpFidComboComponent } from './widgetfideuram/components/nbp-fid-combo/nbp-fid-combo.component';
|
|
||||||
export { NbpFidComboComponent } from './widgetfideuram/components/nbp-fid-combo/nbp-fid-combo.component';
|
|
||||||
|
|
||||||
import { ShowcaseComponent } from './widgetfideuram/components/showcase/showcase.component';
|
|
||||||
export { ShowcaseComponent } from './widgetfideuram/components/showcase/showcase.component';
|
|
||||||
import { Showcase1Component } from './widgetfideuram/components/showcase/showcase1.component';
|
|
||||||
export { Showcase1Component } from './widgetfideuram/components/showcase/showcase1.component';
|
|
||||||
import { WidgetFideuramShowcaseComponent } from './widgetfideuram/components/widget-fideuram-showcase/widget-fideuram-showcase.component';
|
|
||||||
export { WidgetFideuramShowcaseComponent } from './widgetfideuram/components/widget-fideuram-showcase/widget-fideuram-showcase.component';
|
|
||||||
|
|
||||||
import { AgGridModule, AngularFrameworkComponentWrapper, AngularFrameworkOverrides } from 'ag-grid-angular';
|
import { AgGridModule, AngularFrameworkComponentWrapper, AngularFrameworkOverrides } from 'ag-grid-angular';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { NbpBreadCrumbsComponent } from './widgetfideuram/components/nbp-bread-crumbs/nbp-bread-crumbs.component';
|
||||||
|
import { NbpFidBarChartComponent } from './widgetfideuram/components/nbp-fid-bar-chart/nbp-fid-bar-chart.component';
|
||||||
|
import { NbpFidButtonBarComponent } from './widgetfideuram/components/nbp-fid-button-bar/nbp-fid-button-bar.component';
|
||||||
|
import { NbpFidCalendarGenericComponent } from './widgetfideuram/components/nbp-fid-calendar-generic/nbp-fid-calendar-genric.component';
|
||||||
|
import { NbpFidComboComponent } from './widgetfideuram/components/nbp-fid-combo/nbp-fid-combo.component';
|
||||||
|
import { NbpFidDonutChartComponent } from './widgetfideuram/components/nbp-fid-donut-chart/nbp-fid-donut-chart.component';
|
||||||
|
import { NbpFidPyramidChartComponent } from './widgetfideuram/components/nbp-fid-pyramid-chart/nbp-fid-pyramid-chart.component';
|
||||||
|
import { NbpFidSidePopupComponent } from './widgetfideuram/components/nbp-fid-side-popup/nbp-fid-side-popup.component';
|
||||||
|
import { NbpFidTableComponent } from './widgetfideuram/components/nbp-fid-table/nbp-fid-table.component';
|
||||||
|
import { NbpFidToggleTabComponent } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component';
|
||||||
|
import { NbpFidToggleTabComponentA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component.a11y';
|
||||||
|
import { NbpFidToggleTabComponentNOA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component.noa11y';
|
||||||
|
import { NbpFidToggleTabsetComponent } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component';
|
||||||
|
import { NbpFidToggleTabsetComponentA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component.a11y';
|
||||||
|
import { NbpFidToggleTabsetComponentNOA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component.noa11y';
|
||||||
|
import { ShowcaseComponent } from './widgetfideuram/components/showcase/showcase.component';
|
||||||
|
import { Showcase1Component } from './widgetfideuram/components/showcase/showcase1.component';
|
||||||
|
import { WidgetFideuramShowcaseComponent } from './widgetfideuram/components/widget-fideuram-showcase/widget-fideuram-showcase.component';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
export { AgGridModule } from 'ag-grid-angular';
|
export { AgGridModule } from 'ag-grid-angular';
|
||||||
|
export { NbpBreadCrumbsComponent } from './widgetfideuram/components/nbp-bread-crumbs/nbp-bread-crumbs.component';
|
||||||
export { DATE_STRING_FORMAT, formatDate, formatNumber, setSpinnerMessage, clearSpinnerMessage } from './widgetfideuram/Utils';
|
export { NbpFidBarChartComponent } from './widgetfideuram/components/nbp-fid-bar-chart/nbp-fid-bar-chart.component';
|
||||||
|
export { NbpFidButtonBarComponent } from './widgetfideuram/components/nbp-fid-button-bar/nbp-fid-button-bar.component';
|
||||||
|
export { NbpFidCalendarGenericComponent } from './widgetfideuram/components/nbp-fid-calendar-generic/nbp-fid-calendar-genric.component';
|
||||||
|
export { NbpFidComboComponent } from './widgetfideuram/components/nbp-fid-combo/nbp-fid-combo.component';
|
||||||
|
export { NbpFidDonutChartComponent } from './widgetfideuram/components/nbp-fid-donut-chart/nbp-fid-donut-chart.component';
|
||||||
|
export { NbpFidPyramidChartComponent } from './widgetfideuram/components/nbp-fid-pyramid-chart/nbp-fid-pyramid-chart.component';
|
||||||
|
export { NbpFidSidePopupComponent } from './widgetfideuram/components/nbp-fid-side-popup/nbp-fid-side-popup.component';
|
||||||
|
export { NbpFidTableComponent } from './widgetfideuram/components/nbp-fid-table/nbp-fid-table.component';
|
||||||
|
export { NbpFidToggleTabComponent } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component';
|
||||||
|
export { NbpFidToggleTabComponentA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component.a11y';
|
||||||
|
export { NbpFidToggleTabComponentNOA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component.noa11y';
|
||||||
|
export { NbpFidToggleTabsetComponent } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component';
|
||||||
|
export { NbpFidToggleTabsetComponentA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component.a11y';
|
||||||
|
export { NbpFidToggleTabsetComponentNOA11Y } from './widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component.noa11y';
|
||||||
|
export { ShowcaseComponent } from './widgetfideuram/components/showcase/showcase.component';
|
||||||
|
export { Showcase1Component } from './widgetfideuram/components/showcase/showcase1.component';
|
||||||
|
export { WidgetFideuramShowcaseComponent } from './widgetfideuram/components/widget-fideuram-showcase/widget-fideuram-showcase.component';
|
||||||
|
export { clearSpinnerMessage, DATE_STRING_FORMAT, formatDate, formatNumber, setSpinnerMessage } from './widgetfideuram/Utils';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -51,6 +50,7 @@ export { DATE_STRING_FORMAT, formatDate, formatNumber, setSpinnerMessage, clearS
|
|||||||
NbpModule,
|
NbpModule,
|
||||||
AgGridModule,
|
AgGridModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
|
CommonModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
NbpBreadCrumbsComponent,
|
NbpBreadCrumbsComponent,
|
||||||
@ -70,6 +70,7 @@ export { DATE_STRING_FORMAT, formatDate, formatNumber, setSpinnerMessage, clearS
|
|||||||
ShowcaseComponent,
|
ShowcaseComponent,
|
||||||
Showcase1Component,
|
Showcase1Component,
|
||||||
WidgetFideuramShowcaseComponent,
|
WidgetFideuramShowcaseComponent,
|
||||||
|
NbpFidCalendarGenericComponent
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
NbpBreadCrumbsComponent,
|
NbpBreadCrumbsComponent,
|
||||||
@ -89,7 +90,8 @@ export { DATE_STRING_FORMAT, formatDate, formatNumber, setSpinnerMessage, clearS
|
|||||||
ShowcaseComponent,
|
ShowcaseComponent,
|
||||||
Showcase1Component,
|
Showcase1Component,
|
||||||
WidgetFideuramShowcaseComponent,
|
WidgetFideuramShowcaseComponent,
|
||||||
AgGridModule
|
AgGridModule,
|
||||||
|
NbpFidCalendarGenericComponent
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
AngularFrameworkOverrides,
|
AngularFrameworkOverrides,
|
||||||
@ -101,7 +103,8 @@ export { DATE_STRING_FORMAT, formatDate, formatNumber, setSpinnerMessage, clearS
|
|||||||
NbpFidToggleTabsetComponentA11Y,
|
NbpFidToggleTabsetComponentA11Y,
|
||||||
NbpFidToggleTabsetComponentNOA11Y,
|
NbpFidToggleTabsetComponentNOA11Y,
|
||||||
NbpFidToggleTabComponent,
|
NbpFidToggleTabComponent,
|
||||||
NbpFidToggleTabsetComponent
|
NbpFidToggleTabsetComponent,
|
||||||
|
NbpFidCalendarGenericComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class XdceWidgetFideuramModule {
|
export class XdceWidgetFideuramModule {
|
||||||
|
@ -0,0 +1,473 @@
|
|||||||
|
<!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;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-cell {
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
border: 1px solid #dde6e9;
|
||||||
|
border-radius: 3px;
|
||||||
|
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 .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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<div class="datepicker-wrapper">
|
||||||
|
<input id="dateInput" class="datepicker-input" type="text" 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="calendar-cell fa fa-chevron-left"></button><div id='monthYear' class="calendar-cell"></div><button id='nextBtn' class="calendar-cell 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.classList.add("calendar-cell");
|
||||||
|
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");
|
||||||
|
div.classList.add("calendar-cell");
|
||||||
|
|
||||||
|
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);
|
||||||
|
div.classList.add("calendar-cell");
|
||||||
|
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");
|
||||||
|
div.classList.add("calendar-cell");
|
||||||
|
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.classList.add("calendar-cell");
|
||||||
|
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;
|
||||||
|
div.classList.add("calendar-cell");
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Permetti inserimento manuale della data
|
||||||
|
document.getElementById('dateInput').addEventListener('input', function (e) {
|
||||||
|
const value = e.target.value;
|
||||||
|
// Regex base per dd/MM/yyyy
|
||||||
|
const datePattern = /^(\d{2})\/(\d{2})\/(\d{4})$/;
|
||||||
|
if (datePattern.test(value)) {
|
||||||
|
const [, dd, mm, yyyy] = value.match(datePattern);
|
||||||
|
const date = new Date(parseInt(yyyy), parseInt(mm) - 1, parseInt(dd));
|
||||||
|
// Controlla che sia una data valida
|
||||||
|
if (date && date.getDate() === parseInt(dd) && (date.getMonth() + 1) === parseInt(mm) && date.getFullYear() === parseInt(yyyy)) {
|
||||||
|
if (!isDateDisabled(date)) {
|
||||||
|
selectedDate = date;
|
||||||
|
currentDate = new Date(date);
|
||||||
|
dateInput.value = formatDate(selectedDate, dateFormat);
|
||||||
|
dateInput.classList.remove('input-error');
|
||||||
|
renderCalendar();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Se non valido, evidenzia errore
|
||||||
|
dateInput.classList.add('input-error');
|
||||||
|
});
|
||||||
|
document.getElementById('calendarIcon').addEventListener('click', showCalendar);
|
||||||
|
// Espone showCalendar globalmente solo se serve (compatibilità)
|
||||||
|
window.showCalendar = showCalendar;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -0,0 +1,120 @@
|
|||||||
|
<div class="datepicker-wrapper">
|
||||||
|
<input
|
||||||
|
#dateInput
|
||||||
|
[id]="id"
|
||||||
|
[name]="name"
|
||||||
|
[value]="selectedDateStr"
|
||||||
|
(input)="setDate($event.target.value)"
|
||||||
|
class="datepicker-input"
|
||||||
|
type="text"
|
||||||
|
readonly
|
||||||
|
placeholder="Seleziona una data"
|
||||||
|
/>
|
||||||
|
<svg
|
||||||
|
id="calendarIcon"
|
||||||
|
class="datepicker-icon"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
(click)="showCalendar()"
|
||||||
|
>
|
||||||
|
<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 #calendarPopup class="calendar calendar-popup" id="calendarPopup">
|
||||||
|
<div class="calendar-header">
|
||||||
|
<button id="prevBtn" class="fa fa-chevron-left" (click)="prev()"></button>
|
||||||
|
<div id="monthYear" (click)="changeView()">{{ monthYearText }}</div>
|
||||||
|
<button id="nextBtn" class="fa fa-chevron-right" (click)="next()"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-container [ngSwitch]="view">
|
||||||
|
<ng-container *ngSwitchCase="'days'">
|
||||||
|
<div class="calendar-grid calendar-grid-7" id="calendar">
|
||||||
|
<!-- DAYS of Week -->
|
||||||
|
<ng-container *ngFor="let d of daysOfWeek; index as i">
|
||||||
|
<div class="day">{{ d }}</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- PREV Month days -->
|
||||||
|
<ng-container *ngFor="let d of daysInPrevMonthToBeRendered">
|
||||||
|
<div
|
||||||
|
[ngClass]="{
|
||||||
|
'other-month calendar-cell': true,
|
||||||
|
disabled: isDateDisabled(d)
|
||||||
|
}"
|
||||||
|
(click)="selectDate(d)"
|
||||||
|
>
|
||||||
|
{{ pad(d.getDate()) }}
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- CURR Month days -->
|
||||||
|
<ng-container *ngFor="let d of daysInCurrentMonthToBeRendered">
|
||||||
|
<div
|
||||||
|
[ngClass]="{
|
||||||
|
'calendar-cell': true,
|
||||||
|
disabled: isDateDisabled(d),
|
||||||
|
selected: sameDate(selectedDate, d)
|
||||||
|
}"
|
||||||
|
(click)="selectDate(d)"
|
||||||
|
>
|
||||||
|
{{ pad(d.getDate()) }}
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- NEXT Month days -->
|
||||||
|
<ng-container *ngFor="let d of daysInNextMonthToBeRendered">
|
||||||
|
<div
|
||||||
|
[ngClass]="{
|
||||||
|
'other-month calendar-cell': true,
|
||||||
|
disabled: isDateDisabled(d),
|
||||||
|
selected: sameDate(selectedDate, d),
|
||||||
|
today: isToday(d)
|
||||||
|
}"
|
||||||
|
(click)="selectDate(d)"
|
||||||
|
>
|
||||||
|
{{ pad(d.getDate()) }}
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngSwitchCase="'months'">
|
||||||
|
<div class="calendar-grid calendar-grid-3" id="calendar">
|
||||||
|
<ng-container *ngFor="let m of monthsToBeRendered; index as i">
|
||||||
|
<div
|
||||||
|
[ngClass]="{
|
||||||
|
'calendar-cell': true,
|
||||||
|
today: isCurrentMonth(i),
|
||||||
|
selected: sameMonth(selectDate?.getMonth(), i)
|
||||||
|
}"
|
||||||
|
(click)="selectMonth(i)"
|
||||||
|
>
|
||||||
|
{{m}}
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngSwitchCase="'years'">
|
||||||
|
<div class="calendar-grid calendar-grid-5" id="calendar">
|
||||||
|
<ng-container *ngFor="let y of yearsToBeRendered">
|
||||||
|
<div
|
||||||
|
[ngClass]="{
|
||||||
|
'calendar-cell': true,
|
||||||
|
today: isCurrentYear(y),
|
||||||
|
selected: sameYear(selectDate?.getFullYear(), y)
|
||||||
|
}"
|
||||||
|
(click)="selectYear(y)"
|
||||||
|
>
|
||||||
|
{{y}}
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
|
<div class="calendar-actions">
|
||||||
|
<button id="todayBtn">Oggi</button><button id="clearBtn">Cancella</button
|
||||||
|
><button id="confirmBtn">Conferma</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,124 @@
|
|||||||
|
.calendar {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 15px;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-cell {
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
border: 1px solid #dde6e9;
|
||||||
|
border-radius: 3px;
|
||||||
|
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 .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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
@ -0,0 +1,321 @@
|
|||||||
|
import {
|
||||||
|
AfterViewInit,
|
||||||
|
Component,
|
||||||
|
ElementRef,
|
||||||
|
forwardRef,
|
||||||
|
Input,
|
||||||
|
Renderer2,
|
||||||
|
ViewChild,
|
||||||
|
} from "@angular/core";
|
||||||
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
|
||||||
|
import { NbpCalendarPattern, NbpCalendarPosition } from "@isp/xdce-widget";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'nbp-fid-calendar-generic',
|
||||||
|
templateUrl: './nbp-fid-calendar-genric.component.html',
|
||||||
|
styleUrls: ["./nbp-fid-calendar-genric.component.scss"],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
useExisting: forwardRef(() => NbpFidCalendarGenericComponent),
|
||||||
|
multi: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class NbpFidCalendarGenericComponent implements AfterViewInit, ControlValueAccessor {
|
||||||
|
@Input("nbpLabelPattern") pattern: NbpCalendarPattern =
|
||||||
|
NbpCalendarPattern.GGMMAAAA;
|
||||||
|
@Input("nbpPlacement") placement: string = "bottom-right";
|
||||||
|
@Input("id") id: string;
|
||||||
|
@Input("name") name: string;
|
||||||
|
daysOfWeek = ["lun", "mar", "mer", "gio", "ven", "sab", "dom"];
|
||||||
|
months = [
|
||||||
|
"Gennaio",
|
||||||
|
"Febbraio",
|
||||||
|
"Marzo",
|
||||||
|
"Aprile",
|
||||||
|
"Maggio",
|
||||||
|
"Giugno",
|
||||||
|
"Luglio",
|
||||||
|
"Agosto",
|
||||||
|
"Settembre",
|
||||||
|
"Ottobre",
|
||||||
|
"Novembre",
|
||||||
|
"Dicembre",
|
||||||
|
];
|
||||||
|
view: "days" | "months" | "years" = "days";
|
||||||
|
|
||||||
|
visibility: "shown" | "hidden" = "hidden";
|
||||||
|
|
||||||
|
disabledWeekdays = [0, 6]; // es: weekend
|
||||||
|
// CONFIGURAZIONE: range di date da disabilitare (array di oggetti {start, end})
|
||||||
|
disabledDateRanges = [
|
||||||
|
{ start: new Date(2025, 4, 10), end: new Date(2025, 4, 15) }, // 10-15 maggio 2025
|
||||||
|
// aggiungi altri range se necessario
|
||||||
|
];
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
this.renderer.setStyle(
|
||||||
|
this.calendarPopupRef.nativeElement,
|
||||||
|
"display",
|
||||||
|
"none"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
constructor(private renderer: Renderer2) {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
currentDate = new Date();
|
||||||
|
selectedDate: Date | null = null;
|
||||||
|
selectedDateStr : string | null = null;
|
||||||
|
monthYearText: string = "";
|
||||||
|
firstDayOfMonth: Date | null = null;
|
||||||
|
startDay: number = 0;
|
||||||
|
daysInCurrentMonth: number = 0;
|
||||||
|
daysInCurrentMonthToBeRendered: Date[] = [];
|
||||||
|
daysInPrevMonth: number = 0;
|
||||||
|
daysInPrevMonthToBeRendered: Date[] = [];
|
||||||
|
daysInNextMonthToBeRendered: Date[] = [];
|
||||||
|
monthsToBeRendered: string[] = [];
|
||||||
|
yearsToBeRendered: string[] = [];
|
||||||
|
|
||||||
|
@ViewChild("dateInput") dateInputRef: ElementRef;
|
||||||
|
@ViewChild("calendarPopup") calendarPopupRef: ElementRef;
|
||||||
|
|
||||||
|
public showCalendar() {
|
||||||
|
this.positionCalendarPopup();
|
||||||
|
this.renderCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public hideCalendar() {
|
||||||
|
this.renderer.setStyle(
|
||||||
|
this.calendarPopupRef.nativeElement,
|
||||||
|
"display",
|
||||||
|
"none"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderCalendar() {
|
||||||
|
if (this.view == "days") this.renderDays();
|
||||||
|
else if (this.view == "months") this.renderMonths();
|
||||||
|
else this.renderYears();
|
||||||
|
}
|
||||||
|
|
||||||
|
private positionCalendarPopup(): void {
|
||||||
|
const input = this.dateInputRef.nativeElement;
|
||||||
|
const popup = this.calendarPopupRef.nativeElement;
|
||||||
|
|
||||||
|
// Append to body if not already
|
||||||
|
if (popup.parentNode !== document.body) {
|
||||||
|
this.renderer.appendChild(document.body, popup);
|
||||||
|
}
|
||||||
|
|
||||||
|
const rect = input.getBoundingClientRect();
|
||||||
|
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||||
|
const scrollLeft =
|
||||||
|
window.pageXOffset || document.documentElement.scrollLeft;
|
||||||
|
|
||||||
|
this.renderer.setStyle(popup, "display", "block");
|
||||||
|
this.renderer.setStyle(popup, "position", "absolute");
|
||||||
|
this.renderer.setStyle(popup, "z-index", "9999");
|
||||||
|
this.renderer.setStyle(popup, "top", `${rect.bottom + scrollTop}px`);
|
||||||
|
this.renderer.setStyle(popup, "left", `${rect.left + scrollLeft}px`);
|
||||||
|
// this.renderer.setStyle(popup, 'min-width', `${rect.width}px`);
|
||||||
|
}
|
||||||
|
public pad(n: number): string {
|
||||||
|
return n < 10 ? "0" + n : n + "";
|
||||||
|
}
|
||||||
|
public isDateDisabled(date: Date): boolean {
|
||||||
|
// Disabilita per giorno della settimana
|
||||||
|
if (this.disabledWeekdays.indexOf(date.getDay()) != -1) return true;
|
||||||
|
// Disabilita per range
|
||||||
|
for (const range of this.disabledDateRanges) {
|
||||||
|
if (date >= range.start && date <= range.end) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public sameDate(d1: Date, d2: Date) {
|
||||||
|
return (
|
||||||
|
d1.getFullYear() === d2.getFullYear() &&
|
||||||
|
d1.getMonth() === d2.getMonth() &&
|
||||||
|
d1.getDate() === d2.getDate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public sameMonth(m1: number, m2: number) {
|
||||||
|
return m1 == m2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sameYear(y1: number, y2: number) {
|
||||||
|
return y1 == y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatDate(date: Date, format: string) {
|
||||||
|
if (!date) return "";
|
||||||
|
return format
|
||||||
|
.replace("gg", this.pad(date.getDate()))
|
||||||
|
.replace("mm", this.pad(date.getMonth() + 1))
|
||||||
|
.replace("aaaa", date.getFullYear().toString())
|
||||||
|
.replace("aa", String(date.getFullYear()).slice(-2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public selectDate(date: Date) {
|
||||||
|
if (this.isDateDisabled(date)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.selectedDate = date;
|
||||||
|
this.setDate(this.formatDate(date, this.pattern));
|
||||||
|
this.renderCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public selectMonth(idx) {
|
||||||
|
this.currentDate.setMonth(idx);
|
||||||
|
this.view = "days";
|
||||||
|
this.renderCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public selectYear(year: string) {
|
||||||
|
this.currentDate.setFullYear(Number(year));
|
||||||
|
this.view = "months";
|
||||||
|
this.renderCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public isToday(date: Date) {
|
||||||
|
return this.sameDate(date, new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
public isCurrentMonth(idx) {
|
||||||
|
return idx == this.currentDate.getMonth();
|
||||||
|
}
|
||||||
|
|
||||||
|
public isCurrentYear(year: string) {
|
||||||
|
return year === this.currentDate.getFullYear().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderDays() {
|
||||||
|
this.daysInPrevMonthToBeRendered = [];
|
||||||
|
this.daysInCurrentMonthToBeRendered = [];
|
||||||
|
this.daysInNextMonthToBeRendered = [];
|
||||||
|
|
||||||
|
this.monthYearText = `${
|
||||||
|
this.months[this.currentDate.getMonth()]
|
||||||
|
} ${this.currentDate.getFullYear()}`;
|
||||||
|
|
||||||
|
const year = this.currentDate.getFullYear();
|
||||||
|
const month = this.currentDate.getMonth();
|
||||||
|
|
||||||
|
this.firstDayOfMonth = new Date(year, month, 1);
|
||||||
|
this.startDay = (this.firstDayOfMonth.getDay() + 6) % 7;
|
||||||
|
|
||||||
|
this.daysInCurrentMonth = new Date(year, month + 1, 0).getDate();
|
||||||
|
this.daysInPrevMonth = new Date(year, month, 0).getDate();
|
||||||
|
|
||||||
|
for (let i = this.startDay; i > 0; i--) {
|
||||||
|
const day = this.daysInPrevMonth - i + 1;
|
||||||
|
const prevMonthDate = new Date(year, month - 1, day);
|
||||||
|
this.daysInPrevMonthToBeRendered.push(prevMonthDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 1; i <= this.daysInCurrentMonth; i++) {
|
||||||
|
const currMonthDate = new Date(year, month, i);
|
||||||
|
this.daysInCurrentMonthToBeRendered.push(currMonthDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalCells = 42; // 7 giorni x 6 settimane
|
||||||
|
const filledCells = this.startDay + this.daysInCurrentMonth;
|
||||||
|
const nextMonthDays = totalCells - filledCells;
|
||||||
|
for (let i = 1; i <= nextMonthDays; i++) {
|
||||||
|
const nextMonthDate = new Date(year, month + 1, i);
|
||||||
|
this.daysInNextMonthToBeRendered.push(nextMonthDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderMonths() {
|
||||||
|
this.monthsToBeRendered = [];
|
||||||
|
const monthTexts = this.months.map((m) => m.substring(0, 3));
|
||||||
|
this.monthYearText = this.currentDate.getFullYear().toString();
|
||||||
|
monthTexts.forEach((m, idx) => {
|
||||||
|
this.monthsToBeRendered.push(m);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderYears() {
|
||||||
|
this.yearsToBeRendered = [];
|
||||||
|
// 20 anni, 5x4
|
||||||
|
const base = Math.floor(this.currentDate.getFullYear() / 20) * 20;
|
||||||
|
this.monthYearText = `${base} - ${base + 19}`;
|
||||||
|
for (let y = base; y < base + 20; y++) {
|
||||||
|
this.yearsToBeRendered.push(y.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public changeView() {
|
||||||
|
if (this.view === "days") this.view = "months";
|
||||||
|
else if (this.view === "months") this.view = "years";
|
||||||
|
this.renderCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public prev() {
|
||||||
|
if (this.view === "days")
|
||||||
|
this.currentDate.setMonth(this.currentDate.getMonth() - 1);
|
||||||
|
else if (this.view === "months")
|
||||||
|
this.currentDate.setFullYear(this.currentDate.getFullYear() - 1);
|
||||||
|
else this.currentDate.setFullYear(this.currentDate.getFullYear() - 10);
|
||||||
|
this.renderCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public next() {
|
||||||
|
if (this.view === "days")
|
||||||
|
this.currentDate.setMonth(this.currentDate.getMonth() + 1);
|
||||||
|
else if (this.view === "months")
|
||||||
|
this.currentDate.setFullYear(this.currentDate.getFullYear() + 1);
|
||||||
|
else this.currentDate.setFullYear(this.currentDate.getFullYear() + 10);
|
||||||
|
this.renderCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public goToday() {
|
||||||
|
this.currentDate = new Date();
|
||||||
|
this.selectedDate = new Date();
|
||||||
|
this.setDate(this.formatDate(
|
||||||
|
this.selectedDate,
|
||||||
|
this.pattern
|
||||||
|
));
|
||||||
|
this.view = "days";
|
||||||
|
this.renderCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public clearSelection() {
|
||||||
|
this.selectedDate = null;
|
||||||
|
this.setDate("")
|
||||||
|
this.renderCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public confirmDate() {
|
||||||
|
this.hideCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
|
private onChange = (_: any) => {};
|
||||||
|
private onTouched = () => {};
|
||||||
|
|
||||||
|
writeValue(value: string | null): void {
|
||||||
|
this.selectedDateStr = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnChange(fn: any): void {
|
||||||
|
this.onChange = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnTouched(fn: any): void {
|
||||||
|
this.onTouched = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
setDate(value: string): void {
|
||||||
|
this.selectedDateStr = value;
|
||||||
|
this.onChange(value);
|
||||||
|
this.onTouched();
|
||||||
|
}
|
||||||
|
|
||||||
|
setDisabledState?(isDisabled: boolean): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
}
|
@ -50,7 +50,13 @@
|
|||||||
</nbp-input-container>
|
</nbp-input-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p class="new-part">Calendar generic (nbp-input-container + nbp-calendar-generic)</p>
|
<p class="new-part">Calendar generic (nbp-input-container + nbp-calendar-generic)</p>
|
||||||
|
<div>
|
||||||
|
<nbp-fid-calendar-generic [id]="'calendarDefault'" [name]="'calendarDefault'" [nbpLabelPattern]="_nbpCalendarPattern.GGMMAAAA" [nbpPlacement]="_nbpCalendarPosition.BOTTOM_LEFT"></nbp-fid-calendar-generic>
|
||||||
|
</div>
|
||||||
|
<!--
|
||||||
<div>
|
<div>
|
||||||
<nbp-input-container [nbpStyle]="_nbpStyle.DEFAULT" [nbpLabel]="'Default'">
|
<nbp-input-container [nbpStyle]="_nbpStyle.DEFAULT" [nbpLabel]="'Default'">
|
||||||
<nbp-calendar-generic [id]="'calendarDefault'" [name]="'calendarDefault'" [nbpStyle]="_nbpStyle.DEFAULT"
|
<nbp-calendar-generic [id]="'calendarDefault'" [name]="'calendarDefault'" [nbpStyle]="_nbpStyle.DEFAULT"
|
||||||
@ -76,7 +82,7 @@
|
|||||||
[startDateEnabled]="startDate" [endDateEnabled]="endDate">
|
[startDateEnabled]="startDate" [endDateEnabled]="endDate">
|
||||||
</nbp-calendar-generic>
|
</nbp-calendar-generic>
|
||||||
</nbp-input-container>
|
</nbp-input-container>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<p class="new-part">Combo (nbp-input-container + nbp-combo)</p>
|
<p class="new-part">Combo (nbp-input-container + nbp-combo)</p>
|
||||||
<div>
|
<div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user