Compare commits
5 Commits
feature/ca
...
master
Author | SHA1 | Date | |
---|---|---|---|
7a575c5375 | |||
3082f2129e | |||
b99a21dd26 | |||
9efeab2f44 | |||
![]() |
ea3ad437e5 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -4,3 +4,7 @@ node_modules
|
||||
build
|
||||
docs
|
||||
target
|
||||
|
||||
switch_git.bat
|
||||
arm-git.zip
|
||||
fid-git.zip
|
||||
|
BIN
fid-git.zip
BIN
fid-git.zip
Binary file not shown.
@ -50,6 +50,7 @@
|
||||
"@isp/xdce-arch-core": "1.50.30",
|
||||
"@isp/xdce-arch-core-base": "1.21.8",
|
||||
"@isp/xdce-widget": "1.125.2",
|
||||
"@ng-bootstrap/ng-bootstrap": "4.0.0",
|
||||
"ag-grid-angular": "22.1.1",
|
||||
"ag-grid-community": "22.1.1",
|
||||
"@ag-grid-community/all-modules": "22.1.1",
|
||||
|
125
src/index.ts
125
src/index.ts
@ -1,57 +1,67 @@
|
||||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { XdceArchModule } from '@isp/xdce-arch-core';
|
||||
import { NbpModule } from '@isp/xdce-widget';
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { ModuleWithProviders, NgModule, } from "@angular/core";
|
||||
import { FormsModule } from "@angular/forms";
|
||||
import { XdceArchModule } from "@isp/xdce-arch-core";
|
||||
import { NbpModule } from "@isp/xdce-widget";
|
||||
import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import {
|
||||
AgGridModule,
|
||||
AngularFrameworkComponentWrapper,
|
||||
AngularFrameworkOverrides,
|
||||
} from "ag-grid-angular";
|
||||
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 { RplDeclarations, RplEntryComponents, RplExports, RplRootProviders } from './widgetfideuram/components/nbp-fid-calendar-generic/@ng-bootstrap-noa11y/datepicker/datepicker-reply.module';
|
||||
import { NbpFidCalendarGenericComponent } from "./widgetfideuram/components/nbp-fid-calendar-generic/nbp-fid-calendar-generic.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";
|
||||
export { AgGridModule } from "ag-grid-angular";
|
||||
export * from "./widgetfideuram/components/nbp-bread-crumbs/nbp-bread-crumbs.component";
|
||||
export * from "./widgetfideuram/components/nbp-fid-bar-chart/nbp-fid-bar-chart.component";
|
||||
export * from "./widgetfideuram/components/nbp-fid-button-bar/nbp-fid-button-bar.component";
|
||||
export * from "./widgetfideuram/components/nbp-fid-calendar-generic/@ng-bootstrap-noa11y/datepicker/datepicker";
|
||||
export * from "./widgetfideuram/components/nbp-fid-calendar-generic/@ng-bootstrap-noa11y/datepicker/datepicker-day-view";
|
||||
export * from "./widgetfideuram/components/nbp-fid-calendar-generic/@ng-bootstrap-noa11y/datepicker/datepicker-input";
|
||||
export * from "./widgetfideuram/components/nbp-fid-calendar-generic/@ng-bootstrap-noa11y/datepicker/datepicker-navigation";
|
||||
export * from "./widgetfideuram/components/nbp-fid-calendar-generic/@ng-bootstrap-noa11y/datepicker/datepicker-reply-month-view";
|
||||
export * from "./widgetfideuram/components/nbp-fid-calendar-generic/@ng-bootstrap-noa11y/datepicker/datepicker-reply-years-view";
|
||||
export * from './widgetfideuram/components/nbp-fid-calendar-generic/@ng-bootstrap-noa11y/datepicker/datepicker-reply.module';
|
||||
export * from "./widgetfideuram/components/nbp-fid-calendar-generic/nbp-fid-calendar-generic.component";
|
||||
export { NbpFidCalendarGenericComponent } from "./widgetfideuram/components/nbp-fid-calendar-generic/nbp-fid-calendar-generic.component";
|
||||
export * from "./widgetfideuram/components/nbp-fid-combo/nbp-fid-combo.component";
|
||||
export * from "./widgetfideuram/components/nbp-fid-donut-chart/nbp-fid-donut-chart.component";
|
||||
export * from "./widgetfideuram/components/nbp-fid-pyramid-chart/nbp-fid-pyramid-chart.component";
|
||||
export * from "./widgetfideuram/components/nbp-fid-side-popup/nbp-fid-side-popup.component";
|
||||
export * from "./widgetfideuram/components/nbp-fid-table/nbp-fid-table.component";
|
||||
export * from "./widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component";
|
||||
export * from "./widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component.a11y";
|
||||
export * from "./widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tab.component.noa11y";
|
||||
export * from "./widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component";
|
||||
export * from "./widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component.a11y";
|
||||
export * from "./widgetfideuram/components/nbp-fid-toggle-tabset/nbp-fid-toggle-tabset.component.noa11y";
|
||||
export * from "./widgetfideuram/components/showcase/showcase.component";
|
||||
export * from "./widgetfideuram/components/showcase/showcase1.component";
|
||||
export * from "./widgetfideuram/components/widget-fideuram-showcase/widget-fideuram-showcase.component";
|
||||
|
||||
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 { FormsModule } from '@angular/forms';
|
||||
export { AgGridModule } from 'ag-grid-angular';
|
||||
|
||||
export { DATE_STRING_FORMAT, formatDate, formatNumber, setSpinnerMessage, clearSpinnerMessage } from './widgetfideuram/Utils';
|
||||
export * from "./widgetfideuram/Utils";
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
XdceArchModule,
|
||||
NbpModule,
|
||||
AgGridModule,
|
||||
FormsModule,
|
||||
],
|
||||
imports: [XdceArchModule, NbpModule, AgGridModule, FormsModule, NgbModule, TranslateModule, CommonModule],
|
||||
declarations: [
|
||||
NbpBreadCrumbsComponent,
|
||||
NbpFidBarChartComponent,
|
||||
@ -70,6 +80,8 @@ export { DATE_STRING_FORMAT, formatDate, formatNumber, setSpinnerMessage, clearS
|
||||
ShowcaseComponent,
|
||||
Showcase1Component,
|
||||
WidgetFideuramShowcaseComponent,
|
||||
NbpFidCalendarGenericComponent,
|
||||
...RplDeclarations
|
||||
],
|
||||
exports: [
|
||||
NbpBreadCrumbsComponent,
|
||||
@ -89,11 +101,13 @@ export { DATE_STRING_FORMAT, formatDate, formatNumber, setSpinnerMessage, clearS
|
||||
ShowcaseComponent,
|
||||
Showcase1Component,
|
||||
WidgetFideuramShowcaseComponent,
|
||||
AgGridModule
|
||||
AgGridModule,
|
||||
NbpFidCalendarGenericComponent,
|
||||
...RplExports
|
||||
],
|
||||
providers: [
|
||||
AngularFrameworkOverrides,
|
||||
AngularFrameworkComponentWrapper
|
||||
AngularFrameworkComponentWrapper,
|
||||
],
|
||||
entryComponents: [
|
||||
NbpFidToggleTabComponentA11Y,
|
||||
@ -101,14 +115,15 @@ export { DATE_STRING_FORMAT, formatDate, formatNumber, setSpinnerMessage, clearS
|
||||
NbpFidToggleTabsetComponentA11Y,
|
||||
NbpFidToggleTabsetComponentNOA11Y,
|
||||
NbpFidToggleTabComponent,
|
||||
NbpFidToggleTabsetComponent
|
||||
]
|
||||
NbpFidToggleTabsetComponent,
|
||||
...RplEntryComponents
|
||||
],
|
||||
})
|
||||
export class XdceWidgetFideuramModule {
|
||||
static forRoot(): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: XdceWidgetFideuramModule,
|
||||
providers: []
|
||||
providers: [...RplRootProviders],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
import {Injectable, TemplateRef} from '@angular/core';
|
||||
import {DayTemplateContextNOA11Y} from './datepicker-day-template-context';
|
||||
import {NgbDateStruct} from './ngb-date-struct';
|
||||
|
||||
/**
|
||||
* Configuration service for the NgbDatepicker component.
|
||||
* You can inject this service, typically in your root component, and customize the values of its properties in
|
||||
* order to provide default values for all the datepickers used in the application.
|
||||
*/
|
||||
@Injectable()
|
||||
export class NgbDatepickerConfigNOA11Y {
|
||||
dayTemplate: TemplateRef<DayTemplateContextNOA11Y>;
|
||||
displayMonths = 1;
|
||||
firstDayOfWeek = 1;
|
||||
markDisabled: (date: NgbDateStruct, current: {year: number, month: number}) => boolean;
|
||||
minDate: NgbDateStruct;
|
||||
maxDate: NgbDateStruct;
|
||||
navigation: 'select' | 'arrows' | 'none' = 'select';
|
||||
outsideDays: 'visible' | 'collapsed' | 'hidden' = 'visible';
|
||||
showWeekdays = true;
|
||||
showWeekNumbers = false;
|
||||
startDate: {year: number, month: number};
|
||||
disabledWeekend: boolean;
|
||||
holidays: Array<NgbDateStruct>;
|
||||
taxDeadlines: Array<NgbDateStruct>;
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
import {NgbDateStruct} from './ngb-date-struct';
|
||||
|
||||
/**
|
||||
* Context for the datepicker 'day' template in case you want to override the default one
|
||||
*/
|
||||
export interface DayTemplateContextNOA11Y {
|
||||
/**
|
||||
* Month currently displayed by the datepicker
|
||||
*/
|
||||
currentMonth: number;
|
||||
|
||||
/**
|
||||
* Date that corresponds to the template
|
||||
*/
|
||||
date: NgbDateStruct;
|
||||
|
||||
/**
|
||||
* True if current date is disabled
|
||||
*/
|
||||
disabled: boolean;
|
||||
|
||||
/**
|
||||
* True if current date is focused
|
||||
*/
|
||||
focused: boolean;
|
||||
|
||||
/**
|
||||
* True if current date is selected
|
||||
*/
|
||||
selected: boolean;
|
||||
|
||||
/**
|
||||
* True if current date is today
|
||||
*/
|
||||
isToday: boolean;
|
||||
|
||||
/**
|
||||
* True if current date is a weekend day
|
||||
*/
|
||||
isWeekend: boolean;
|
||||
|
||||
/**
|
||||
* True if current date is a weekend day
|
||||
*/
|
||||
isDayPast: boolean;
|
||||
|
||||
/**
|
||||
* True if current date is a tax deadlines
|
||||
*/
|
||||
isFiscalDay: boolean;
|
||||
|
||||
/**
|
||||
* True if current date is an holiday
|
||||
*/
|
||||
isHoliday?: boolean;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
<div [ngClass]=" abilitaGiorni(date) ? 'ngbdatepickerdayview' : 'ngbdatepickerdayviewdisabled'">
|
||||
<span [attr.role]="'button'" [attr.aria-label]="' '" [attr.aria.labelledby]="' '" [attr.aria-describedby]="labelDay(date)">{{ date.day }}</span>
|
||||
<div *ngIf="isFiscalDay" class="is-fiscal"></div>
|
||||
</div>
|
@ -0,0 +1,32 @@
|
||||
.ngbdatepickerdayview {
|
||||
border-radius: 0!important;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
width: inherit!important;
|
||||
height: inherit!important;
|
||||
line-height: 2.6875rem!important;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.ngbdatepickerdayviewdisabled {
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
width: inherit!important;
|
||||
height: inherit!important;
|
||||
line-height: 2.6875rem!important;
|
||||
vertical-align: middle;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.is-fiscal {
|
||||
// Triangolo bianco
|
||||
border-bottom-width: 0.5rem;
|
||||
border-bottom-style: solid;
|
||||
border-left: 0.5rem solid transparent;
|
||||
border-right: 0.5rem solid transparent;
|
||||
transform: rotate(45deg);
|
||||
transform-origin: top;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: -0.5rem;
|
||||
}
|
||||
|
@ -0,0 +1,71 @@
|
||||
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
|
||||
import {NgbDateStruct} from './ngb-date-struct';
|
||||
|
||||
@Component({
|
||||
selector: '[ngbFidDatepickerDayView]',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: {
|
||||
'class': 'btn-secondary',
|
||||
'[class.bg-primary]': 'selected',
|
||||
'[class.text-white]': 'selected',
|
||||
'[class.text-muted]': 'isMuted()',
|
||||
'[class.outside]': 'isMuted()',
|
||||
'[class.active]': 'focused',
|
||||
'[class.is-today]': 'isToday',
|
||||
'[class.is-holiday]' : 'isHoliday',
|
||||
'[class.is-weekend]': 'isWeekend',
|
||||
'[class.is-daypast]': 'isDayPast',
|
||||
'[class.is-fiscal]' : 'isFiscalDay'
|
||||
},
|
||||
|
||||
templateUrl: './datepicker-day-view.html',
|
||||
styleUrls: ['./datepicker-day-view.scss'],
|
||||
|
||||
})
|
||||
export class NgbDatepickerDayViewNOA11Y {
|
||||
@Input() currentMonth: number;
|
||||
@Input() date: NgbDateStruct;
|
||||
@Input() disabled: boolean;
|
||||
@Input() focused: boolean;
|
||||
@Input() selected: boolean;
|
||||
|
||||
@Input() startDateEnabled: any;
|
||||
@Input() endDateEnabled: any;
|
||||
|
||||
@Input() isToday: boolean;
|
||||
@Input() isWeekend: boolean;
|
||||
@Input() isDayPast: boolean;
|
||||
@Input() taxDeadlines: any;
|
||||
@Input() isFiscalDay: boolean;
|
||||
@Input() isHoliday : boolean;
|
||||
|
||||
isMuted() { return !this.selected && (this.date.month !== this.currentMonth || this.disabled); }
|
||||
|
||||
abilitaGiorni(data) {
|
||||
let startDate, endDate;
|
||||
let buffer = new Date(data.year, data.month - 1, data.day);
|
||||
|
||||
if (this.startDateEnabled instanceof Date) {
|
||||
startDate = new Date(this.startDateEnabled.getFullYear(), this.startDateEnabled.getMonth(), this.startDateEnabled.getDate());
|
||||
endDate = new Date(this.endDateEnabled.getFullYear(), this.endDateEnabled.getMonth(), this.endDateEnabled.getDate());
|
||||
} else {
|
||||
startDate = new Date(this.startDateEnabled.year, this.startDateEnabled.month - 1, this.startDateEnabled.day);
|
||||
endDate = new Date(this.endDateEnabled.year, this.endDateEnabled.month - 1, this.endDateEnabled.day);
|
||||
}
|
||||
|
||||
if (startDate && endDate) {
|
||||
return (startDate <= buffer && buffer <= endDate);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
labelDay(data){
|
||||
let result;
|
||||
let weekdays = ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'];
|
||||
result = weekdays[new Date(data.year, data.month - 1, data.day).getDay()] + ' ' + data.day;
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import { NgbDateStruct } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
const WEEKDAYS_SHORT = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'];
|
||||
const MONTHS_SHORT = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||
const MONTHS_FULL = [
|
||||
'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November',
|
||||
'December'
|
||||
];
|
||||
|
||||
/**
|
||||
* Type of the service supplying month and weekday names to to NgbDatepicker component.
|
||||
* See the i18n demo for how to extend this class and define a custom provider for i18n.
|
||||
*/
|
||||
@Injectable()
|
||||
export abstract class NgbDatepickerI18nNOA11Y {
|
||||
/**
|
||||
* Returns the short weekday name to display in the heading of the month view.
|
||||
* With default calendar we use ISO 8601: 'weekday' is 1=Mon ... 7=Sun
|
||||
*/
|
||||
abstract getWeekdayShortName(weekday: number): string;
|
||||
|
||||
/**
|
||||
* Returns the short month name to display in the date picker navigation.
|
||||
* With default calendar we use ISO 8601: 'month' is 1=Jan ... 12=Dec
|
||||
*/
|
||||
abstract getMonthShortName(month: number): string;
|
||||
|
||||
/**
|
||||
* Returns the full month name to display in the date picker navigation.
|
||||
* With default calendar we use ISO 8601: 'month' is 1=January ... 12=December
|
||||
*/
|
||||
abstract getMonthFullName(month: number): string;
|
||||
|
||||
abstract getDayAriaLabel(date: NgbDateStruct): string;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class NgbDatepickerI18nDefaultNOA11Y extends NgbDatepickerI18nNOA11Y {
|
||||
getWeekdayShortName(weekday: number): string { return WEEKDAYS_SHORT[weekday - 1]; }
|
||||
|
||||
getMonthShortName(month: number): string { return MONTHS_SHORT[month - 1]; }
|
||||
|
||||
getMonthFullName(month: number): string { return MONTHS_FULL[month - 1]; }
|
||||
|
||||
getDayAriaLabel(date: NgbDateStruct): string { return `${date.day} ${MONTHS_FULL[date.month-1]} ${date.year}`}
|
||||
}
|
@ -0,0 +1,509 @@
|
||||
import {
|
||||
Directive,
|
||||
Input,
|
||||
ComponentRef,
|
||||
ElementRef,
|
||||
ViewContainerRef,
|
||||
Renderer2,
|
||||
ComponentFactoryResolver,
|
||||
NgZone,
|
||||
TemplateRef,
|
||||
forwardRef,
|
||||
EventEmitter,
|
||||
Output,
|
||||
OnChanges,
|
||||
OnDestroy,
|
||||
SimpleChanges, QueryList
|
||||
} from '@angular/core';
|
||||
import { AbstractControl, ControlValueAccessor, Validator, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
|
||||
|
||||
import { NgbDate } from './ngb-date';
|
||||
import { RplCalendarNOA11Y, NgbDatepickerNavigateEventNOA11Y } from './datepicker';
|
||||
import { DayTemplateContextNOA11Y } from './datepicker-day-template-context';
|
||||
import { NgbDateParserFormatterNOA11Y } from './ngb-date-parser-formatter';
|
||||
|
||||
import { Positioning } from '../util/positioning';
|
||||
import { NgbDateStruct } from './ngb-date-struct';
|
||||
import { NgbCalendarNOA11Y } from './ngb-calendar';
|
||||
import { NgbDatepickerServiceNOA11Y } from './datepicker-service';
|
||||
import {NbpCalendarPattern, NbpCalendarPosition, NbpDateSeparator} from '../../nbp-calendar-generic.enum';
|
||||
import {EventManager, NATIVE_CONNECTOR} from '@isp/xdce-arch-core-base';
|
||||
import {take} from 'rxjs/operators';
|
||||
|
||||
const NGB_DATEPICKER_VALUE_ACCESSOR = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => NgbInputDatepickerNOA11Y),
|
||||
multi: true
|
||||
};
|
||||
|
||||
const NGB_DATEPICKER_VALIDATOR = {
|
||||
provide: NG_VALIDATORS,
|
||||
useExisting: forwardRef(() => NgbInputDatepickerNOA11Y),
|
||||
multi: true
|
||||
};
|
||||
|
||||
/**
|
||||
* A directive that makes it possible to have datepickers on input fields.
|
||||
* Manages integration with the input field itself (data entry) and ngModel (validation etc.).
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'input[rplFidCalendarNOA11Y]',
|
||||
exportAs: 'rplFidCalendarNOA11Y',
|
||||
host: {
|
||||
'(input)': 'waitForFormat($event.target.value)',
|
||||
'(change)': 'manualDateChange($event.target.value, true)',
|
||||
'(keyup.esc)': 'close()',
|
||||
'(blur)': 'onBlur()',
|
||||
'(document:click)':'onFocusOut($event)'
|
||||
},
|
||||
providers: [NGB_DATEPICKER_VALUE_ACCESSOR, NGB_DATEPICKER_VALIDATOR, NgbDatepickerServiceNOA11Y]
|
||||
})
|
||||
|
||||
export class NgbInputDatepickerNOA11Y implements OnChanges,
|
||||
OnDestroy, ControlValueAccessor, Validator {
|
||||
private _cRef: ComponentRef<RplCalendarNOA11Y> = null;
|
||||
private _model: NgbDate;
|
||||
private _zoneSubscription: any;
|
||||
|
||||
opened: boolean;
|
||||
|
||||
dataBeforeChange;
|
||||
/**
|
||||
* Reference for the custom template for the day display
|
||||
*/
|
||||
@Input() dayTemplate: TemplateRef<DayTemplateContextNOA11Y>;
|
||||
|
||||
/**
|
||||
* Number of months to display
|
||||
*/
|
||||
@Input() displayMonths: number;
|
||||
|
||||
/**
|
||||
* First day of the week. With default calendar we use ISO 8601: 1=Mon ... 7=Sun
|
||||
*/
|
||||
@Input() firstDayOfWeek: number;
|
||||
|
||||
/**
|
||||
* Callback to mark a given date as disabled.
|
||||
* 'Current' contains the month that will be displayed in the view
|
||||
*/
|
||||
@Input() markDisabled: (date: NgbDateStruct, current: { year: number, month: number }) => boolean;
|
||||
|
||||
/**
|
||||
* Min date for the navigation. If not provided will be 10 years before today or `startDate`
|
||||
*/
|
||||
_minDate: NgbDateStruct;
|
||||
@Input()
|
||||
get minDate() {
|
||||
return this._minDate;
|
||||
}
|
||||
set minDate(minDate: NgbDateStruct) {
|
||||
this._minDate = minDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Max date for the navigation. If not provided will be 10 years from today or `startDate`
|
||||
*/
|
||||
_maxDate: NgbDateStruct;
|
||||
@Input()
|
||||
get maxDate() {
|
||||
return this._maxDate;
|
||||
}
|
||||
set maxDate(maxDate: NgbDateStruct) {
|
||||
this._maxDate = maxDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigation type: `select` (default with select boxes for month and year), `arrows`
|
||||
* (without select boxes, only navigation arrows) or `none` (no navigation at all)
|
||||
*/
|
||||
@Input() navigation: 'select' | 'arrows' | 'none';
|
||||
|
||||
/**
|
||||
* The way to display days that don't belong to current month: `visible` (default),
|
||||
* `hidden` (not displayed) or `collapsed` (not displayed with empty space collapsed)
|
||||
*/
|
||||
@Input() outsideDays: 'visible' | 'collapsed' | 'hidden';
|
||||
|
||||
|
||||
/**
|
||||
* Placement of a datepicker popup. Accepts: "top", "bottom", "left", "right", "bottom-left",
|
||||
* "bottom-right" etc.
|
||||
*/
|
||||
@Input() placement = 'bottom-left';
|
||||
|
||||
/**
|
||||
* Whether to display days of the week
|
||||
*/
|
||||
@Input() showWeekdays: boolean;
|
||||
|
||||
/**
|
||||
* Whether to display week numbers
|
||||
*/
|
||||
@Input() showWeekNumbers: boolean;
|
||||
|
||||
/**
|
||||
* Date to open calendar with.
|
||||
* With default calendar we use ISO 8601: 'month' is 1=Jan ... 12=Dec.
|
||||
* If nothing or invalid date provided, calendar will open with current month.
|
||||
* Use 'navigateTo(date)' as an alternative
|
||||
*/
|
||||
@Input() startDate: { year: number, month: number };
|
||||
|
||||
@Input() disabledWeekend: boolean;
|
||||
|
||||
@Input() holidays: Array<NgbDateStruct>;
|
||||
|
||||
@Input() taxDeadlines: Array<NgbDateStruct>;
|
||||
|
||||
/**
|
||||
* input for unifiedVg
|
||||
*/
|
||||
@Input() isUnifiedVg: boolean;
|
||||
|
||||
private _pattern: any = NbpCalendarPattern;
|
||||
@Input() nbpLabelPattern: NbpCalendarPattern = this._pattern.GGMMAAAA;
|
||||
|
||||
private _separator = NbpDateSeparator;
|
||||
@Input() nbpDateSeparator: NbpDateSeparator = this._separator.DOT;
|
||||
|
||||
/**
|
||||
* An event fired when navigation happens and currently displayed month changes.
|
||||
* See NgbDatepickerNavigateEvent for the payload info.
|
||||
*/
|
||||
@Output() navigate = new EventEmitter<NgbDatepickerNavigateEventNOA11Y>();
|
||||
|
||||
private _onChange = (_: any) => { };
|
||||
private _onTouched = () => { };
|
||||
private _validatorChange = () => { };
|
||||
|
||||
private _placement: any = NbpCalendarPosition;
|
||||
private positionService: Positioning;
|
||||
|
||||
private get isInModal(): boolean {
|
||||
let el: HTMLElement = (<HTMLElement> this._elRef.nativeElement);
|
||||
|
||||
if (!el || !el.parentElement || !el.parentElement.tagName) {
|
||||
return false;
|
||||
}
|
||||
let tagName: string = el.parentElement.tagName;
|
||||
|
||||
while (!tagName.match(/modal/i) && !tagName.match(/body/i)) {
|
||||
el = el.parentElement;
|
||||
tagName = el.parentElement && el.parentElement.tagName ? el.parentElement.tagName : '';
|
||||
}
|
||||
return tagName && !!tagName.match(/modal/i);
|
||||
}
|
||||
|
||||
private get isCorporate(): boolean {
|
||||
return this._cRef.location.nativeElement.classList.contains('isp-corporate-mode-wrapper');
|
||||
}
|
||||
|
||||
|
||||
get _isNative(): boolean {
|
||||
return /(ip(a|o)d|iphone|android)/ig.test(window.navigator.userAgent)
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _parserFormatter: NgbDateParserFormatterNOA11Y, private _elRef: ElementRef, private _vcRef: ViewContainerRef,
|
||||
private _renderer: Renderer2, private _cfr: ComponentFactoryResolver, ngZone: NgZone,
|
||||
private _service: NgbDatepickerServiceNOA11Y, private _calendar: NgbCalendarNOA11Y,
|
||||
private eventManager: EventManager
|
||||
) {
|
||||
this.positionService = new Positioning();
|
||||
this._zoneSubscription = ngZone.onStable.subscribe(() => this.setDatepickerPosition());
|
||||
}
|
||||
|
||||
setDatepickerPosition() {
|
||||
if (!this._cRef || !this._elRef) {
|
||||
return;
|
||||
}
|
||||
const calendar: HTMLElement = this._cRef.location.nativeElement;
|
||||
const datepickerInput: HTMLElement = this._elRef.nativeElement;
|
||||
const calendarClone: HTMLElement = (<HTMLElement>calendar.cloneNode(true));
|
||||
|
||||
this._renderer.removeClass(calendarClone.querySelector('.isp-main-datepicker'), 'd-none');
|
||||
this._renderer.addClass(calendarClone, 'invisible');
|
||||
window.document.body.appendChild(calendarClone);
|
||||
const navigation: number = calendarClone.querySelector(".isp-datepicker-navigation")['offsetHeight'];
|
||||
const routingView: number = calendarClone.querySelector(".isp-datepicker-routing-view")['offsetHeight'];
|
||||
const position: ClientRect = this.positionService.positionElements(datepickerInput, calendarClone, this.placement);
|
||||
|
||||
this._renderer.removeChild(calendarClone.parentElement, calendarClone);
|
||||
switch (this.placement) {
|
||||
case this._placement.TOP:
|
||||
case this._placement.TOP_RIGHT:
|
||||
case this._placement.TOP_LEFT:
|
||||
position.top = this.isCorporate ? (-navigation - routingView) : (-navigation - routingView - 3);
|
||||
break;
|
||||
case this._placement.RIGHT:
|
||||
case this._placement.LEFT:
|
||||
position.top = (-navigation - (routingView / 2));
|
||||
break;
|
||||
}
|
||||
calendar.style.top = `${position.top}px`;
|
||||
calendar.style.left = `${position.left}px`;
|
||||
this._renderer.removeClass(calendar.querySelector('.isp-main-datepicker'), 'd-none');
|
||||
}
|
||||
|
||||
registerOnChange(fn: (value: any) => any): void { this._onChange = fn; }
|
||||
|
||||
registerOnTouched(fn: () => any): void { this._onTouched = fn; }
|
||||
|
||||
registerOnValidatorChange(fn: () => void): void { this._validatorChange = fn; };
|
||||
|
||||
setDisabledState(isDisabled: boolean): void {
|
||||
this._renderer.setProperty(this._elRef.nativeElement, 'disabled', isDisabled);
|
||||
if (this.isOpen()) {
|
||||
this._cRef.instance.setDisabledState(isDisabled);
|
||||
}
|
||||
}
|
||||
|
||||
validate(c: AbstractControl): { [key: string]: any } {
|
||||
const value = c.value;
|
||||
|
||||
if (value === null || value === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
let newValue: NgbDate;
|
||||
newValue = new NgbDate(parseInt(value.substring(0, 4), 10),
|
||||
parseInt(value.substring(5, 7), 10),
|
||||
parseInt(value.substring(8, 10), 10));
|
||||
if (!this._calendar.isValid(newValue)) {
|
||||
return { 'ngbDate': { invalid: c.value } };
|
||||
}
|
||||
|
||||
if (this.minDate && NgbDate.from(newValue).before(NgbDate.from(this.minDate))) {
|
||||
return { 'ngbDate': { requiredBefore: this.minDate } };
|
||||
}
|
||||
|
||||
if (this.maxDate && NgbDate.from(newValue).after(NgbDate.from(this.maxDate))) {
|
||||
return { 'ngbDate': { requiredAfter: this.maxDate } };
|
||||
}
|
||||
} else {
|
||||
if (!this._calendar.isValid(value)) {
|
||||
return { 'ngbDate': { invalid: c.value } };
|
||||
}
|
||||
|
||||
if (this.minDate && NgbDate.from(value).before(NgbDate.from(this.minDate))) {
|
||||
return { 'ngbDate': { requiredBefore: this.minDate } };
|
||||
}
|
||||
|
||||
if (this.maxDate && NgbDate.from(value).after(NgbDate.from(this.maxDate))) {
|
||||
return { 'ngbDate': { requiredAfter: this.maxDate } };
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
writeValue(value: any) {
|
||||
const ngbDate = value ? new NgbDate(value.year, value.month, value.day) : null;
|
||||
this._model = this._calendar.isValid(value) ? ngbDate : null;
|
||||
this._writeModelValue(this._model);
|
||||
}
|
||||
|
||||
waitForFormat(value: string, updateView = false) {
|
||||
this.dataBeforeChange = value;
|
||||
let actualValue = value;
|
||||
setTimeout(() => {
|
||||
if (actualValue === this.dataBeforeChange) {
|
||||
this.manualDateChange(actualValue, updateView);
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
manualDateChange(value: string, updateView = false) {
|
||||
let datesplitted = value.split(/[./-]/g);
|
||||
if(this.nbpLabelPattern == this._pattern.MMAAAA && datesplitted.length < 3 && datesplitted.length > 1)
|
||||
{
|
||||
value = '01.' + value;
|
||||
}
|
||||
let [year, month, day] = value.split('-');
|
||||
if (this.isUnifiedVg && this._isNative) {
|
||||
if (year && month && day) {
|
||||
// value = day + '.' + month + '.' + year;
|
||||
}
|
||||
}
|
||||
this._model = this._service.toValidDate(this._parserFormatter.parse(value, this.nbpLabelPattern), null);
|
||||
this._onChange(this._model ? this._model.toStruct() : (value === '' ? null : value));
|
||||
if (updateView && this._model) {
|
||||
this._writeModelValue(this._model);
|
||||
}
|
||||
}
|
||||
|
||||
isOpen() { return !!this._cRef; }
|
||||
|
||||
/**
|
||||
* Opens the datepicker with the selected date indicated by the ngModel value.
|
||||
*/
|
||||
open(mode: boolean) {
|
||||
if (!this.isOpen()) {
|
||||
|
||||
if (this._model && (this.minDate || this.maxDate)) {
|
||||
if ((this.minDate && NgbDate.from(this._model).before(NgbDate.from(this.minDate))) || (this.maxDate && NgbDate.from(this._model).after(NgbDate.from(this.maxDate)))) {
|
||||
this._model = null;
|
||||
}
|
||||
}
|
||||
|
||||
const cf = this._cfr.resolveComponentFactory(RplCalendarNOA11Y);
|
||||
this._cRef = this._vcRef.createComponent(cf);
|
||||
|
||||
this._applyPopupStyling(this._cRef.location.nativeElement);
|
||||
this._cRef.instance.writeValue(this._model);
|
||||
this._applyDatepickerInputs(this._cRef.instance);
|
||||
this._subscribeForDatepickerOutputs(this._cRef.instance);
|
||||
|
||||
this._cRef.instance.disabledWeekend = this.disabledWeekend;
|
||||
this._cRef.instance.holidays = this.holidays;
|
||||
this._cRef.instance.taxDeadlines = this.taxDeadlines;
|
||||
|
||||
if (mode){
|
||||
this._renderer.addClass(this._cRef.location.nativeElement, 'isp-corporate-mode-wrapper');
|
||||
}
|
||||
this._cRef.instance.ngOnInit();
|
||||
|
||||
// date selection event handling
|
||||
this._cRef.instance.registerOnChange((selectedDate) => {
|
||||
this.writeValue(selectedDate);
|
||||
this._onChange(selectedDate);
|
||||
if (!this.opened) {
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
|
||||
// focus handling
|
||||
this._cRef.instance.focus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the datepicker popup.
|
||||
*/
|
||||
close() {
|
||||
if (this.isOpen()) {
|
||||
this._vcRef.remove(this._vcRef.indexOf(this._cRef.hostView));
|
||||
this._cRef = null;
|
||||
this.eventManager.emit('DATEPICKER_CLOSE', true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the datepicker popup (opens when closed and closes when opened).
|
||||
*/
|
||||
toggle(mode: boolean) {
|
||||
if (this.isOpen()) {
|
||||
this.close();
|
||||
} else {
|
||||
this.open(mode);
|
||||
}
|
||||
}
|
||||
|
||||
addMargin(value: string) {
|
||||
if (this._cRef) {
|
||||
this._renderer.setStyle(this._cRef.location.nativeElement, "margin-top", value);
|
||||
}
|
||||
}
|
||||
|
||||
onFocusOut($event) {
|
||||
const parent: HTMLElement = this._elRef.nativeElement.parentElement;
|
||||
const icon: HTMLElement = parent.querySelector('i');
|
||||
|
||||
if(this.isOpen() && !(event.target === icon || this._elRef.nativeElement.contains($event.target) || this._cRef.location.nativeElement.contains($event.target))) {
|
||||
this._cRef.instance.focusOutComponent($event);
|
||||
console.info('onfocusout close');
|
||||
this.close();
|
||||
if (this.eventManager) {
|
||||
this.eventManager.emit('HANDLER_CALENDAR', {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates current view to provided date.
|
||||
* With default calendar we use ISO 8601: 'month' is 1=Jan ... 12=Dec.
|
||||
* If nothing or invalid date provided calendar will open current month.
|
||||
* Use 'startDate' input as an alternative
|
||||
*/
|
||||
navigateTo(date?: { year: number, month: number }) {
|
||||
if (this.isOpen()) {
|
||||
this._cRef.instance.navigateTo(date);
|
||||
}
|
||||
}
|
||||
|
||||
onBlur() { this._onTouched(); }
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['minDate'] || changes['maxDate']) {
|
||||
this._validatorChange();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.close();
|
||||
this._zoneSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
getCalendarHeight() {
|
||||
if (this._cRef && this._cRef.instance.datepickerRoutingView) {
|
||||
return this._cRef.instance.datepickerRoutingView.getRoutingViewHeight();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
getCalendarWidth() {
|
||||
if (this._cRef && this._cRef.instance.datepickerRoutingView) {
|
||||
return this._cRef.instance.datepickerRoutingView.getRoutingViewWidth();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
getInputHeight() {
|
||||
if (this._elRef) {
|
||||
return this._elRef.nativeElement.offsetHeight;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private _applyDatepickerInputs(datepickerInstance: RplCalendarNOA11Y): void {
|
||||
['dayTemplate', 'displayMonths', 'firstDayOfWeek', 'markDisabled', 'minDate', 'maxDate', 'navigation',
|
||||
'outsideDays', 'showNavigation', 'showWeekdays', 'showWeekNumbers']
|
||||
.forEach((optionName: string) => {
|
||||
if ((this as any)[optionName] !== undefined) {
|
||||
(datepickerInstance as any)[optionName] = (this as any)[optionName];
|
||||
}
|
||||
});
|
||||
datepickerInstance.startDate = this.startDate || this._model;
|
||||
}
|
||||
|
||||
private _applyPopupStyling(nativeElement: any) {
|
||||
this._renderer.addClass(nativeElement, 'dropdown-menu');
|
||||
this._renderer.setStyle(nativeElement, 'padding', '0');
|
||||
}
|
||||
|
||||
private _subscribeForDatepickerOutputs(datepickerInstance: RplCalendarNOA11Y) {
|
||||
datepickerInstance.navigate.subscribe((date: any) => this.navigate.emit(date));
|
||||
}
|
||||
|
||||
private _writeModelValue(model: NgbDate) {
|
||||
if (model) {
|
||||
const { day, month, year } = model;
|
||||
|
||||
if(this.nbpLabelPattern == this._pattern.MMAAAA) {
|
||||
this._renderer.setProperty(this._elRef.nativeElement, 'value', this._parserFormatter.format({year, month, day: 0}, this.nbpLabelPattern, this.nbpDateSeparator));
|
||||
}
|
||||
else {
|
||||
this._renderer.setProperty(this._elRef.nativeElement, 'value', this._parserFormatter.format({year, month, day}, this.nbpLabelPattern, this.nbpDateSeparator));
|
||||
}
|
||||
|
||||
} else {
|
||||
this._renderer.setProperty(this._elRef.nativeElement, 'value', this._parserFormatter.format(model, this.nbpLabelPattern, this.nbpDateSeparator));
|
||||
}
|
||||
|
||||
if (this.isOpen()) {
|
||||
this._cRef.instance.writeValue(model);
|
||||
this._onTouched();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {NgbDatepickerServiceNOA11Y} from './datepicker-service';
|
||||
import {NgbCalendarNOA11Y} from './ngb-calendar';
|
||||
import {toString} from '../util/util';
|
||||
import {NgbDate} from './ngb-date';
|
||||
|
||||
enum Key {
|
||||
Enter = 13,
|
||||
Space = 32,
|
||||
PageUp = 33,
|
||||
PageDown = 34,
|
||||
End = 35,
|
||||
Home = 36,
|
||||
ArrowLeft = 37,
|
||||
ArrowUp = 38,
|
||||
ArrowRight = 39,
|
||||
ArrowDown = 40
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class NgbDatepickerKeyMapServiceNOA11Y {
|
||||
private _minDate: NgbDate;
|
||||
private _maxDate: NgbDate;
|
||||
private _firstViewDate: NgbDate;
|
||||
private _lastViewDate: NgbDate;
|
||||
|
||||
constructor(private _service: NgbDatepickerServiceNOA11Y, private _calendar: NgbCalendarNOA11Y) {
|
||||
_service.model$.subscribe(model => {
|
||||
this._minDate = model.minDate;
|
||||
this._maxDate = model.maxDate;
|
||||
this._firstViewDate = model.firstDate;
|
||||
this._lastViewDate = model.lastDate;
|
||||
});
|
||||
}
|
||||
|
||||
processKey(event: KeyboardEvent) {
|
||||
if (Key[toString(event.which)]) {
|
||||
switch (event.which) {
|
||||
case Key.PageUp:
|
||||
this._service.focusMove(event.shiftKey ? 'y' : 'm', -1);
|
||||
break;
|
||||
case Key.PageDown:
|
||||
this._service.focusMove(event.shiftKey ? 'y' : 'm', 1);
|
||||
break;
|
||||
case Key.End:
|
||||
this._service.focus(event.shiftKey ? this._maxDate : this._lastViewDate);
|
||||
break;
|
||||
case Key.Home:
|
||||
this._service.focus(event.shiftKey ? this._minDate : this._firstViewDate);
|
||||
break;
|
||||
case Key.ArrowLeft:
|
||||
this._service.focusMove('d', -1);
|
||||
break;
|
||||
case Key.ArrowUp:
|
||||
this._service.focusMove('d', -this._calendar.getDaysPerWeek());
|
||||
break;
|
||||
case Key.ArrowRight:
|
||||
this._service.focusMove('d', 1);
|
||||
break;
|
||||
case Key.ArrowDown:
|
||||
this._service.focusMove('d', this._calendar.getDaysPerWeek());
|
||||
break;
|
||||
case Key.Enter:
|
||||
case Key.Space:
|
||||
this._service.focusSelect();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
<select [disabled]="disabled" class="custom-select d-inline-block" [value]="date?.month" (change)="changeMonth($event.target.value)"
|
||||
tabindex="-1">
|
||||
<option *ngFor="let m of months" [value]="m">{{ i18n.getMonthShortName(m) }}</option>
|
||||
</select>
|
||||
<select [disabled]="disabled" class="custom-select d-inline-block" [value]="date?.year" (change)="changeYear($event.target.value)"
|
||||
tabindex="-1">
|
||||
<option *ngFor="let y of years" [value]="y">{{ y }}</option>
|
||||
</select>
|
@ -0,0 +1,41 @@
|
||||
select {
|
||||
font-family: sans-serif;
|
||||
margin: 0;
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25;
|
||||
height: inherit;
|
||||
width: 50%;
|
||||
-ms-touch-action: manipulation;
|
||||
touch-action: manipulation;
|
||||
text-transform: none;
|
||||
.custom-select {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
height: calc(2.25rem + 0.125rem);
|
||||
padding: .375rem 1.75rem .375rem .75rem;
|
||||
line-height: 1.25;
|
||||
vertical-align: middle;
|
||||
border-width: 0.0625rem;
|
||||
border-style: solid;
|
||||
border-radius: .25rem;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
.d-inline-block {
|
||||
display: inline-block !important;
|
||||
}
|
||||
}
|
||||
|
||||
optgroup {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* mounth and Year*/
|
||||
|
||||
ngb-datepicker-navigation-select.d-block {
|
||||
width: 9rem !important;
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { NgbDate } from './ngb-date';
|
||||
import { toInteger } from '../util/util';
|
||||
import { NgbDatepickerI18nNOA11Y } from './datepicker-i18n';
|
||||
import { NgbCalendarNOA11Y } from './ngb-calendar';
|
||||
|
||||
@Component({
|
||||
selector: 'ngb-fid-datepicker-navigation-select',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
templateUrl: './datepicker-navigation-select.html',
|
||||
styleUrls: ['./datepicker-navigation-select.scss'],
|
||||
|
||||
})
|
||||
export class NgbDatepickerNavigationSelectNOA11Y implements OnChanges {
|
||||
months: number[];
|
||||
years: number[] = [];
|
||||
|
||||
@Input() date: NgbDate;
|
||||
@Input() disabled: boolean;
|
||||
@Input() maxDate: NgbDate;
|
||||
@Input() minDate: NgbDate;
|
||||
|
||||
@Output() select = new EventEmitter<NgbDate>();
|
||||
|
||||
constructor(public i18n: NgbDatepickerI18nNOA11Y, private calendar: NgbCalendarNOA11Y) { this.months = calendar.getMonths(); }
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['maxDate'] || changes['minDate'] || changes['date']) {
|
||||
this._generateYears();
|
||||
this._generateMonths();
|
||||
}
|
||||
}
|
||||
|
||||
changeMonth(month: string) { this.select.emit(new NgbDate(this.date.year, toInteger(month), 1)); }
|
||||
|
||||
changeYear(year: string) { this.select.emit(new NgbDate(toInteger(year), this.date.month, 1)); }
|
||||
|
||||
private _generateMonths() {
|
||||
this.months = this.calendar.getMonths();
|
||||
|
||||
if (this.date && this.date.year === this.minDate.year) {
|
||||
const index = this.months.findIndex(month => month === this.minDate.month);
|
||||
this.months = this.months.slice(index);
|
||||
}
|
||||
|
||||
if (this.date && this.date.year === this.maxDate.year) {
|
||||
const index = this.months.findIndex(month => month === this.maxDate.month);
|
||||
this.months = this.months.slice(0, index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private _generateYears() {
|
||||
this.years = Array.from({ length: this.maxDate.year - this.minDate.year + 1 }, (e, i) => this.minDate.year + i);
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
<ng-template #retail>
|
||||
<div class="isp-datepicker-navigation">
|
||||
<span>
|
||||
<!-- Bottone mensile ad una freccia -->
|
||||
<button type='button' class='btn btn-sm btn-link camillo' (click)='!!doNavigate(navigation.PREV)'
|
||||
[disabled]='prevDisabled()' tabindex='-1'
|
||||
[attr.role]="'button'" [attr.aria-label]="' '">
|
||||
<span class='ngb-dp-navigation-chevron camillo'></span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<div class="header-navigation-date" (click)="setTemplate()">
|
||||
<ngb-fid-datepicker-navigation-select *ngIf='showSelect' class='d-block' [style.width.rem]='months * 9' [date]='date'
|
||||
[minDate]='minDate'
|
||||
[maxDate]='maxDate' [disabled]='disabled'
|
||||
(select)='selectDate($event)'></ngb-fid-datepicker-navigation-select>
|
||||
</div>
|
||||
|
||||
<span>
|
||||
<!-- Bottone mensile ad una freccia -->
|
||||
<button type='button' class='btn btn-sm btn-link camillo' (click)='!!doNavigate(navigation.NEXT)'
|
||||
[disabled]='nextDisabled()' tabindex='-1'
|
||||
[attr.role]="'button'" [attr.aria-label]="' '">
|
||||
<span class='ngb-dp-navigation-chevron right camillo'></span>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</ng-template>
|
||||
<ng-template #corporate>
|
||||
<div class="isp-datepicker-navigation">
|
||||
<span>
|
||||
<!-- Bottone mensile ad una freccia -->
|
||||
<button type='button' class='btn btn-sm btn-link camillo' (click)='!!doNavigate(navigation.PREV)'
|
||||
[disabled]='prevDisabled()' tabindex='-1'
|
||||
[attr.role]="'button'" [attr.aria-label]="' '">
|
||||
<span class='icomoon-Simboli_Risorsa-12 camillo'></span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<div class="header-navigation-date" (click)="setTemplate()">
|
||||
<ngb-fid-datepicker-navigation-select *ngIf='showSelect' class='d-block' [style.width.rem]='months * 9' [date]='date'
|
||||
[minDate]='minDate'
|
||||
[maxDate]='maxDate' [disabled]='disabled'
|
||||
(select)='selectDate($event)'></ngb-fid-datepicker-navigation-select>
|
||||
</div>
|
||||
|
||||
<span>
|
||||
<!-- Bottone mensile ad una freccia -->
|
||||
<button type='button' class='btn btn-sm btn-link camillo' (click)='!!doNavigate(navigation.NEXT)'
|
||||
[disabled]='nextDisabled()' tabindex='-1'
|
||||
[attr.role]="'button'" [attr.aria-label]="' '">
|
||||
<span class='icomoon-Simboli_Risorsa-13 right camillo'></span>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</ng-template>
|
||||
<ng-container [ngTemplateOutlet]="widgetTemplate"></ng-container>
|
@ -0,0 +1,108 @@
|
||||
:host(.isp-corporate-mode-wrapper) {
|
||||
.isp-datepicker-navigation {
|
||||
span button {
|
||||
&.btn-link {
|
||||
span.icomoon-Simboli_Risorsa-13, span.icomoon-Simboli_Risorsa-12 {
|
||||
&::before {
|
||||
border: none;
|
||||
transform: none;
|
||||
margin: 0;
|
||||
font-weight: bold!important;
|
||||
display: inline-block;
|
||||
height: 0.75rem;
|
||||
width: 0.75rem;
|
||||
}
|
||||
&.right {
|
||||
&::before {
|
||||
transform: none;
|
||||
display: inline-block;
|
||||
height: 0.75rem;
|
||||
width: 0.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.isp-datepicker-navigation {
|
||||
width: 100%;
|
||||
height: 3.125rem;
|
||||
line-height: 1.85rem;
|
||||
-webkit-box-pack: justify !important;
|
||||
-ms-flex-pack: justify !important;
|
||||
justify-content: space-between !important;
|
||||
display: -webkit-box !important;
|
||||
display: -ms-flexbox !important;
|
||||
display: flex !important;
|
||||
border-top-width: 0.0625rem;
|
||||
border-top-style: solid;
|
||||
span button {
|
||||
text-decoration: none;
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
margin: 0;
|
||||
text-transform: none;
|
||||
overflow: visible;
|
||||
-webkit-appearance: button;
|
||||
-ms-touch-action: manipulation;
|
||||
touch-action: manipulation;
|
||||
&.btn-link {
|
||||
width: 3.3125rem;
|
||||
min-height: 100% !important;
|
||||
cursor: pointer;
|
||||
border-style: solid;
|
||||
border-width: 0.0625rem !important;
|
||||
font-weight: 400;
|
||||
border-radius: 0;
|
||||
span.ngb-dp-navigation-chevron {
|
||||
&::before {
|
||||
border-style: solid;
|
||||
border-width: 0.125rem 0.125rem 0rem 0rem;
|
||||
content: '';
|
||||
display: inline-block;
|
||||
height: 0.75rem;
|
||||
transform: rotate(-135deg);
|
||||
-webkit-transform: rotate(-135deg);
|
||||
-ms-transform: rotate(-135deg);
|
||||
width: 0.75rem;
|
||||
margin: 0 0 0 0.5rem;
|
||||
}
|
||||
&.right {
|
||||
&::before {
|
||||
-webkit-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
margin: 0 0.5rem 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.camillo {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
border-left-width: 0.0625rem;
|
||||
border-left-style: solid;
|
||||
border-right-width: 0.0625rem;
|
||||
border-right-style: solid;
|
||||
}
|
||||
}
|
||||
.header-navigation-date {
|
||||
min-width: 8.3125rem;
|
||||
min-height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
table, caption, tbody, tfoot, thead, tr, th, td {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
font-size: 100%;
|
||||
vertical-align: baseline;
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, Injector } from '@angular/core';
|
||||
import { NavigationEvent } from './datepicker-view-model';
|
||||
import { NgbDate } from './ngb-date';
|
||||
import { NgbDatepickerI18nNOA11Y } from './datepicker-i18n';
|
||||
import { NgbCalendarNOA11Y } from './ngb-calendar';
|
||||
import { NgbDateStruct } from './ngb-date-struct';
|
||||
import { NbpBaseComponent } from '@isp/xdce-widget/base';
|
||||
import { CalendarItemNOA11Y } from './datepicker';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'ngb-fid-datepicker-navigation',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { 'class': 'd-flex justify-content-between', '[class.collapsed]': '!showSelect' },
|
||||
templateUrl: './datepicker-navigation.html',
|
||||
styleUrls: ['./datepicker-navigation.scss'],
|
||||
})
|
||||
export class NgbDatepickerNavigationNOA11Y extends NbpBaseComponent{
|
||||
navigation = NavigationEvent;
|
||||
|
||||
@Input() date: NgbDate;
|
||||
@Input() disabled: boolean;
|
||||
@Input() months: number;
|
||||
@Input() years: CalendarItemNOA11Y [][];
|
||||
@Input() showSelect: boolean;
|
||||
@Input() showWeekNumbers: boolean;
|
||||
@Input() template: number = 0;
|
||||
@Input() disabledWeekend: boolean;
|
||||
@Input() holidays: Array<NgbDateStruct>
|
||||
@Input() taxDeadlines: Array<NgbDateStruct>
|
||||
|
||||
@Output() navigate = new EventEmitter<NavigationEvent>();
|
||||
@Output() select = new EventEmitter<NgbDate>();
|
||||
@Output() newTemplate = new EventEmitter<number>();
|
||||
|
||||
_minDate: NgbDate;
|
||||
@Input()
|
||||
get minDate() {
|
||||
return this._minDate;
|
||||
}
|
||||
set minDate(minDate: NgbDate) {
|
||||
this._minDate = minDate;
|
||||
}
|
||||
|
||||
_maxDate: NgbDate;
|
||||
@Input()
|
||||
get maxDate() {
|
||||
return this._maxDate;
|
||||
}
|
||||
set maxDate(maxDate: NgbDate) {
|
||||
this._maxDate = maxDate;
|
||||
}
|
||||
|
||||
constructor(public i18n: NgbDatepickerI18nNOA11Y, private _calendar: NgbCalendarNOA11Y, private injector : Injector) {
|
||||
super(injector);
|
||||
}
|
||||
|
||||
doNavigate(event: NavigationEvent) {
|
||||
this.navigate.emit(event);
|
||||
}
|
||||
|
||||
nextDisabled() {
|
||||
let yearsSize = 0;
|
||||
this.years.forEach(row => yearsSize += row.length);
|
||||
return this.disabled || (this.maxDate && ((this.template == 0 && this._calendar.getNext(this.date, 'm').after(this.maxDate))
|
||||
|| (this.template == 1 && this.date.year + 1 > this.maxDate.year)
|
||||
|| (this.template == 2 && this.years[0][0].number + yearsSize > this.maxDate.year)));
|
||||
}
|
||||
|
||||
prevDisabled() {
|
||||
let prevMonthDate = new Date(this.date.year, this.date.month + 1, 0);
|
||||
let prevMonth = new NgbDate(prevMonthDate.getFullYear(), prevMonthDate.getMonth() - 1, prevMonthDate.getDate());
|
||||
return this.disabled || (this.minDate && ((this.template == 0 && prevMonth.before(this.minDate))
|
||||
|| (this.template == 1 && this.date.year - 1 < this.minDate.year)
|
||||
|| (this.template == 2 && this.years[0][0].number - 1 < this.minDate.year)));
|
||||
}
|
||||
|
||||
selectDate(date: NgbDate) {
|
||||
this.select.emit(date);
|
||||
}
|
||||
|
||||
setTemplate() {
|
||||
this.template = (this.template + 1) % 3;
|
||||
this.newTemplate.emit(this.template);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
<div [ngClass]=" abilitaMesi(mese) ? 'ngbdatepickerreplymonthview' : 'ngbdatepickerreplymonthviewdisabled disabledView'">
|
||||
<span [attr.role]="'button'" [attr.aria-label]="' '" [attr.aria.labelledby]="' '" [attr.aria-describedby]="' '">{{ mese.name | translate | slice: 0:3 | uppercase }}</span>
|
||||
</div>
|
@ -0,0 +1,20 @@
|
||||
div[ngbFidDatepickerReplyMonthView] {
|
||||
border-radius: 0 !important;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
min-width: 4.95rem !important;
|
||||
height: 2.8125rem !important;
|
||||
line-height: 2.8125rem !important;
|
||||
vertical-align: middle !important;
|
||||
border-right-width: 0.0625rem;
|
||||
border-right-style: solid;
|
||||
border-top-width: 0.0625rem;
|
||||
border-top-style: solid;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
.ngbdatepickerreplymonthviewdisabled {
|
||||
cursor: default;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit, OnChanges, SimpleChanges, OnDestroy } from '@angular/core';
|
||||
import { NgbMeseStruct } from './ngb-mese-struct';
|
||||
import { NgbYearStruct } from './ngb-year-struct';
|
||||
import { NgbDatepickerServiceNOA11Y } from './datepicker-service';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { DatepickerViewModel } from './datepicker-view-model';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: '[ngbFidDatepickerReplyMonthView]',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: {
|
||||
'class': 'btn-secondary-month',
|
||||
'[class.bg-primary]': 'selected',
|
||||
'[class.text-white]': 'selected',
|
||||
'[class.text-muted]': 'isMuted()',
|
||||
'[class.outside]': 'isMuted()',
|
||||
'[class.active]': 'focused',
|
||||
'[class.is-current]': 'isCurrent'
|
||||
},
|
||||
|
||||
templateUrl: './datepicker-reply-month-view.html',
|
||||
styleUrls: ['./datepicker-reply-month-view.scss'],
|
||||
|
||||
})
|
||||
export class NgbDatepickerReplyMonthViewNOA11Y implements OnInit, OnDestroy {
|
||||
|
||||
@Input() currentMonth: number;
|
||||
@Input() mese: NgbMeseStruct;
|
||||
@Input() year: number;
|
||||
@Input() disabled: boolean;
|
||||
@Input() focused: boolean;
|
||||
@Input() selected: boolean;
|
||||
|
||||
@Input() startDateEnabled: any;
|
||||
@Input() endDateEnabled: any;
|
||||
|
||||
isCurrent : boolean = false;
|
||||
|
||||
private _sub : Subscription;
|
||||
|
||||
ngOnDestroy(): void {
|
||||
// if(this._sub) {
|
||||
// this._sub.unsubscribe();
|
||||
// }
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
const now = new Date();
|
||||
// console.info('onInit month', this.mese.number, (now.getMonth()+1), this.year, now.getFullYear(), this.mese.number === (now.getMonth()+1), this.year === now.getFullYear());
|
||||
// console.info('onInit month', typeof (this.mese.number), typeof ((now.getMonth()+1)), typeof (this.year), typeof (now.getFullYear()), this.mese.number === (now.getMonth()+1), this.year === now.getFullYear());
|
||||
// console.info('onInit month selected', this.selected);
|
||||
this.isCurrent = this.mese.number === (now.getMonth()+1) && this.year === now.getFullYear();
|
||||
this.setSelected(this.service._model$.getValue());
|
||||
}
|
||||
|
||||
isMuted() { return false };
|
||||
|
||||
abilitaMesi(data) {
|
||||
|
||||
return (((this.startDateEnabled.year == this.year && this.startDateEnabled.month <= data.number) ||
|
||||
(data.number < this.startDateEnabled.month && this.startDateEnabled.year < this.year) ||
|
||||
(this.startDateEnabled.month <= data.number && this.startDateEnabled.year <= this.year))
|
||||
&& ((data.number <= this.endDateEnabled.month && this.year <= this.endDateEnabled.year) || (data.number > this.endDateEnabled.month && this.year < this.endDateEnabled.year)))
|
||||
|
||||
}
|
||||
|
||||
setSelected(model : DatepickerViewModel) {
|
||||
// console.info('selected:month', model, this.mese, this.year);
|
||||
if(model && model.selectedDate) {
|
||||
this.selected = (this.mese && this.mese.number === model.selectedDate.month) && this.year === model.selectedDate.year;
|
||||
return;
|
||||
}
|
||||
// console.info('selected:month no current, checking first');
|
||||
if(model && model.firstDate) {
|
||||
this.selected = (this.mese && this.mese.number === model.firstDate.month) && this.year === model.firstDate.year;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private service : NgbDatepickerServiceNOA11Y) {
|
||||
// this._sub = this.service.model$.subscribe(this.setSelected);
|
||||
}
|
||||
// isMuted() { return !this.selected && (this.mese.number !== this.currentMonth || this.disabled); }
|
||||
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
<div [ngClass]=" abilitaAnni(year) ? 'ngbDatepickerReplyYearsView' : 'ngbDatepickerReplyYearsViewdisabled disabledView'">
|
||||
<span [attr.role]="'button'" [attr.aria-label]="' '" [attr.aria.labelledby]="' '" [attr.aria-describedby]="' '">{{ year.name }}</span>
|
||||
</div>
|
@ -0,0 +1,19 @@
|
||||
div[ngbFidDatepickerReplyYearsView] {
|
||||
border-radius: 0 !important;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
min-width: 4.95rem !important;
|
||||
height: 2.8125rem !important;
|
||||
line-height: 2.8125rem !important;
|
||||
vertical-align: middle !important;
|
||||
border-right-width: 0.0625rem;
|
||||
border-right-style: solid;
|
||||
border-top-width: 0.0625rem;
|
||||
border-top-style: solid;
|
||||
border-collapse: collapse;
|
||||
border-spacing:0.0625rem;
|
||||
.ngbDatepickerReplyYearsViewdisabled {
|
||||
cursor: default;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit, OnDestroy } from '@angular/core';
|
||||
import { NgbYearStruct } from './ngb-year-struct';
|
||||
import { NgbDatepickerServiceNOA11Y } from './datepicker-service';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { DatepickerViewModel } from './datepicker-view-model';
|
||||
|
||||
@Component({
|
||||
selector: '[ngbFidDatepickerReplyYearsView]',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: {
|
||||
'class': 'btn-secondary-years',
|
||||
'[class.bg-primary]': 'selected',
|
||||
'[class.text-white]': 'selected',
|
||||
'[class.text-muted]': 'isMuted()',
|
||||
'[class.outside]': 'isMuted()',
|
||||
'[class.active]': 'focused',
|
||||
'[class.is-current]':'isCurrent'
|
||||
},
|
||||
|
||||
templateUrl: './datepicker-reply-years-view.html',
|
||||
styleUrls: ['./datepicker-reply-years-view.scss'],
|
||||
|
||||
})
|
||||
export class NgbDatepickerReplyYearsViewNOA11Y implements OnInit, OnDestroy {
|
||||
|
||||
@Input() currentMonth: number;
|
||||
@Input() year: NgbYearStruct;
|
||||
@Input() disabled: boolean;
|
||||
@Input() focused: boolean;
|
||||
@Input() selected: boolean;
|
||||
|
||||
@Input() startDateEnabled: any;
|
||||
@Input() endDateEnabled: any;
|
||||
isCurrent : boolean = false;
|
||||
|
||||
private _sub : Subscription;
|
||||
|
||||
isMuted() { return false };
|
||||
|
||||
ngOnInit(): void {
|
||||
const now = new Date();
|
||||
this.isCurrent = this.year.number === now.getFullYear();
|
||||
this.setSelected(this.service._model$.getValue());
|
||||
}
|
||||
|
||||
setSelected(model : DatepickerViewModel) {
|
||||
// console.info('selected:year', model, this.year);
|
||||
if(model && model.selectedDate) {
|
||||
this.selected = this.year && model.selectedDate.year === this.year.number;
|
||||
return;
|
||||
}
|
||||
// console.info('selected:year no current, checking first');
|
||||
if(model && model.firstDate) {
|
||||
this.selected = this.year && model.firstDate.year === this.year.number;
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
// if(this._sub) {
|
||||
// this._sub.unsubscribe();
|
||||
// }
|
||||
}
|
||||
|
||||
abilitaAnni(data) {
|
||||
|
||||
if(this.startDateEnabled.year <= data.number && data.number <= this.endDateEnabled.year){
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
constructor(private service : NgbDatepickerServiceNOA11Y) {
|
||||
// this._sub = this.service.model$.subscribe(this.setSelected);
|
||||
}
|
||||
// isMuted() { return !this.selected && (this.mese.number !== this.currentMonth || this.disabled); }
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
import { RplCalendarNOA11Y } from './datepicker';
|
||||
import { NgbDatepickerConfigNOA11Y } from './datepicker-config';
|
||||
import { NgbDatepickerDayViewNOA11Y } from './datepicker-day-view';
|
||||
import { NgbDatepickerI18nDefaultNOA11Y, NgbDatepickerI18nNOA11Y } from './datepicker-i18n';
|
||||
import { NgbInputDatepickerNOA11Y } from './datepicker-input';
|
||||
import { NgbDatepickerNavigationNOA11Y } from './datepicker-navigation';
|
||||
import { NgbDatepickerNavigationSelectNOA11Y } from './datepicker-navigation-select';
|
||||
import { NgbDatepickerReplyMonthViewNOA11Y } from './datepicker-reply-month-view';
|
||||
import { NgbDatepickerReplyYearsViewNOA11Y } from './datepicker-reply-years-view';
|
||||
import { NgbDatepickerRoutingViewNOA11Y } from './datepicker-routing-view';
|
||||
import { NgbCalendarGregorianNOA11Y, NgbCalendarNOA11Y } from './ngb-calendar';
|
||||
import { NgbDateISOParserFormatterNOA11Y, NgbDateParserFormatterNOA11Y } from './ngb-date-parser-formatter';
|
||||
|
||||
export * from './datepicker';
|
||||
export * from './datepicker-config';
|
||||
export * from './datepicker-day-template-context';
|
||||
export * from './datepicker-day-view';
|
||||
export * from './datepicker-i18n';
|
||||
export * from './datepicker-input';
|
||||
export * from './datepicker-keymap-service';
|
||||
export * from './datepicker-navigation';
|
||||
export * from './datepicker-navigation-select';
|
||||
export * from './datepicker-reply-month-view';
|
||||
export * from './datepicker-reply-years-view';
|
||||
export * from './datepicker-routing-view';
|
||||
export * from './datepicker-service';
|
||||
export * from './hijri/ngb-calendar-hijri';
|
||||
export * from './hijri/ngb-calendar-islamic-civil';
|
||||
export * from './ngb-calendar';
|
||||
export * from './ngb-date-parser-formatter';
|
||||
|
||||
|
||||
export const RplDeclarations = [
|
||||
RplCalendarNOA11Y,
|
||||
NgbDatepickerRoutingViewNOA11Y,
|
||||
NgbDatepickerNavigationNOA11Y,
|
||||
NgbDatepickerNavigationSelectNOA11Y,
|
||||
NgbDatepickerDayViewNOA11Y,
|
||||
NgbDatepickerReplyMonthViewNOA11Y,
|
||||
NgbDatepickerReplyYearsViewNOA11Y,
|
||||
NgbInputDatepickerNOA11Y
|
||||
];
|
||||
export const RplExports = [RplCalendarNOA11Y, NgbInputDatepickerNOA11Y];
|
||||
export const RplEntryComponents = [RplCalendarNOA11Y];
|
||||
export const RplRootProviders = [
|
||||
{ provide: NgbCalendarNOA11Y, useClass: NgbCalendarGregorianNOA11Y },
|
||||
{ provide: NgbDatepickerI18nNOA11Y, useClass: NgbDatepickerI18nDefaultNOA11Y },
|
||||
{ provide: NgbDateParserFormatterNOA11Y, useClass: NgbDateISOParserFormatterNOA11Y }, NgbDatepickerConfigNOA11Y
|
||||
];
|
@ -0,0 +1,102 @@
|
||||
<div class="isp-datepicker-routing-view" #ispDatepickerRoutingView>
|
||||
<div [ngSwitch]="currentTemplate">
|
||||
|
||||
<!-- giorni -->
|
||||
<div *ngSwitchCase=0>
|
||||
|
||||
<!-- mesi nell'header. -->
|
||||
<div *ngIf="showWeekdays" class="ngb-dp-week d-flex">
|
||||
<div *ngIf="showWeekNumbers" class="ngb-dp-weekday"></div>
|
||||
<div *ngFor="let w of month.weekdays" class="ngb-dp-weekday small text-center text-info font-italic" [attr.role]="'button'" [attr.aria-label]="' '">
|
||||
<span [attr.role]="'button'" [attr.aria-label]="' '" [attr.aria-labelledby]="' '">
|
||||
{{ i18n.getWeekdayShortName(w) | translate | slice: 0:3 }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template ngFor let-week [ngForOf]="month.weeks">
|
||||
<div *ngIf="!isCollapsed(week) && !isHiddenWeek(week)" class="ngb-dp-week d-flex">
|
||||
<div *ngIf="showWeekNumbers" class="ngb-dp-week-number small text-center font-italic text-muted">
|
||||
<span [attr.role]="'none'" [attr.aria-label]="' '">{{ week.number }}</span>
|
||||
</div>
|
||||
<div *ngFor="let day of week.days" (click)="doSelect(day, $event)" class="ngb-dp-day"
|
||||
[class.disabled]="day.context.disabled" [class.hidden]="isHidden(day)"
|
||||
[attr.role]="'none'"
|
||||
[attr.aria-label]="' '">
|
||||
|
||||
<ng-template [ngIf]="!isHidden(day)">
|
||||
|
||||
<div ngbFidDatepickerDayView
|
||||
[ngClass] = "{'cursor-pointer' : !disabledWeekend && !day.context.disabled}"
|
||||
[date]="day.context.date"
|
||||
[currentMonth]="day.context.currentMonth"
|
||||
[selected]="day.context.selected"
|
||||
[disabled]="day.context.disabled"
|
||||
[focused]="day.context.focused"
|
||||
[startDateEnabled]="startDateEnabled"
|
||||
[endDateEnabled]="endDateEnabled"
|
||||
[isToday]="day.context.isToday"
|
||||
[isWeekend]="day.context.isWeekend"
|
||||
[isHoliday]="day.context.isHoliday"
|
||||
[taxDeadlines]="taxDeadlines"
|
||||
[isFiscalDay]="day.context.isFiscalDay"
|
||||
[attr.role]="'none'"
|
||||
[attr.aria-label]="' '"
|
||||
[attr.aria-labelledby]="' '"
|
||||
[attr.aria-describedby]="' '">
|
||||
</div>
|
||||
|
||||
</ng-template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<!-- mesi -->
|
||||
<div *ngSwitchCase=1>
|
||||
<div *ngFor="let row of mesi" class="d-flex ngb-dp-mese">
|
||||
<ng-container *ngFor="let mese of row">
|
||||
|
||||
<div ngbFidDatepickerReplyMonthView [mese]="mese" [year]="dataTemplate.year" [selected]="mese.selected"
|
||||
[disabled]="mese.disabled"
|
||||
[focused]="mese.focused"
|
||||
[startDateEnabled]="startDateEnabled"
|
||||
[endDateEnabled]="endDateEnabled"
|
||||
[attr.role]="'none'"
|
||||
[attr.aria-label]="' '"
|
||||
[attr.aria-labelledby]="' '"
|
||||
[attr.aria-describedby]="' '"
|
||||
(click)="doSelectMonth(mese, $event)">
|
||||
</div>
|
||||
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- anni -->
|
||||
<div *ngSwitchCase=2>
|
||||
<div *ngFor="let row of years" class="d-flex ngb-dp-mese">
|
||||
<ng-container *ngFor="let year of row">
|
||||
|
||||
<div ngbFidDatepickerReplyYearsView [year]="year" [selected]="year.selected" [disabled]="year.disabled"
|
||||
[focused]="year.focused"
|
||||
[startDateEnabled]="startDateEnabled"
|
||||
[endDateEnabled]="endDateEnabled"
|
||||
[attr.role]="'none'"
|
||||
[attr.aria-label]="' '"
|
||||
[attr.aria-labelledby]="' '"
|
||||
[attr.aria-describedby]="' '"
|
||||
(click)="doSelectYear(year, $event)">
|
||||
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- default -->
|
||||
<div *ngSwitchDefault>errore template</div>
|
||||
|
||||
</div>
|
||||
<div><button name="today">Oggi</button><button name="clear">Cancella</button><button name="close">Chiudi</button></div>
|
||||
</div>
|
@ -0,0 +1,112 @@
|
||||
.isp-datepicker-routing-view {
|
||||
pointer-events: auto;
|
||||
.d-flex {
|
||||
display: -webkit-box !important;
|
||||
display: -ms-flexbox !important;
|
||||
display: flex !important;
|
||||
border-bottom-width: 0.0625rem;
|
||||
border-bottom-style: solid;
|
||||
border-right-width: 0.0625rem;
|
||||
border-right-style: solid;
|
||||
border-left-width: 0.0625rem;
|
||||
border-left-style: solid;
|
||||
padding: 0 0.0625rem;
|
||||
&:first-child:not(.ngb-dp-mese) {
|
||||
border-top-width: 0.0625rem;
|
||||
border-top-style: solid;
|
||||
}
|
||||
&.ngb-dp-week, &.ngb-dp-mese {
|
||||
|
||||
.ngb-dp-day {
|
||||
width: 2.6875rem !important;
|
||||
height: 2.5625rem !important;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
&.disabled, &.hidden {
|
||||
cursor: default;
|
||||
}
|
||||
&:not(:first-child) {
|
||||
border-left-width: 0.0625rem;
|
||||
border-left-style: solid;
|
||||
}
|
||||
.cursor-pointer {
|
||||
cursor : pointer !important
|
||||
}
|
||||
}
|
||||
.bg-primary {
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: -0.5rem;
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
.btn-secondary {
|
||||
height: inherit;
|
||||
font-size: .625rem !important;
|
||||
}
|
||||
.btn-secondary, .btn-secondary-month, .btn-secondary-years {
|
||||
font-weight: bold;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
div[ngbdatepickerreplymonthview], div[ngbdatepickerreplyyearsview]{
|
||||
&.btn-secondary-month, &.btn-secondary-years {
|
||||
border-radius: 0 !important;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
min-width: 4.95rem !important;
|
||||
height: 2.8125rem !important;
|
||||
line-height: 2.8125rem !important;
|
||||
vertical-align: middle !important;
|
||||
border-right-width: 0.0625rem;
|
||||
border-right-style: solid;
|
||||
border-top-width: 0.0625rem;
|
||||
border-top-style: solid;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
&:last-child {
|
||||
border-right-style: none;
|
||||
border-right-width: 0;
|
||||
}
|
||||
.ngbdatepickerreplymonthviewdisabled, .ngbDatepickerReplyYearsViewdisabled {
|
||||
cursor: default;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.d-flex:first-child & {
|
||||
border-top-width: 0;
|
||||
border-top-style: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.is-weekend, .is-daypast {
|
||||
cursor: default;
|
||||
}
|
||||
.ngb-dp-weekday, .ngb-dp-week-number {
|
||||
width: 14.28% !important;
|
||||
height: 2.375rem !important;
|
||||
line-height: 2.4375rem;
|
||||
&.small, & small {
|
||||
font-size: 80%;
|
||||
font-weight: 400;
|
||||
}
|
||||
&.text-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
&.font-italic {
|
||||
font-family: 'Arial Bold', 'Arial';
|
||||
font-weight: 700;
|
||||
font-style: normal !important;
|
||||
font-size: .875rem;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,254 @@
|
||||
import {
|
||||
Component, EventEmitter, Input, OnInit, Output,
|
||||
TemplateRef, ChangeDetectionStrategy, ChangeDetectorRef, SimpleChanges, OnChanges, OnDestroy, ViewChild, ElementRef
|
||||
} from '@angular/core';
|
||||
import {DayViewModel, MonthViewModel, WeekViewModel} from './datepicker-view-model';
|
||||
import {NgbDate} from './ngb-date';
|
||||
import {NgbDatepickerI18nNOA11Y} from './datepicker-i18n';
|
||||
import {DayTemplateContextNOA11Y} from './datepicker-day-template-context';
|
||||
import {NgbDataTemplateStruct} from './ngb-dataTemplate-struct';
|
||||
import { NgbDatepickerServiceNOA11Y } from './datepicker-service';
|
||||
import { CalendarItemNOA11Y } from './datepicker';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'ngb-fid-datepicker-routing-view',
|
||||
host: { 'class': 'd-block' },
|
||||
templateUrl: './datepicker-routing-view.html',
|
||||
styleUrls: ['./datepicker-routing-view.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class NgbDatepickerRoutingViewNOA11Y implements OnInit, OnChanges, OnDestroy {
|
||||
@Input() dayTemplate: TemplateRef<DayTemplateContextNOA11Y>;
|
||||
@Input() monthTemplate: TemplateRef<DayTemplateContextNOA11Y>;
|
||||
@Input() yearsTemplate: TemplateRef<DayTemplateContextNOA11Y>;
|
||||
@Input() currentTemplate: number;
|
||||
@Input() mesi: any;
|
||||
@Input() years: any;
|
||||
@Input() disabledWeekend : boolean;
|
||||
|
||||
@Input() date: any;
|
||||
@Input() dataTemplate: NgbDataTemplateStruct;
|
||||
|
||||
@Input() month: MonthViewModel;
|
||||
|
||||
@Input() outsideDays: 'visible' | 'hidden' | 'collapsed';
|
||||
@Input() showWeekdays;
|
||||
@Input() showWeekNumbers;
|
||||
|
||||
|
||||
@Input() startDateEnabled: any;
|
||||
@Input() endDateEnabled: any;
|
||||
|
||||
@Input() isToday: boolean;
|
||||
@Input() isWeekend: boolean;
|
||||
@Input() taxDeadlines: any;
|
||||
|
||||
|
||||
@Output() select = new EventEmitter<NgbDate>();
|
||||
@Output() changeTemplate = new EventEmitter<NgbDataTemplateStruct>();
|
||||
|
||||
@ViewChild("ispDatepickerRoutingView") routingView: ElementRef;
|
||||
|
||||
currentYear : number;
|
||||
currentMonth : number;
|
||||
currentDay : number;
|
||||
sub: Subscription;
|
||||
|
||||
constructor(public i18n: NgbDatepickerI18nNOA11Y, private cdr: ChangeDetectorRef, private service : NgbDatepickerServiceNOA11Y) {
|
||||
|
||||
}
|
||||
ngOnInit() {
|
||||
// alert("in select in routing : " + this.startDateEnabled)
|
||||
// alert("in select in routing : " + this.endDateEnabled)
|
||||
// this.currentYear = this.date && this.date.year;
|
||||
// this.currentMonth = this.date && this.date.month;
|
||||
// console.info('routing init', this.currentYear, this.currentMonth);
|
||||
this.dataTemplate.day = this.date && this.date.day;
|
||||
this.dataTemplate.month = this.date && this.date.month;
|
||||
this.dataTemplate.year = this.date && this.date.year;
|
||||
const model = this.service._model$.getValue();
|
||||
if(model && model.selectedDate) {
|
||||
this.currentDay = model.selectedDate.day;
|
||||
this.currentMonth = model.selectedDate.month;
|
||||
this.currentYear = model.selectedDate.year;
|
||||
}
|
||||
// this.sub = this.service.model$.subscribe((model) => {
|
||||
// if(model.selectedDate) {
|
||||
// this.currentDay = model.selectedDate.day;
|
||||
// this.currentMonth = model.selectedDate.month;
|
||||
// this.currentYear = model.selectedDate.year;
|
||||
// }
|
||||
// })
|
||||
// console.info('routing init', this.date, this.dataTemplate);
|
||||
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
// if (this.sub) {
|
||||
// this.sub.unsubscribe();
|
||||
// }
|
||||
}
|
||||
|
||||
ngOnChanges(changes : SimpleChanges) {
|
||||
if(changes.years) {
|
||||
this.years = [...changes.years.currentValue];
|
||||
}
|
||||
if(changes.currentTemplate || changes.dataTemplate) {
|
||||
this.resetMesi();
|
||||
this.resetAnni();
|
||||
const model = this.service._model$.getValue();
|
||||
if(model && model.selectedDate) {
|
||||
this.currentDay = model.selectedDate.day;
|
||||
this.currentMonth = model.selectedDate.month;
|
||||
this.currentYear = model.selectedDate.year;
|
||||
}
|
||||
}
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
doSelect(day: DayViewModel, $event : any) {
|
||||
|
||||
if (!this.abilitaGiorni(day.date)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.dataTemplate.valid) {
|
||||
// il day si prende quello selezionato e non quello del dataTemplate
|
||||
// day.date.day = this.dataTemplate.day;
|
||||
day.date.month = this.dataTemplate.month;
|
||||
day.date.year = this.dataTemplate.year;
|
||||
this.currentYear = day.date.year;
|
||||
this.currentMonth = day.date.month;
|
||||
this.currentDay = day.date.day;
|
||||
this.select.emit(NgbDate.from(day.date));
|
||||
} else {
|
||||
if (!day.context.disabled && !this.isHidden(day)) {
|
||||
this.currentYear = day.date.year;
|
||||
this.currentMonth = day.date.month;
|
||||
this.currentDay = day.date.day;
|
||||
this.select.emit(NgbDate.from(day.date));
|
||||
}
|
||||
}
|
||||
$event.stopPropagation();
|
||||
}
|
||||
|
||||
abilitaGiorni(data) {
|
||||
|
||||
let buffer = new Date(data.year, data.month - 1, data.day);
|
||||
|
||||
let startDate = new Date(this.startDateEnabled.year, this.startDateEnabled.month - 1, this.startDateEnabled.day);
|
||||
|
||||
let endDate = new Date(this.endDateEnabled.year, this.endDateEnabled.month - 1, this.endDateEnabled.day);
|
||||
|
||||
return (startDate <= buffer && buffer <= endDate);
|
||||
|
||||
}
|
||||
|
||||
abilitaMesi(data) {
|
||||
|
||||
return (((this.startDateEnabled.year == this.dataTemplate.year && this.startDateEnabled.month <= data.number) ||
|
||||
(data.number < this.startDateEnabled.month && this.startDateEnabled.year < this.dataTemplate.year) ||
|
||||
(this.startDateEnabled.month <= data.number && this.startDateEnabled.year <= this.dataTemplate.year))
|
||||
&& ((data.number <= this.endDateEnabled.month && this.dataTemplate.year <= this.endDateEnabled.year) || (data.number > this.endDateEnabled.month && this.dataTemplate.year < this.endDateEnabled.year)))
|
||||
|
||||
}
|
||||
|
||||
abilitaAnni(data) {
|
||||
|
||||
return (this.startDateEnabled.year <= data.number && data.number <= this.endDateEnabled.year);
|
||||
|
||||
}
|
||||
|
||||
doSelectMonth(mese: any, $event: any) {
|
||||
|
||||
if (!this.abilitaMesi(mese)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentTemplate = 0;
|
||||
this.dataTemplate.template = this.currentTemplate;
|
||||
|
||||
// reset giorni
|
||||
this.month.weeks.forEach((week) => {
|
||||
week.days.forEach((day) => {
|
||||
day.context.selected = day.date.day === this.currentDay && day.date.month === this.currentMonth && day.date.year === this.currentYear;
|
||||
})
|
||||
});
|
||||
this.resetMesi();
|
||||
|
||||
this.dataTemplate.month = mese.number;
|
||||
this.dataTemplate.valid = true;
|
||||
this.changeTemplate.emit(this.dataTemplate);
|
||||
$event.stopPropagation();
|
||||
}
|
||||
|
||||
doSelectYear(year: any, $event: any) {
|
||||
|
||||
if (!this.abilitaAnni(year)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentTemplate = 1;
|
||||
this.dataTemplate.template = this.currentTemplate;
|
||||
|
||||
// resetta mesi e anno
|
||||
this.resetMesi();
|
||||
|
||||
this.dataTemplate.year = year.number;
|
||||
this.dataTemplate.valid = true;
|
||||
this.changeTemplate.emit(this.dataTemplate);
|
||||
$event.stopPropagation();
|
||||
}
|
||||
|
||||
isCollapsed(week: WeekViewModel) {
|
||||
return this.outsideDays === 'collapsed' && week.days[0].date.month !== this.month.number &&
|
||||
week.days[week.days.length - 1].date.month !== this.month.number;
|
||||
}
|
||||
|
||||
isHiddenWeek(week: WeekViewModel) {
|
||||
let counter = 0;
|
||||
for(let i=0; i<week.days.length; i++) {
|
||||
if (this.isHidden(week.days[i])) {
|
||||
counter ++;
|
||||
}
|
||||
}
|
||||
return counter === 7;
|
||||
}
|
||||
|
||||
isHidden(day: DayViewModel) {
|
||||
return (this.outsideDays === 'hidden' || this.outsideDays === 'collapsed') && this.month.number !== day.date.month;
|
||||
}
|
||||
|
||||
getRoutingViewHeight() {
|
||||
return this.routingView.nativeElement.offsetHeight;
|
||||
}
|
||||
|
||||
getRoutingViewWidth() {
|
||||
return this.routingView.nativeElement.offsetWidth;
|
||||
}
|
||||
|
||||
private resetMesi(){
|
||||
let months : CalendarItemNOA11Y[][] = [];
|
||||
months = this.mesi.map((row) => {
|
||||
return row.map((m) => {
|
||||
const res = {...m};
|
||||
res.selected = res.number === this.currentMonth && this.dataTemplate.year === this.currentYear;
|
||||
return res;
|
||||
})
|
||||
});
|
||||
this.mesi = months;
|
||||
}
|
||||
|
||||
private resetAnni() {
|
||||
let yrs : CalendarItemNOA11Y[][] = [];
|
||||
yrs = this.years.map((row) => {
|
||||
return row.map((y) => {
|
||||
const res = {...y};
|
||||
res.selected = res.number === this.currentYear;
|
||||
return res;
|
||||
});
|
||||
});
|
||||
this.years = yrs;
|
||||
}
|
||||
}
|
@ -0,0 +1,273 @@
|
||||
import {NgbCalendarNOA11Y, NgbPeriodNOA11Y} from './ngb-calendar';
|
||||
import {NgbDate} from './ngb-date';
|
||||
import {DatepickerViewModel, NgbMarkDisabled} from './datepicker-view-model';
|
||||
import {Injectable} from '@angular/core';
|
||||
import {isInteger} from '../util/util';
|
||||
import {Subject, Observable, BehaviorSubject} from 'rxjs';
|
||||
import {buildMonths, checkDateInRange, checkMinBeforeMax, isChangedDate, isDateSelectable} from './datepicker-tools';
|
||||
|
||||
import {filter} from 'rxjs/operators';
|
||||
import { NgbDateStruct } from './ngb-date-struct';
|
||||
|
||||
@Injectable()
|
||||
export class NgbDatepickerServiceNOA11Y {
|
||||
|
||||
private _state: DatepickerViewModel =
|
||||
{disabled: false,
|
||||
displayMonths: 1,
|
||||
firstDayOfWeek: 1,
|
||||
focusVisible: false,
|
||||
months: [],
|
||||
selectedDate: null
|
||||
};
|
||||
|
||||
public _model$ = new BehaviorSubject<DatepickerViewModel>(this._state);
|
||||
|
||||
get model$() : Observable<DatepickerViewModel> { return this._model$.asObservable().pipe(filter(model => model.months.length > 0)); }
|
||||
|
||||
set disabled(disabled: boolean) {
|
||||
if (this._state.disabled !== disabled) {
|
||||
this._nextState({disabled: disabled});
|
||||
}
|
||||
}
|
||||
|
||||
set displayMonths(months: number) {
|
||||
if (isInteger(months) && months > 0 && this._state.displayMonths !== months) {
|
||||
this._nextState({displayMonths: months});
|
||||
}
|
||||
}
|
||||
|
||||
set firstDayOfWeek(firstDayOfWeek: number) {
|
||||
if (isInteger(firstDayOfWeek) && firstDayOfWeek >= 0 && this._state.firstDayOfWeek !== firstDayOfWeek) {
|
||||
this._nextState({firstDayOfWeek: firstDayOfWeek});
|
||||
}
|
||||
}
|
||||
|
||||
set focusVisible(focusVisible: boolean) {
|
||||
if (this._state.focusVisible !== focusVisible && !this._state.disabled) {
|
||||
this._nextState({focusVisible: focusVisible});
|
||||
}
|
||||
}
|
||||
|
||||
set maxDate(date: NgbDate) {
|
||||
if (date === undefined || this._calendar.isValid(date) && isChangedDate(this._state.maxDate, date)) {
|
||||
this._nextState({maxDate: date});
|
||||
}
|
||||
}
|
||||
|
||||
set markDisabled(markDisabled: NgbMarkDisabled) {
|
||||
if (this._state.markDisabled !== markDisabled) {
|
||||
this._nextState({markDisabled: markDisabled});
|
||||
}
|
||||
}
|
||||
|
||||
set minDate(date: NgbDate) {
|
||||
if (date === undefined || this._calendar.isValid(date) && isChangedDate(this._state.minDate, date)) {
|
||||
this._nextState({minDate: date});
|
||||
}
|
||||
}
|
||||
|
||||
set disabledWeekend(disabledWeekend: boolean) {
|
||||
if (this._state.disabledWeekend !== disabledWeekend) {
|
||||
this._nextState({disabledWeekend: disabledWeekend});
|
||||
}
|
||||
}
|
||||
|
||||
set holidays(holidays: Array<NgbDateStruct>) {
|
||||
if (this._state.holidays !== holidays) {
|
||||
this._nextState({holidays: holidays});
|
||||
}
|
||||
}
|
||||
|
||||
set taxDeadlines(taxDeadlines: Array<NgbDateStruct>) {
|
||||
if (this._state.taxDeadlines !== taxDeadlines) {
|
||||
this._nextState({taxDeadlines: taxDeadlines});
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private _calendar: NgbCalendarNOA11Y) {}
|
||||
|
||||
focus(date: NgbDate) {
|
||||
if (!this._state.disabled && this._calendar.isValid(date) && isChangedDate(this._state.focusDate, date)) {
|
||||
this._nextState({focusDate: date});
|
||||
}
|
||||
}
|
||||
|
||||
focusMove(period?: NgbPeriodNOA11Y, number?: number) {
|
||||
this.focus(this._calendar.getNext(this._state.focusDate, period, number));
|
||||
}
|
||||
|
||||
focusSelect() {
|
||||
if (isDateSelectable(this._state.months, this._state.focusDate)) {
|
||||
this.select(this._state.focusDate);
|
||||
}
|
||||
}
|
||||
|
||||
open(date: NgbDate) {
|
||||
if (!this._state.disabled && this._calendar.isValid(date)) {
|
||||
this._nextState({firstDate: date});
|
||||
}
|
||||
}
|
||||
|
||||
select(date: NgbDate) {
|
||||
const validDate = this.toValidDate(date, null);
|
||||
if (!this._state.disabled && isChangedDate(this._state.selectedDate, validDate)) {
|
||||
this._nextState({selectedDate: validDate});
|
||||
}
|
||||
}
|
||||
|
||||
toValidDate(date: {year: number, month: number, day?: number}, defaultValue?: NgbDate): NgbDate {
|
||||
const ngbDate = NgbDate.from(date);
|
||||
if (defaultValue === undefined) {
|
||||
defaultValue = this._calendar.getToday();
|
||||
}
|
||||
return this._calendar.isValid(ngbDate) ? ngbDate : defaultValue;
|
||||
}
|
||||
|
||||
private _nextState(patch: Partial<DatepickerViewModel>) {
|
||||
const newState = this._updateState(patch);
|
||||
this._patchContexts(newState);
|
||||
this._state = newState;
|
||||
this._model$.next(this._state);
|
||||
}
|
||||
|
||||
private _patchContexts(state: DatepickerViewModel) {
|
||||
state.months.forEach(month => {
|
||||
month.weeks.forEach(week => {
|
||||
week.days.forEach(day => {
|
||||
|
||||
// patch focus flag
|
||||
if (state.focusDate) {
|
||||
day.context.focused = state.focusDate.equals(day.date) && state.focusVisible;
|
||||
}
|
||||
|
||||
// override context disabled
|
||||
if (state.disabled === true) {
|
||||
day.context.disabled = true;
|
||||
}
|
||||
|
||||
// patch selection flag
|
||||
if (state.selectedDate !== undefined) {
|
||||
day.context.selected = state.selectedDate !== null && state.selectedDate.equals(day.date);
|
||||
}
|
||||
|
||||
// check if day is today
|
||||
if (day.date.year === new Date().getFullYear()
|
||||
&& day.date.month === new Date().getMonth() + 1
|
||||
&& day.date.day === new Date().getDate()) {
|
||||
day.context.isToday = true;
|
||||
} else {
|
||||
/* Se è un giorno del mese corrente ma passato rispetto ad oggi metto la classe default */
|
||||
if (day.date.year === new Date().getFullYear()
|
||||
&& day.date.month === new Date().getMonth() + 1
|
||||
&& day.date.day < new Date().getDate()) {
|
||||
day.context.isDayPast = true;
|
||||
}
|
||||
}
|
||||
|
||||
// check if day is a weekend day
|
||||
const otherday = new Date(day.date.year, day.date.month - 1, day.date.day);
|
||||
if (otherday.getDay() === 0 || otherday.getDay() === 6) {
|
||||
day.context.isWeekend = true;
|
||||
// disable weekend days if flag disableWeekend is set
|
||||
if(state.disabledWeekend) {
|
||||
day.context.disabled = true;
|
||||
}
|
||||
/* disabilito i giorni di weekend che non sono del mese visualizzato */
|
||||
if (day.date.month !== new Date().getMonth() + 1
|
||||
&& (this._state.focusVisible && day.date.month !== this._state.firstDate.month)) {
|
||||
day.context.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Disabilitazione del giorno nel caso in cui è un giorno di festa
|
||||
if(state.holidays){
|
||||
state.holidays.forEach((value, index) => {
|
||||
if (value.year === day.date.year &&
|
||||
value.month === day.date.month &&
|
||||
value.day === day.date.day) {
|
||||
day.context.disabled = true;
|
||||
day.context.isHoliday = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Controllo se al componente è stato passato un array contenente i giorni di scadenza fiscale
|
||||
if(state.taxDeadlines){
|
||||
state.taxDeadlines.forEach((value, index) => {
|
||||
if (value.year === day.date.year &&
|
||||
value.month === day.date.month &&
|
||||
value.day === day.date.day) {
|
||||
day.context.isFiscalDay = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private _updateState(patch: Partial<DatepickerViewModel>): DatepickerViewModel {
|
||||
// patching fields
|
||||
const state = Object.assign({}, this._state, patch);
|
||||
|
||||
let startDate = state.firstDate;
|
||||
|
||||
// min/max dates changed
|
||||
if ('minDate' in patch || 'maxDate' in patch) {
|
||||
checkMinBeforeMax(state.minDate, state.maxDate);
|
||||
state.focusDate = checkDateInRange(state.focusDate, state.minDate, state.maxDate);
|
||||
state.firstDate = checkDateInRange(state.firstDate, state.minDate, state.maxDate);
|
||||
startDate = state.focusDate;
|
||||
}
|
||||
|
||||
// disabled
|
||||
if ('disabled' in patch) {
|
||||
state.focusVisible = false;
|
||||
}
|
||||
|
||||
// focus date changed
|
||||
if ('focusDate' in patch) {
|
||||
state.focusDate = checkDateInRange(state.focusDate, state.minDate, state.maxDate);
|
||||
startDate = state.focusDate;
|
||||
|
||||
// nothing to rebuild if only focus changed and it is still visible
|
||||
if (state.months.length !== 0 && !state.focusDate.before(state.firstDate) &&
|
||||
!state.focusDate.after(state.lastDate)) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
// first date changed
|
||||
if ('firstDate' in patch) {
|
||||
state.firstDate = checkDateInRange(state.firstDate, state.minDate, state.maxDate);
|
||||
startDate = state.firstDate;
|
||||
}
|
||||
|
||||
// rebuilding months
|
||||
if (startDate) {
|
||||
const forceRebuild = 'firstDayOfWeek' in patch || 'markDisabled' in patch || 'minDate' in patch ||
|
||||
'maxDate' in patch || 'disabled' in patch;
|
||||
|
||||
const months = buildMonths(
|
||||
this._calendar, state.months, startDate, state.minDate, state.maxDate, state.displayMonths,
|
||||
state.firstDayOfWeek, state.markDisabled, forceRebuild);
|
||||
|
||||
// updating months and boundary dates
|
||||
state.months = months;
|
||||
state.firstDate = months.length > 0 ? months[0].firstDate : undefined;
|
||||
state.lastDate = months.length > 0 ? months[months.length - 1].lastDate : undefined;
|
||||
|
||||
// adjusting focus after months were built
|
||||
if ('firstDate' in patch) {
|
||||
if (state.focusDate === undefined || state.focusDate.before(state.firstDate) ||
|
||||
state.focusDate.after(state.lastDate)) {
|
||||
state.focusDate = startDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
import {NgbDate} from './ngb-date';
|
||||
import {DayViewModel, MonthViewModel, NgbMarkDisabled} from './datepicker-view-model';
|
||||
import {NgbCalendarNOA11Y} from './ngb-calendar';
|
||||
|
||||
export function isChangedDate(prev: NgbDate, next: NgbDate) {
|
||||
return !dateComparator(prev, next);
|
||||
}
|
||||
|
||||
export function dateComparator(prev: NgbDate, next: NgbDate) {
|
||||
return (!prev && !next) || (!!prev && !!next && prev.equals(next));
|
||||
}
|
||||
|
||||
export function checkMinBeforeMax(minDate: NgbDate, maxDate: NgbDate) {
|
||||
if (maxDate && minDate && maxDate.before(minDate)) {
|
||||
throw new Error(`'maxDate' ${maxDate} should be greater than 'minDate' ${minDate}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function checkDateInRange(date: NgbDate, minDate: NgbDate, maxDate: NgbDate): NgbDate {
|
||||
if (date && minDate && date.before(minDate)) {
|
||||
return NgbDate.from(minDate);
|
||||
}
|
||||
if (date && maxDate && date.after(maxDate)) {
|
||||
return NgbDate.from(maxDate);
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
export function isDateSelectable(months: MonthViewModel[], date: NgbDate) {
|
||||
let selectable = false;
|
||||
const month = months.find(curMonth => curMonth.year === date.year && curMonth.number === date.month);
|
||||
if (month) {
|
||||
month.weeks.find(week => {
|
||||
const day = week.days.find(day => date.equals(day.date));
|
||||
if (day && !day.context.disabled) {
|
||||
selectable = true;
|
||||
}
|
||||
return !!day;
|
||||
});
|
||||
}
|
||||
|
||||
return selectable;
|
||||
}
|
||||
|
||||
export function buildMonths(
|
||||
calendar: NgbCalendarNOA11Y, months: MonthViewModel[], date: NgbDate, minDate: NgbDate, maxDate: NgbDate,
|
||||
displayMonths: number, firstDayOfWeek: number, markDisabled: NgbMarkDisabled, force: boolean): MonthViewModel[] {
|
||||
const newMonths = [];
|
||||
for (let i = 0; i < displayMonths; i++) {
|
||||
const newDate = calendar.getNext(date, 'm', i);
|
||||
const index = months.findIndex(month => month.firstDate.equals(newDate));
|
||||
|
||||
if (force || index === -1) {
|
||||
newMonths.push(buildMonth(calendar, newDate, minDate, maxDate, firstDayOfWeek, markDisabled));
|
||||
} else {
|
||||
newMonths.push(months[index]);
|
||||
}
|
||||
}
|
||||
|
||||
return newMonths;
|
||||
}
|
||||
|
||||
export function buildMonth(
|
||||
calendar: NgbCalendarNOA11Y, date: NgbDate, minDate: NgbDate, maxDate: NgbDate, firstDayOfWeek: number,
|
||||
markDisabled: NgbMarkDisabled): MonthViewModel {
|
||||
const month:
|
||||
MonthViewModel = {firstDate: null, lastDate: null, number: date.month, year: date.year, weeks: [], weekdays: []};
|
||||
|
||||
date = getFirstViewDate(calendar, date, firstDayOfWeek);
|
||||
|
||||
// month has weeks
|
||||
for (let week = 0; week < calendar.getWeeksPerMonth(); week++) {
|
||||
const days: DayViewModel[] = [];
|
||||
|
||||
// week has days
|
||||
for (let day = 0; day < calendar.getDaysPerWeek(); day++) {
|
||||
if (week === 0) {
|
||||
month.weekdays.push(calendar.getWeekday(date));
|
||||
}
|
||||
|
||||
const newDate = new NgbDate(date.year, date.month, date.day);
|
||||
const nextDate = calendar.getNext(newDate);
|
||||
|
||||
// marking date as disabled
|
||||
let disabled = !!((minDate && newDate.before(minDate)) || (maxDate && newDate.after(maxDate)));
|
||||
if (!disabled && markDisabled) {
|
||||
disabled = markDisabled(newDate, {month: month.number, year: month.year});
|
||||
}
|
||||
|
||||
// saving first date of the month
|
||||
if (month.firstDate === null && newDate.month === month.number) {
|
||||
month.firstDate = newDate;
|
||||
}
|
||||
|
||||
// saving last date of the month
|
||||
if (newDate.month === month.number && nextDate.month !== month.number) {
|
||||
month.lastDate = newDate;
|
||||
}
|
||||
|
||||
days.push({
|
||||
date: newDate,
|
||||
context: {
|
||||
date: {year: newDate.year, month: newDate.month, day: newDate.day},
|
||||
currentMonth: month.number,
|
||||
disabled: disabled,
|
||||
focused: false,
|
||||
selected: false,
|
||||
isToday: false,
|
||||
isWeekend: false,
|
||||
isDayPast: false,
|
||||
isFiscalDay: false
|
||||
}
|
||||
});
|
||||
|
||||
date = nextDate;
|
||||
}
|
||||
|
||||
month.weeks.push(
|
||||
{number: calendar.getWeekNumber(days.map(day => NgbDate.from(day.date)), firstDayOfWeek), days: days});
|
||||
}
|
||||
|
||||
return month;
|
||||
}
|
||||
|
||||
export function getFirstViewDate(calendar: NgbCalendarNOA11Y, date: NgbDate, firstDayOfWeek: number): NgbDate {
|
||||
const currentMonth = date.month;
|
||||
let today = new NgbDate(date.year, date.month, date.day);
|
||||
let yesterday = calendar.getPrev(today);
|
||||
|
||||
const firstDayOfCurrentMonthIsAlsoFirstDayOfWeek =
|
||||
() => { return today.month !== yesterday.month && firstDayOfWeek === calendar.getWeekday(today); };
|
||||
|
||||
const reachedTheFirstDayOfTheLastWeekOfPreviousMonth =
|
||||
() => { return today.month !== currentMonth && firstDayOfWeek === calendar.getWeekday(today); };
|
||||
|
||||
// going back in time
|
||||
while (!reachedTheFirstDayOfTheLastWeekOfPreviousMonth() && !firstDayOfCurrentMonthIsAlsoFirstDayOfWeek()) {
|
||||
today = new NgbDate(yesterday.year, yesterday.month, yesterday.day);
|
||||
yesterday = calendar.getPrev(yesterday);
|
||||
}
|
||||
|
||||
return today;
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
import {NgbDate} from './ngb-date';
|
||||
import {NgbDateStruct} from './ngb-date-struct';
|
||||
import {DayTemplateContextNOA11Y} from './datepicker-day-template-context';
|
||||
|
||||
export type NgbMarkDisabled = (date: NgbDateStruct, current: {year: number, month: number}) => boolean;
|
||||
|
||||
export type DayViewModel = {
|
||||
date: NgbDate,
|
||||
context: DayTemplateContextNOA11Y
|
||||
}
|
||||
|
||||
export type WeekViewModel = {
|
||||
number: number,
|
||||
days: DayViewModel[]
|
||||
}
|
||||
|
||||
export type MonthViewModel = {
|
||||
firstDate: NgbDate,
|
||||
lastDate: NgbDate,
|
||||
number: number,
|
||||
year: number,
|
||||
weeks: WeekViewModel[],
|
||||
weekdays: number[]
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
export type DatepickerViewModel = {
|
||||
disabled: boolean,
|
||||
displayMonths: number,
|
||||
firstDate?: NgbDate,
|
||||
firstDayOfWeek: number,
|
||||
focusDate?: NgbDate,
|
||||
focusVisible: boolean,
|
||||
lastDate?: NgbDate,
|
||||
markDisabled?: NgbMarkDisabled,
|
||||
maxDate?: NgbDate,
|
||||
minDate?: NgbDate,
|
||||
months: MonthViewModel[],
|
||||
selectedDate: NgbDate,
|
||||
disabledWeekend?: boolean,
|
||||
holidays?: NgbDateStruct[],
|
||||
taxDeadlines?: NgbDateStruct[]
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
export enum NavigationEvent {
|
||||
PREV,
|
||||
NEXT,
|
||||
PREVYEAR,
|
||||
NEXTYEAR,
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
<!-- intestazione -->
|
||||
<div class="isp-main-datepicker d-none">
|
||||
<div class="ngb-dp-header bg-faded pt-1 rounded-top" [style.height.rem]="getHeaderHeight()"
|
||||
[style.marginBottom.rem]="-getHeaderMargin()">
|
||||
<!-- componente per la navigazione! Seleziona il template -->
|
||||
<ngb-fid-datepicker-navigation *ngIf="navigation !== 'none'"
|
||||
[date]="model.firstDate"
|
||||
[minDate]="model.minDate"
|
||||
[maxDate]="model.maxDate"
|
||||
[months]="model.months.length"
|
||||
[years]="years"
|
||||
[template]="template"
|
||||
[disabled]="model.disabled"
|
||||
[showWeekNumbers]="showWeekNumbers"
|
||||
[showSelect]="navigation === 'select'"
|
||||
[disabledWeekend]="model.disabledWeekend"
|
||||
[holidays]="model.holidays"
|
||||
[taxDeadlines]="model.taxDeadlines"
|
||||
(navigate)="onNavigateEvent($event)"
|
||||
(select)="onNavigateDateSelect($event)"
|
||||
(newTemplate)="setNewTemplate($event)"
|
||||
[attr.role]="'none'"
|
||||
[attr.label]="' '"
|
||||
[attr.labelledby]="' '"
|
||||
[attr.describedby]="' '">
|
||||
</ngb-fid-datepicker-navigation>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- corpo componente -->
|
||||
<div class="ngb-dp-months d-flex px-1 pb-1">
|
||||
<ng-template ngFor let-month [ngForOf]="model.months" let-i="index">
|
||||
<div class="ngb-dp-month d-block ml-3">
|
||||
|
||||
<div *ngIf="navigation !== 'select' || displayMonths > 1" style="min-width:150px"
|
||||
class="ngb-dp-month-name text-center" (click)="setNewTemplate((template+1)%3);$event.stopPropagation();">
|
||||
|
||||
<div [ngSwitch]="template" style="margin-top:1px">
|
||||
<div *ngSwitchCase=0 >
|
||||
{{ i18n.getMonthFullName(dataTemplate.month) | translate }} {{ dataTemplate.year }}
|
||||
</div>
|
||||
<div *ngSwitchCase=1>
|
||||
{{ dataTemplate.year }}
|
||||
</div>
|
||||
<div *ngSwitchCase=2>
|
||||
{{ dataTemplate.year }} - {{ dataTemplate.year + 11 }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- componente routing che usa il template selezionato-->
|
||||
<ngb-fid-datepicker-routing-view
|
||||
[mesi]="mesi"
|
||||
[years]="years"
|
||||
[disabledWeekend]="disabledWeekend"
|
||||
[dataTemplate]="dataTemplate"
|
||||
[date]="model.firstDate"
|
||||
[currentTemplate]="template"
|
||||
[month]="month"
|
||||
[showWeekdays]="showWeekdays"
|
||||
[showWeekNumbers]="showWeekNumbers"
|
||||
[startDateEnabled]="startDateEnabled"
|
||||
[endDateEnabled]="endDateEnabled"
|
||||
[outsideDays]="(displayMonths === 1 ? outsideDays : 'hidden')"
|
||||
[taxDeadlines]="taxDeadlines"
|
||||
(select)="onDateSelect($event)"
|
||||
(changeTemplate)="onChangeTemplate($event)"
|
||||
[attr.role]="'none'"
|
||||
[attr.label]="' '"
|
||||
[attr.labelledby]="' '"
|
||||
[attr.describedby]="' '">
|
||||
</ngb-fid-datepicker-routing-view>
|
||||
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,201 @@
|
||||
:host(.isp-corporate-mode-wrapper) {
|
||||
&.dropdown-menu {
|
||||
margin-top: 0;
|
||||
}
|
||||
.isp-main-datepicker{
|
||||
.ngb-dp-header {
|
||||
height: 2.1875rem!important;
|
||||
margin-bottom: 0 !important;
|
||||
& ::ng-deep .isp-datepicker-navigation {
|
||||
height: 2.1875rem !important;
|
||||
border-top-left-radius: 0.125rem;
|
||||
border-top-right-radius: 0.125rem;
|
||||
span {
|
||||
button.btn-link {
|
||||
width: 2.1875rem;
|
||||
height: 2.1875rem;
|
||||
font-size: 0.9375rem;
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.ngb-dp-months {
|
||||
.ngb-dp-month {
|
||||
.ngb-dp-month-name {
|
||||
height: 2.1875rem !important;
|
||||
margin-top: -2.1875rem !important;
|
||||
top: auto;
|
||||
line-height: 0.875rem !important;
|
||||
font-size: 0.75rem !important;
|
||||
}
|
||||
& ::ng-deep .isp-datepicker-routing-view {
|
||||
.d-flex {
|
||||
border-bottom-style: none;
|
||||
border-bottom-width: initial;
|
||||
&:last-child{
|
||||
border-bottom-width: 0.0625rem;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-left-radius: 0.125rem;
|
||||
border-bottom-right-radius: 0.125rem;
|
||||
}
|
||||
&.ngb-dp-mese:first-child {
|
||||
border-top-width: 0.0625rem;
|
||||
border-top-style: solid;
|
||||
}
|
||||
&.ngb-dp-week, &.ngb-dp-mese {
|
||||
.ngb-dp-week-number {
|
||||
height: inherit !important;
|
||||
line-height: inherit;
|
||||
width: 2.125rem !important;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
.ngb-dp-weekday {
|
||||
height: inherit !important;
|
||||
line-height: 1.3125rem;
|
||||
width: 2.125rem !important;
|
||||
font-size: 0.625rem;
|
||||
}
|
||||
.ngb-dp-day {
|
||||
width: 2.125rem !important;
|
||||
height: 2.125rem !important;
|
||||
font-size: 0.75rem;
|
||||
&:not(:first-child) {
|
||||
border-left: none;
|
||||
}
|
||||
.bg-primary, .btn-secondary {
|
||||
font-size: 0.75rem;
|
||||
.ngbdatepickerdayview, .ngbdatepickerdayviewdisabled {
|
||||
line-height: 2.125rem !important;
|
||||
}
|
||||
.ngbdatepickerreplymonthview {
|
||||
cursor: pointer;
|
||||
}
|
||||
.ngbdatepickerdayviewdisabled, .ngbdatepickerreplymonthviewdisabled {
|
||||
cursor: default;
|
||||
}
|
||||
.ngbDatepickerReplyYearsView {
|
||||
cursor: pointer;
|
||||
}
|
||||
.ngbDatepickerReplyYearsView[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
.ngbDatepickerReplyYearsViewdisabled {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
.is-weekend, .is-daypast, .text-muted {
|
||||
.ngbdatepickerdayview{
|
||||
opacity: .5;
|
||||
}
|
||||
}
|
||||
}
|
||||
div[ngbdatepickerreplymonthview], div[ngbdatepickerreplyyearsview]{
|
||||
&.btn-secondary-month, &.btn-secondary-years {
|
||||
min-width: 0rem !important;
|
||||
width: 3.75rem !important;
|
||||
height: 2.125rem !important;
|
||||
line-height: 2.125rem !important;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
font-size: 0.75rem;
|
||||
.ngbdatepickerdayview, .ngbdatepickerreplymonthview {
|
||||
cursor: pointer;
|
||||
}
|
||||
.ngbdatepickerdayviewdisabled, .ngbdatepickerreplymonthviewdisabled {
|
||||
cursor: default;
|
||||
}
|
||||
.ngbDatepickerReplyYearsView {
|
||||
cursor: pointer;
|
||||
}
|
||||
.ngbDatepickerReplyYearsView[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
.ngbDatepickerReplyYearsViewdisabled {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.isp-main-datepicker {
|
||||
.justify-content-between {
|
||||
-webkit-box-pack: justify !important;
|
||||
-ms-flex-pack: justify !important;
|
||||
justify-content: space-between !important;
|
||||
}
|
||||
.d-flex {
|
||||
display: -webkit-box !important;
|
||||
display: -ms-flexbox !important;
|
||||
display: flex !important;
|
||||
height: 3.125rem !important;
|
||||
line-height: 1.875rem !important;
|
||||
}
|
||||
.collapsed {
|
||||
margin-bottom: -2rem;
|
||||
}
|
||||
.ngb-dp-header {
|
||||
height: 4.625rem !important;
|
||||
margin-bottom: -1.5rem !important;
|
||||
border-bottom: none !important;
|
||||
&.pt-1 {
|
||||
padding-top: 0 !important;
|
||||
height: 4.25rem;
|
||||
margin-bottom: -2rem;
|
||||
}
|
||||
&.rounded-top {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
}
|
||||
.ngb-dp-months {
|
||||
&.pb-1 {
|
||||
padding: 0 !important;
|
||||
}
|
||||
&.px-1 {
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
.ngb-dp-month {
|
||||
pointer-events: none;
|
||||
&:first-child {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
&.ml-3 {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
&.d-block {
|
||||
display: block !important;
|
||||
}
|
||||
.ngb-dp-month-name {
|
||||
font-family: 'Arial', sans-serif;
|
||||
font-size: 1rem !important;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
position: absolute;
|
||||
text-align: center !important;
|
||||
top: 0;
|
||||
height: 3.125rem !important;
|
||||
line-height: 1.42857143rem !important;
|
||||
word-wrap: break-word;
|
||||
word-break: break-word;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display:flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,599 @@
|
||||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
Input,
|
||||
OnChanges,
|
||||
TemplateRef,
|
||||
forwardRef,
|
||||
OnInit,
|
||||
SimpleChanges,
|
||||
EventEmitter,
|
||||
Output,
|
||||
OnDestroy,
|
||||
ElementRef, ViewChild, ViewChildren
|
||||
} from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
|
||||
import { NgbCalendarNOA11Y } from './ngb-calendar';
|
||||
import { NgbDate } from './ngb-date';
|
||||
import { NgbDatepickerServiceNOA11Y } from './datepicker-service';
|
||||
import { NgbDatepickerKeyMapServiceNOA11Y } from './datepicker-keymap-service';
|
||||
import { DatepickerViewModel, NavigationEvent } from './datepicker-view-model';
|
||||
import { toInteger } from '../util/util';
|
||||
import { DayTemplateContextNOA11Y } from './datepicker-day-template-context';
|
||||
import { NgbDatepickerConfigNOA11Y } from './datepicker-config';
|
||||
import { NgbDateStruct } from './ngb-date-struct';
|
||||
import { NgbDatepickerI18nNOA11Y } from './datepicker-i18n';
|
||||
import { isChangedDate } from './datepicker-tools';
|
||||
import { NgbDataTemplateStruct } from './ngb-dataTemplate-struct';
|
||||
import { EnabledRangeService } from '../../nbp-enabled-range.service';
|
||||
import {NgbDatepickerRoutingViewNOA11Y} from "./datepicker-routing-view";
|
||||
|
||||
const NGB_CALENDAR_VALUE_ACCESSOR = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => RplCalendarNOA11Y),
|
||||
multi: true
|
||||
};
|
||||
|
||||
/**
|
||||
* The payload of the datepicker navigation event
|
||||
*/
|
||||
export interface RplCalendarNavigateEventNOA11Y {
|
||||
/**
|
||||
* Currently displayed month
|
||||
*/
|
||||
current: { year: number, month: number };
|
||||
|
||||
/**
|
||||
* Month we're navigating to
|
||||
*/
|
||||
next: { year: number, month: number };
|
||||
}
|
||||
|
||||
export class CalendarItemNOA11Y {
|
||||
name: string;
|
||||
number: number;
|
||||
focused: boolean;
|
||||
disabled: boolean;
|
||||
selected: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* A lightweight and highly configurable datepicker directive
|
||||
*/
|
||||
@Component({
|
||||
exportAs: 'rplCalendarNOA11Y',
|
||||
selector: 'rpl-calendar-noa11y',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: {
|
||||
'class': 'd-inline-block rounded',
|
||||
'tabindex': '0',
|
||||
'[attr.tabindex]': 'model.disabled ? undefined : "0"',
|
||||
'(blur)': 'showFocus(false)',
|
||||
'(focus)': 'showFocus(true)',
|
||||
'(keydown)': 'onKeyDown($event)'
|
||||
},
|
||||
|
||||
templateUrl: './datepicker.html',
|
||||
styleUrls: ['./datepicker.scss'],
|
||||
providers: [NGB_CALENDAR_VALUE_ACCESSOR, NgbDatepickerServiceNOA11Y, NgbDatepickerKeyMapServiceNOA11Y]
|
||||
})
|
||||
export class RplCalendarNOA11Y implements OnDestroy,
|
||||
OnChanges, OnInit, ControlValueAccessor {
|
||||
model: DatepickerViewModel;
|
||||
|
||||
@ViewChild(forwardRef(() => NgbDatepickerRoutingViewNOA11Y)) datepickerRoutingView: NgbDatepickerRoutingViewNOA11Y;
|
||||
@ViewChild(forwardRef(() => NgbDatepickerRoutingViewNOA11Y)) datepickerHeader: NgbDatepickerRoutingViewNOA11Y;
|
||||
|
||||
private _subscription: Subscription;
|
||||
/**
|
||||
* Reference for the custom template for the day display
|
||||
*/
|
||||
@Input() dayTemplate: TemplateRef<DayTemplateContextNOA11Y>;
|
||||
|
||||
/**
|
||||
* Number of months to display
|
||||
*/
|
||||
@Input() displayMonths: number;
|
||||
|
||||
/**
|
||||
* First day of the week. With default calendar we use ISO 8601: 'weekday' is 1=Mon ... 7=Sun
|
||||
*/
|
||||
@Input() firstDayOfWeek: number;
|
||||
|
||||
/**
|
||||
* Callback to mark a given date as disabled.
|
||||
* 'Current' contains the month that will be displayed in the view
|
||||
*/
|
||||
@Input() markDisabled: (date: NgbDateStruct, current: { year: number, month: number }) => boolean;
|
||||
|
||||
/**
|
||||
* Min date for the navigation. If not provided will be 10 years before today or `startDate`
|
||||
*/
|
||||
_minDate: NgbDateStruct;
|
||||
@Input()
|
||||
get minDate() {
|
||||
return this._minDate;
|
||||
}
|
||||
set minDate(minDate: NgbDateStruct) {
|
||||
this._minDate = minDate;
|
||||
this.startDateEnabled = minDate
|
||||
}
|
||||
|
||||
/**
|
||||
* Max date for the navigation. If not provided will be 10 years from today or `startDate`
|
||||
*/
|
||||
_maxDate: NgbDateStruct;
|
||||
@Input()
|
||||
get maxDate() {
|
||||
return this._maxDate;
|
||||
}
|
||||
set maxDate(maxDate: NgbDateStruct) {
|
||||
this._maxDate = maxDate;
|
||||
this.endDateEnabled = maxDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigation type: `select` (default with select boxes for month and year), `arrows`
|
||||
* (without select boxes, only navigation arrows) or `none` (no navigation at all)
|
||||
*/
|
||||
@Input() navigation: 'select' | 'arrows' | 'none';
|
||||
|
||||
/**
|
||||
* The way to display days that don't belong to current month: `visible` (default),
|
||||
* `hidden` (not displayed) or `collapsed` (not displayed with empty space collapsed)
|
||||
*/
|
||||
@Input() outsideDays: 'visible' | 'collapsed' | 'hidden';
|
||||
|
||||
/**
|
||||
* Whether to display days of the week
|
||||
*/
|
||||
@Input() showWeekdays: boolean;
|
||||
|
||||
/**
|
||||
* Whether to display week numbers
|
||||
*/
|
||||
@Input() showWeekNumbers: boolean;
|
||||
|
||||
/**
|
||||
* Date to open calendar with.
|
||||
* With default calendar we use ISO 8601: 'month' is 1=Jan ... 12=Dec.
|
||||
* If nothing or invalid date provided, calendar will open with current month.
|
||||
* Use 'navigateTo(date)' as an alternative
|
||||
*/
|
||||
@Input() startDate: { year: number, month: number, day?: number };
|
||||
|
||||
@Input() startDateEnabled: any;
|
||||
@Input() endDateEnabled: any;
|
||||
|
||||
@Input() disabledWeekend: boolean;
|
||||
@Input() holidays: Array<NgbDateStruct>;
|
||||
@Input() taxDeadlines: Array<NgbDateStruct>;
|
||||
|
||||
// /**
|
||||
// * Start date Enabled
|
||||
// */
|
||||
// @Input() startDateEnabled: { year: number, month: number, day: number };
|
||||
|
||||
// /**
|
||||
// * End date Enabled
|
||||
// */
|
||||
// @Input() endDateEnabled: { year: number, month: number, day: number };
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* In questa variabile sono memorizzati i dati iniziali che scenderanno l'albero dei template
|
||||
*/
|
||||
dataTemplate: NgbDataTemplateStruct = { template: 0, day: 0, month: 0, year: 0, valid: false };
|
||||
|
||||
/**
|
||||
* An event fired when navigation happens and currently displayed month changes.
|
||||
* See NgbDatepickerNavigateEvent for the payload info.
|
||||
*/
|
||||
@Output() navigate = new EventEmitter<NgbDatepickerNavigateEventNOA11Y>();
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Template da Adoperare
|
||||
*/
|
||||
template: number = 0;
|
||||
|
||||
|
||||
mesi : CalendarItemNOA11Y[][] = [
|
||||
[
|
||||
{ name: "JAN", number: 1, disabled: false, selected: false, focused: false },
|
||||
{ name: "FEB", number: 2, disabled: false, selected: false, focused: false },
|
||||
{ name: "MAR", number: 3, disabled: false, selected: false, focused: false },
|
||||
{ name: "APR", number: 4, disabled: false, selected: false, focused: false }
|
||||
],
|
||||
[
|
||||
{ name: "MAY", number: 5, disabled: false, selected: false, focused: false },
|
||||
{ name: "JUN", number: 6, disabled: false, selected: false, focused: false },
|
||||
{ name: "JUL", number: 7, disabled: false, selected: false, focused: false },
|
||||
{ name: "AUG", number: 8, disabled: false, selected: false, focused: false }
|
||||
],
|
||||
[
|
||||
{ name: "SEP", number: 9, disabled: false, selected: false, focused: false },
|
||||
{ name: "OCT", number: 10, disabled: false, selected: false, focused: false },
|
||||
{ name: "NOV", number: 11, disabled: false, selected: false, focused: false },
|
||||
{ name: "DEC", number: 12, disabled: false, selected: false, focused: false }
|
||||
]
|
||||
]
|
||||
|
||||
years : CalendarItemNOA11Y [][] = [
|
||||
[
|
||||
{ name: "2018", number: 2018, disabled: false, selected: false, focused: false },
|
||||
{ name: "2019", number: 2019, disabled: false, selected: false, focused: false },
|
||||
{ name: "2020", number: 2020, disabled: false, selected: false, focused: false },
|
||||
{ name: "2021", number: 2021, disabled: false, selected: false, focused: false }
|
||||
],
|
||||
[
|
||||
{ name: "2022", number: 2022, disabled: false, selected: false, focused: false },
|
||||
{ name: "2023", number: 2023, disabled: false, selected: false, focused: false },
|
||||
{ name: "2024", number: 2024, disabled: false, selected: false, focused: false },
|
||||
{ name: "2025", number: 2025, disabled: false, selected: false, focused: false }
|
||||
],
|
||||
[
|
||||
{ name: "2026", number: 2026, disabled: false, selected: false, focused: false },
|
||||
{ name: "2027", number: 2027, disabled: false, selected: false, focused: false },
|
||||
{ name: "2028", number: 2028, disabled: false, selected: false, focused: false },
|
||||
{ name: "2029", number: 2029, disabled: false, selected: false, focused: false }
|
||||
]
|
||||
]
|
||||
|
||||
onChange = (_: any) => { };
|
||||
onTouched = () => { };
|
||||
// startDateEnabled: string;
|
||||
// endDateEnabled: string;
|
||||
|
||||
constructor(
|
||||
private enabledRange: EnabledRangeService,
|
||||
|
||||
private _keyMapService: NgbDatepickerKeyMapServiceNOA11Y,
|
||||
public _service: NgbDatepickerServiceNOA11Y,
|
||||
private _calendar: NgbCalendarNOA11Y,
|
||||
public i18n: NgbDatepickerI18nNOA11Y, config: NgbDatepickerConfigNOA11Y,
|
||||
private _cd: ChangeDetectorRef,
|
||||
private _elementRef: ElementRef) {
|
||||
this.dayTemplate = config.dayTemplate;
|
||||
this.displayMonths = config.displayMonths;
|
||||
this.firstDayOfWeek = config.firstDayOfWeek;
|
||||
this.markDisabled = config.markDisabled;
|
||||
this.minDate = config.minDate;
|
||||
this.maxDate = config.maxDate;
|
||||
this.navigation = config.navigation;
|
||||
this.showWeekdays = config.showWeekdays;
|
||||
this.showWeekNumbers = config.showWeekNumbers;
|
||||
this.startDate = config.startDate;
|
||||
this.disabledWeekend = config.disabledWeekend;
|
||||
this.holidays = config.holidays;
|
||||
this.taxDeadlines = config.taxDeadlines;
|
||||
|
||||
this.startDateEnabled = enabledRange.startDate;
|
||||
this.endDateEnabled = enabledRange.endDate;
|
||||
|
||||
// alert("finale Start : " + this.startDateEnabled)
|
||||
// alert("finale End : " + this.endDateEnabled)
|
||||
|
||||
|
||||
this._subscription = _service.model$.subscribe(model => {
|
||||
const newDate = model.firstDate;
|
||||
const oldDate = this.model ? this.model.firstDate : null;
|
||||
const newSelectedDate = model.selectedDate;
|
||||
const oldSelectedDate = this.model ? this.model.selectedDate : null;
|
||||
|
||||
this.model = model;
|
||||
|
||||
// handling selection change
|
||||
if (isChangedDate(newSelectedDate, oldSelectedDate)) {
|
||||
this.onTouched();
|
||||
this.onChange(
|
||||
newSelectedDate ? { year: newSelectedDate.year, month: newSelectedDate.month, day: newSelectedDate.day } :
|
||||
null);
|
||||
}
|
||||
// emitting navigation event if the first month changes
|
||||
if (!newDate.equals(oldDate)) {
|
||||
this.navigate.emit({
|
||||
current: oldDate ? { year: oldDate.year, month: oldDate.month } : null,
|
||||
next: { year: newDate.year, month: newDate.month }
|
||||
});
|
||||
}
|
||||
_cd.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
abilitaMesi(data) {
|
||||
|
||||
if(this.startDateEnabled.month <= data && data <= this.endDateEnabled.month && (this.startDateEnabled.year <= this.dataTemplate.year && this.dataTemplate.year <= this.endDateEnabled.year) ){
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
abilitaAnni(data) {
|
||||
|
||||
if(this.startDateEnabled.year <= data && data <= this.endDateEnabled.year){
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
setNewTemplate(selectedTemplate: number) {
|
||||
this.setMesi(this.dataTemplate.month, true);
|
||||
this.updateYears(this.dataTemplate.year);
|
||||
this.setYear(this.dataTemplate.year, true);
|
||||
const prevTemplate = this.template;
|
||||
this.template = selectedTemplate;
|
||||
if(prevTemplate === 2 && this.template === 0) {
|
||||
const model = this._service._model$.getValue();
|
||||
if(model && model.selectedDate) {
|
||||
this.navigateTo({month: model.selectedDate.month, year: model.selectedDate.year});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setMesi(position: number, selected: boolean) {
|
||||
|
||||
if (!this.abilitaMesi(position))
|
||||
return
|
||||
|
||||
let nRow = 0, nCol = 0
|
||||
|
||||
if (position == 4)
|
||||
nRow = 0
|
||||
else if (position == 8)
|
||||
nRow = 1
|
||||
else if (position == 12)
|
||||
nRow = 2
|
||||
else
|
||||
nRow = Math.trunc(position / 4)
|
||||
|
||||
nCol = position - (nRow * 4) - 1;
|
||||
console.info('dataTemplate', this.dataTemplate, 'mese', this.mesi[nRow][nCol], 'nRow', nRow, 'nCol', nCol);
|
||||
this.mesi[nRow][nCol].selected = selected;
|
||||
}
|
||||
|
||||
updateYears(startYearValue: number) {
|
||||
let yrs : CalendarItemNOA11Y[][] = [];
|
||||
for (let j = 0; j < 3; j++) {
|
||||
yrs[j] = [];
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const yr = new CalendarItemNOA11Y();
|
||||
yr.number = startYearValue + i + j * 4;
|
||||
yr.name = yr.number+"";
|
||||
yr.disabled = false;
|
||||
yr.focused = false;
|
||||
yr.selected = false;
|
||||
yrs[j][i]= yr;
|
||||
// this.years[j][i].number = startYearValue + i + j * 4
|
||||
// this.years[j][i].name = this.years[j][i].number + "";
|
||||
}
|
||||
}
|
||||
yrs.forEach((row) => {
|
||||
row.forEach((y) => {
|
||||
y.selected = this.dataTemplate.year === y.number;
|
||||
})
|
||||
})
|
||||
this.years = yrs;
|
||||
}
|
||||
|
||||
setYear(yearValue: number, selected: boolean) {
|
||||
|
||||
if (!this.abilitaAnni(yearValue))
|
||||
return
|
||||
|
||||
this.years.forEach((row) => {
|
||||
row.forEach((year) => {
|
||||
if (year.number == yearValue) year.selected = selected
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Manually focus the calendar
|
||||
*/
|
||||
focus() { this._elementRef.nativeElement.focus(); }
|
||||
|
||||
getHeaderHeight() {
|
||||
const h = this.showWeekdays ? 6.25 : 4.25;
|
||||
return this.displayMonths === 1 || this.navigation !== 'select' ? h - 2 : h;
|
||||
}
|
||||
|
||||
getHeaderMargin() {
|
||||
const m = this.showWeekdays ? 2 : 0;
|
||||
return this.displayMonths !== 1 || this.navigation !== 'select' ? m + 2 : m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates current view to provided date.
|
||||
* With default calendar we use ISO 8601: 'month' is 1=Jan ... 12=Dec.
|
||||
* If nothing or invalid date provided calendar will open current month.
|
||||
* Use 'startDate' input as an alternative
|
||||
*/
|
||||
navigateTo(date?: { year: number, month: number }) {
|
||||
this._service.open(date ? new NgbDate(date.year, date.month, 1) : this._calendar.getToday());
|
||||
}
|
||||
|
||||
ngOnDestroy() { this._subscription.unsubscribe(); }
|
||||
|
||||
ngOnInit() {
|
||||
if (this.model === undefined) {
|
||||
this._service.displayMonths = toInteger(this.displayMonths);
|
||||
this._service.markDisabled = this.markDisabled;
|
||||
this._service.firstDayOfWeek = this.firstDayOfWeek;
|
||||
this._service.disabledWeekend = this.disabledWeekend;
|
||||
this._service.holidays = this.holidays;
|
||||
this._service.taxDeadlines = this.taxDeadlines;
|
||||
this._setDates();
|
||||
|
||||
// inixializzazione dataTemplate alla data selezionata
|
||||
if (!this.startDate || !this.startDate.month || !this.startDate.year) {
|
||||
this.startDate = { year: null, month: null, day: null };
|
||||
|
||||
let today = new Date();
|
||||
let dd = today.getDate();
|
||||
let mm = today.getMonth() + 1; //January is 0!
|
||||
let yyyy = today.getFullYear();
|
||||
|
||||
this.startDate.day = dd;
|
||||
|
||||
this.startDate.month = mm;
|
||||
|
||||
this.startDate.year = yyyy
|
||||
}
|
||||
this.dataTemplate.day = this.startDate.day;
|
||||
this.dataTemplate.month = this.startDate.month;
|
||||
this.dataTemplate.year = this.startDate.year;
|
||||
this.dataTemplate.valid = false;
|
||||
|
||||
let elem: HTMLElement = this._elementRef.nativeElement;
|
||||
elem.classList.contains('isp-corporate-mode-wrapper') ? this.outsideDays = 'hidden' : this.outsideDays = 'visible';
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['displayMonths']) {
|
||||
this._service.displayMonths = toInteger(this.displayMonths);
|
||||
}
|
||||
if (changes['markDisabled']) {
|
||||
this._service.markDisabled = this.markDisabled;
|
||||
}
|
||||
if (changes['firstDayOfWeek']) {
|
||||
this._service.firstDayOfWeek = this.firstDayOfWeek;
|
||||
}
|
||||
if (changes['taxDeadlines']) {
|
||||
this._service.taxDeadlines = this.taxDeadlines;
|
||||
}
|
||||
}
|
||||
|
||||
onDateSelect(date: NgbDate) {
|
||||
this._service.focus(date);
|
||||
this.writeValue(date);
|
||||
}
|
||||
|
||||
onKeyDown(event: KeyboardEvent) { this._keyMapService.processKey(event); }
|
||||
|
||||
onNavigateDateSelect(date: NgbDate) {
|
||||
this._service.open(date);
|
||||
}
|
||||
|
||||
onNavigateEvent(event: NavigationEvent) {
|
||||
|
||||
let bufferData: NgbDate;
|
||||
|
||||
this.model.firstDate.month = this.dataTemplate.month;
|
||||
this.model.firstDate.year = this.dataTemplate.year;
|
||||
|
||||
if (event == NavigationEvent.PREV && this.template == 0) {
|
||||
bufferData = this._calendar.getPrev(this.model.firstDate, 'm', 1)
|
||||
this._service.open(bufferData);
|
||||
this.updateDataTemplate(bufferData)
|
||||
}
|
||||
else if (NavigationEvent.NEXT && this.template == 0) {
|
||||
bufferData = this._calendar.getNext(this.model.firstDate, 'm', 1);
|
||||
this._service.open(bufferData);
|
||||
this.updateDataTemplate(bufferData)
|
||||
}
|
||||
else if (event == NavigationEvent.PREV && this.template == 1) {
|
||||
|
||||
bufferData = this._calendar.getPrev(this.model.firstDate, 'm', 12);
|
||||
this._service.open(bufferData);
|
||||
this.updateDataTemplate(bufferData);
|
||||
}
|
||||
else if (event == NavigationEvent.NEXT && this.template == 1) {
|
||||
|
||||
bufferData = this._calendar.getNext(this.model.firstDate, 'm', 12);
|
||||
this._service.open(bufferData);
|
||||
this.updateDataTemplate(bufferData)
|
||||
}
|
||||
else if (event == NavigationEvent.PREV && this.template == 2) {
|
||||
bufferData = this._calendar.getPrev(this.model.firstDate, 'm', 144);
|
||||
this._service.open(bufferData);
|
||||
this.updateDataTemplate(bufferData);
|
||||
this.updateYears(this.dataTemplate.year);
|
||||
}
|
||||
else if (event == NavigationEvent.NEXT && this.template == 2) {
|
||||
|
||||
bufferData = this._calendar.getNext(this.model.firstDate, 'm', 144);
|
||||
this._service.open(bufferData);
|
||||
this.updateDataTemplate(bufferData);
|
||||
this.updateYears(this.dataTemplate.year);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onChangeTemplate(dataTemplate: NgbDataTemplateStruct) {
|
||||
this.dataTemplate = dataTemplate;
|
||||
this.template = dataTemplate.template;
|
||||
this.navigateTo({month: dataTemplate.month, year: dataTemplate.year});
|
||||
}
|
||||
updateDataTemplate(date: NgbDate) {
|
||||
const newTemplate = {...this.dataTemplate};
|
||||
newTemplate.day = date.day;
|
||||
newTemplate.month = date.month;
|
||||
newTemplate.year = date.year;
|
||||
this.dataTemplate = newTemplate;
|
||||
this.navigateTo({month: this.dataTemplate.month, year: this.dataTemplate.year});
|
||||
|
||||
}
|
||||
registerOnChange(fn: (value: any) => any): void { this.onChange = fn; }
|
||||
|
||||
registerOnTouched(fn: () => any): void { this.onTouched = fn; }
|
||||
|
||||
setDisabledState(isDisabled: boolean) { this._service.disabled = isDisabled; }
|
||||
|
||||
showFocus(focusVisible: boolean) { this._service.focusVisible = focusVisible; }
|
||||
|
||||
writeValue(value: any) { this._service.select(value); }
|
||||
|
||||
private _setDates() {
|
||||
const startDate = this._service.toValidDate(this.startDate, this._calendar.getToday());
|
||||
const minDate = this._service.toValidDate(this.minDate, this._calendar.getPrev(startDate, 'y', 10));
|
||||
const maxDate =
|
||||
this._service.toValidDate(this.maxDate, this._calendar.getPrev(this._calendar.getNext(startDate, 'y', 11)));
|
||||
|
||||
this.minDate = { year: minDate.year, month: minDate.month, day: minDate.day };
|
||||
this.maxDate = { year: maxDate.year, month: maxDate.month, day: maxDate.day };
|
||||
|
||||
this._service.minDate = minDate;
|
||||
this._service.maxDate = maxDate;
|
||||
this.navigateTo(startDate);
|
||||
}
|
||||
|
||||
public focusOutComponent(event: any){
|
||||
if(!this._elementRef.nativeElement.contains(event.target)) {
|
||||
let elem: HTMLElement = this._elementRef.nativeElement;
|
||||
if(elem.parentElement) {
|
||||
elem.parentElement.removeChild(elem);
|
||||
}
|
||||
this._subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* The payload of the calendar navigation event
|
||||
*/
|
||||
export interface NgbDatepickerNavigateEventNOA11Y {
|
||||
/**
|
||||
* Currently displayed month
|
||||
*/
|
||||
current: { year: number, month: number };
|
||||
|
||||
/**
|
||||
* Month we're navigating to
|
||||
*/
|
||||
next: { year: number, month: number };
|
||||
}
|
||||
|
@ -0,0 +1,95 @@
|
||||
import {NgbDate} from '../ngb-date';
|
||||
import {NgbPeriodNOA11Y, NgbCalendarNOA11Y} from '../ngb-calendar';
|
||||
import {Injectable} from '@angular/core';
|
||||
import {isNumber} from '../../util/util';
|
||||
|
||||
@Injectable()
|
||||
export abstract class NgbCalendarHijriNOA11Y extends NgbCalendarNOA11Y {
|
||||
getDaysPerWeek() { return 7; }
|
||||
|
||||
getMonths() { return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; }
|
||||
|
||||
getWeeksPerMonth() { return 6; }
|
||||
|
||||
isValid(date: NgbDate): boolean {
|
||||
return date && isNumber(date.year) && isNumber(date.month) && isNumber(date.day) &&
|
||||
!isNaN(this.toGregorian(date).getTime());
|
||||
}
|
||||
|
||||
setDay(date: NgbDate, day: number): NgbDate {
|
||||
day = +day;
|
||||
let mDays = this.getDaysInIslamicMonth(date.month, date.year);
|
||||
if (day <= 0) {
|
||||
while (day <= 0) {
|
||||
date = this.setMonth(date, date.month - 1);
|
||||
mDays = this.getDaysInIslamicMonth(date.month, date.year);
|
||||
day += mDays;
|
||||
}
|
||||
} else if (day > mDays) {
|
||||
while (day > mDays) {
|
||||
day -= mDays;
|
||||
date = this.setMonth(date, date.month + 1);
|
||||
mDays = this.getDaysInIslamicMonth(date.month, date.year);
|
||||
}
|
||||
}
|
||||
date.day = day;
|
||||
return date;
|
||||
}
|
||||
|
||||
setMonth(date: NgbDate, month: number): NgbDate {
|
||||
month = +month;
|
||||
date.year = date.year + Math.floor((month - 1) / 12);
|
||||
date.month = Math.floor(((month - 1) % 12 + 12) % 12) + 1;
|
||||
return date;
|
||||
}
|
||||
|
||||
setYear(date: NgbDate, yearValue: number): NgbDate {
|
||||
date.year = +yearValue;
|
||||
return date;
|
||||
}
|
||||
|
||||
abstract getWeekday(date: NgbDate): number;
|
||||
|
||||
abstract getNext(date: NgbDate, period?: NgbPeriodNOA11Y, number?: number): NgbDate;
|
||||
|
||||
abstract getPrev(date: NgbDate, period?: NgbPeriodNOA11Y, number?: number): NgbDate;
|
||||
|
||||
abstract getWeekNumber(week: NgbDate[], firstDayOfWeek: number): number;
|
||||
|
||||
abstract getToday(): NgbDate;
|
||||
|
||||
/**
|
||||
* Returns the equivalent Hijri date value for a give input Gregorian date.
|
||||
* `gDate` is s JS Date to be converted to Hijri.
|
||||
*/
|
||||
abstract fromGregorian(gDate: Date): NgbDate;
|
||||
|
||||
/**
|
||||
* Converts the current Hijri date to Gregorian.
|
||||
*/
|
||||
abstract toGregorian(hijriDate: NgbDate): Date;
|
||||
|
||||
/**
|
||||
* Returns the number of days in a specific Hijri month.
|
||||
* `month` is 1 for Muharram, 2 for Safar, etc.
|
||||
* `year` is any Hijri year.
|
||||
*/
|
||||
abstract getDaysInIslamicMonth(month: number, year: number): number;
|
||||
|
||||
protected _isIslamicLeapYear(year: number): boolean { return (14 + 11 * year) % 30 < 11; }
|
||||
|
||||
/**
|
||||
* Returns the start of Hijri Month.
|
||||
* `month` is 0 for Muharram, 1 for Safar, etc.
|
||||
* `year` is any Hijri year.
|
||||
*/
|
||||
protected _getMonthStart(year: number, month: number): number {
|
||||
return Math.ceil(29.5 * month) + (year - 1) * 354 + Math.floor((3 + 11 * year) / 30.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start of Hijri year.
|
||||
* `year` is any Hijri year.
|
||||
*/
|
||||
protected _getYearStart(year: number): number { return (year - 1) * 354 + Math.floor((3 + 11 * year) / 30.0); }
|
||||
}
|
@ -0,0 +1,429 @@
|
||||
import {NgbCalendarIslamicCivilNOA11Y} from './ngb-calendar-islamic-civil';
|
||||
import {NgbDate} from '../ngb-date';
|
||||
|
||||
describe('ngb-calendar-islamic-civil', () => {
|
||||
const DATE_TABLE = [
|
||||
[1420, 1, 1, 1999, 3, 17], [1420, 1, 12, 1999, 3, 28], [1420, 1, 23, 1999, 4, 9],
|
||||
[1420, 2, 4, 1999, 4, 20], [1420, 2, 15, 1999, 4, 31], [1420, 2, 26, 1999, 5, 11],
|
||||
[1420, 3, 8, 1999, 5, 22], [1420, 3, 19, 1999, 6, 3], [1420, 3, 30, 1999, 6, 14],
|
||||
[1420, 4, 11, 1999, 6, 25], [1420, 4, 22, 1999, 7, 5], [1420, 5, 4, 1999, 7, 16],
|
||||
[1420, 5, 15, 1999, 7, 27], [1420, 5, 26, 1999, 8, 7], [1420, 6, 7, 1999, 8, 18],
|
||||
[1420, 6, 18, 1999, 8, 29], [1420, 6, 29, 1999, 9, 10], [1420, 7, 11, 1999, 9, 21],
|
||||
[1420, 7, 22, 1999, 10, 1], [1420, 8, 3, 1999, 10, 12], [1420, 8, 14, 1999, 10, 23],
|
||||
[1420, 9, 29, 2000, 0, 6], [1420, 10, 10, 2000, 0, 17], [1420, 10, 21, 2000, 0, 28],
|
||||
[1420, 11, 3, 2000, 1, 8], [1420, 11, 14, 2000, 1, 19], [1420, 11, 25, 2000, 2, 1],
|
||||
[1420, 12, 6, 2000, 2, 12], [1420, 12, 17, 2000, 2, 23], [1420, 12, 28, 2000, 3, 3],
|
||||
[1421, 1, 9, 2000, 3, 14], [1421, 1, 20, 2000, 3, 25], [1421, 2, 1, 2000, 4, 6],
|
||||
[1421, 2, 12, 2000, 4, 17], [1421, 2, 23, 2000, 4, 28], [1421, 3, 5, 2000, 5, 8],
|
||||
[1421, 3, 16, 2000, 5, 19], [1421, 3, 27, 2000, 5, 30], [1421, 4, 8, 2000, 6, 11],
|
||||
[1421, 4, 19, 2000, 6, 22], [1421, 5, 1, 2000, 7, 2], [1421, 5, 12, 2000, 7, 13],
|
||||
[1421, 5, 23, 2000, 7, 24], [1421, 6, 4, 2000, 8, 4], [1421, 6, 15, 2000, 8, 15],
|
||||
[1421, 6, 26, 2000, 8, 26], [1421, 7, 8, 2000, 9, 7], [1421, 7, 19, 2000, 9, 18],
|
||||
[1421, 7, 30, 2000, 9, 29], [1421, 8, 11, 2000, 10, 9], [1421, 8, 22, 2000, 10, 20],
|
||||
[1421, 10, 7, 2001, 0, 3], [1421, 10, 18, 2001, 0, 14], [1421, 10, 7, 2001, 0, 3],
|
||||
[1421, 10, 18, 2001, 0, 14], [1421, 10, 29, 2001, 0, 25], [1421, 11, 11, 2001, 1, 5],
|
||||
[1421, 11, 22, 2001, 1, 16], [1421, 12, 3, 2001, 1, 27], [1421, 12, 14, 2001, 2, 10],
|
||||
[1421, 12, 25, 2001, 2, 21], [1422, 1, 7, 2001, 3, 1], [1422, 1, 18, 2001, 3, 12],
|
||||
[1422, 1, 29, 2001, 3, 23], [1422, 2, 10, 2001, 4, 4], [1422, 2, 21, 2001, 4, 15],
|
||||
[1422, 3, 3, 2001, 4, 26], [1422, 3, 14, 2001, 5, 6], [1422, 3, 25, 2001, 5, 17],
|
||||
[1422, 4, 6, 2001, 5, 28], [1422, 4, 17, 2001, 6, 9], [1422, 4, 28, 2001, 6, 20],
|
||||
[1422, 5, 10, 2001, 6, 31], [1422, 5, 21, 2001, 7, 11], [1422, 6, 2, 2001, 7, 22],
|
||||
[1422, 6, 13, 2001, 8, 2], [1422, 6, 24, 2001, 8, 13], [1422, 7, 6, 2001, 8, 24],
|
||||
[1422, 7, 17, 2001, 9, 5], [1422, 7, 28, 2001, 9, 16], [1422, 8, 9, 2001, 9, 27],
|
||||
[1422, 8, 20, 2001, 10, 7], [1422, 9, 2, 2001, 10, 18], [1422, 9, 13, 2001, 10, 29],
|
||||
[1422, 9, 24, 2001, 11, 10], [1422, 10, 5, 2001, 11, 21], [1422, 10, 16, 2002, 0, 1],
|
||||
[1422, 10, 27, 2002, 0, 12], [1422, 11, 9, 2002, 0, 23], [1422, 11, 20, 2002, 1, 3],
|
||||
[1422, 12, 1, 2002, 1, 14], [1422, 12, 12, 2002, 1, 25], [1422, 12, 23, 2002, 2, 8],
|
||||
[1423, 1, 5, 2002, 2, 19], [1423, 1, 16, 2002, 2, 30], [1423, 1, 27, 2002, 3, 10],
|
||||
[1423, 2, 8, 2002, 3, 21], [1423, 2, 19, 2002, 4, 2], [1423, 3, 1, 2002, 4, 13],
|
||||
[1423, 3, 12, 2002, 4, 24], [1423, 3, 23, 2002, 5, 4], [1423, 4, 4, 2002, 5, 15],
|
||||
[1423, 4, 15, 2002, 5, 26], [1423, 4, 26, 2002, 6, 7], [1423, 5, 8, 2002, 6, 18],
|
||||
[1423, 5, 19, 2002, 6, 29], [1423, 5, 30, 2002, 7, 9], [1423, 6, 11, 2002, 7, 20],
|
||||
[1423, 6, 22, 2002, 7, 31], [1423, 7, 4, 2002, 8, 11], [1423, 7, 15, 2002, 8, 22],
|
||||
[1423, 7, 26, 2002, 9, 3], [1423, 8, 7, 2002, 9, 14], [1423, 8, 18, 2002, 9, 25],
|
||||
[1423, 8, 29, 2002, 10, 5], [1423, 9, 11, 2002, 10, 16], [1423, 9, 22, 2002, 10, 27],
|
||||
[1423, 10, 3, 2002, 11, 8], [1423, 10, 14, 2002, 11, 19], [1423, 10, 25, 2002, 11, 30],
|
||||
[1423, 11, 7, 2003, 0, 10], [1423, 11, 18, 2003, 0, 21], [1423, 11, 29, 2003, 1, 1],
|
||||
[1423, 12, 10, 2003, 1, 12], [1423, 12, 21, 2003, 1, 23], [1424, 1, 2, 2003, 2, 6],
|
||||
[1424, 1, 13, 2003, 2, 17], [1424, 1, 24, 2003, 2, 28], [1424, 2, 5, 2003, 3, 8],
|
||||
[1424, 2, 16, 2003, 3, 19], [1424, 2, 27, 2003, 3, 30], [1424, 3, 9, 2003, 4, 11],
|
||||
[1424, 3, 20, 2003, 4, 22], [1424, 4, 1, 2003, 5, 2], [1424, 4, 12, 2003, 5, 13],
|
||||
[1424, 4, 23, 2003, 5, 24], [1424, 5, 5, 2003, 6, 5], [1424, 5, 16, 2003, 6, 16],
|
||||
[1424, 5, 27, 2003, 6, 27], [1424, 6, 8, 2003, 7, 7], [1424, 6, 19, 2003, 7, 18],
|
||||
[1424, 7, 1, 2003, 7, 29], [1424, 7, 12, 2003, 8, 9], [1424, 7, 23, 2003, 8, 20],
|
||||
[1424, 8, 4, 2003, 9, 1], [1424, 8, 15, 2003, 9, 12], [1424, 8, 26, 2003, 9, 23],
|
||||
[1424, 9, 8, 2003, 10, 3], [1424, 9, 19, 2003, 10, 14], [1424, 9, 30, 2003, 10, 25],
|
||||
[1424, 11, 15, 2004, 0, 8], [1424, 11, 26, 2004, 0, 19], [1424, 12, 7, 2004, 0, 30],
|
||||
[1424, 12, 18, 2004, 1, 10], [1424, 12, 29, 2004, 1, 21], [1425, 1, 11, 2004, 2, 3],
|
||||
[1425, 1, 22, 2004, 2, 14], [1425, 2, 3, 2004, 2, 25], [1425, 2, 14, 2004, 3, 5],
|
||||
[1425, 2, 25, 2004, 3, 16], [1425, 3, 7, 2004, 3, 27], [1425, 3, 18, 2004, 4, 8],
|
||||
[1425, 3, 29, 2004, 4, 19], [1425, 4, 10, 2004, 4, 30], [1425, 4, 21, 2004, 5, 10],
|
||||
[1425, 5, 3, 2004, 5, 21], [1425, 5, 14, 2004, 6, 2], [1425, 5, 25, 2004, 6, 13],
|
||||
[1425, 6, 6, 2004, 6, 24], [1425, 6, 17, 2004, 7, 4], [1425, 6, 28, 2004, 7, 15],
|
||||
[1425, 7, 10, 2004, 7, 26], [1425, 7, 21, 2004, 8, 6], [1425, 8, 2, 2004, 8, 17],
|
||||
[1425, 8, 13, 2004, 8, 28], [1425, 8, 24, 2004, 9, 9], [1425, 9, 6, 2004, 9, 20],
|
||||
[1425, 9, 17, 2004, 9, 31], [1425, 9, 28, 2004, 10, 11], [1425, 10, 9, 2004, 10, 22],
|
||||
[1425, 11, 24, 2005, 0, 5], [1425, 12, 5, 2005, 0, 16], [1425, 12, 16, 2005, 0, 27],
|
||||
[1425, 12, 27, 2005, 1, 7], [1426, 1, 9, 2005, 1, 18], [1426, 1, 20, 2005, 2, 1],
|
||||
[1426, 2, 1, 2005, 2, 12], [1426, 2, 12, 2005, 2, 23], [1426, 2, 23, 2005, 3, 3],
|
||||
[1426, 3, 5, 2005, 3, 14], [1426, 3, 16, 2005, 3, 25], [1426, 3, 27, 2005, 4, 6],
|
||||
[1426, 4, 8, 2005, 4, 17], [1426, 4, 19, 2005, 4, 28], [1426, 5, 1, 2005, 5, 8],
|
||||
[1426, 5, 12, 2005, 5, 19], [1426, 5, 23, 2005, 5, 30], [1426, 6, 4, 2005, 6, 11],
|
||||
[1426, 6, 15, 2005, 6, 22], [1426, 6, 26, 2005, 7, 2], [1426, 7, 8, 2005, 7, 13],
|
||||
[1426, 7, 19, 2005, 7, 24], [1426, 7, 30, 2005, 8, 4], [1426, 8, 11, 2005, 8, 15],
|
||||
[1426, 8, 22, 2005, 8, 26], [1426, 9, 4, 2005, 9, 7], [1426, 9, 15, 2005, 9, 18],
|
||||
[1426, 9, 26, 2005, 9, 29], [1426, 10, 7, 2005, 10, 9], [1426, 10, 18, 2005, 10, 20],
|
||||
[1426, 10, 29, 2005, 11, 1], [1426, 11, 11, 2005, 11, 12], [1426, 11, 22, 2005, 11, 23],
|
||||
[1426, 12, 3, 2006, 0, 3], [1426, 12, 14, 2006, 0, 14], [1426, 12, 25, 2006, 0, 25],
|
||||
[1427, 1, 6, 2006, 1, 5], [1427, 1, 17, 2006, 1, 16], [1427, 1, 28, 2006, 1, 27],
|
||||
[1427, 2, 9, 2006, 2, 10], [1427, 2, 20, 2006, 2, 21], [1427, 3, 2, 2006, 3, 1],
|
||||
[1427, 3, 13, 2006, 3, 12], [1427, 3, 24, 2006, 3, 23], [1427, 4, 5, 2006, 4, 4],
|
||||
[1427, 4, 16, 2006, 4, 15], [1427, 4, 27, 2006, 4, 26], [1427, 5, 9, 2006, 5, 6],
|
||||
[1427, 5, 20, 2006, 5, 17], [1427, 6, 1, 2006, 5, 28], [1427, 6, 12, 2006, 6, 9],
|
||||
[1427, 6, 23, 2006, 6, 20], [1427, 7, 5, 2006, 6, 31], [1427, 7, 16, 2006, 7, 11],
|
||||
[1427, 7, 27, 2006, 7, 22], [1427, 8, 8, 2006, 8, 2], [1427, 8, 19, 2006, 8, 13],
|
||||
[1427, 9, 1, 2006, 8, 24], [1427, 9, 12, 2006, 9, 5], [1427, 9, 23, 2006, 9, 16],
|
||||
[1427, 10, 4, 2006, 9, 27], [1427, 10, 15, 2006, 10, 7], [1427, 10, 26, 2006, 10, 18],
|
||||
[1427, 11, 8, 2006, 10, 29], [1427, 11, 19, 2006, 11, 10], [1427, 11, 30, 2006, 11, 21],
|
||||
[1427, 12, 11, 2007, 0, 1], [1427, 12, 22, 2007, 0, 12], [1428, 1, 4, 2007, 0, 23],
|
||||
[1428, 1, 15, 2007, 1, 3], [1428, 1, 26, 2007, 1, 14], [1428, 2, 7, 2007, 1, 25],
|
||||
[1428, 2, 18, 2007, 2, 8], [1428, 2, 29, 2007, 2, 19], [1428, 3, 11, 2007, 2, 30],
|
||||
[1428, 3, 22, 2007, 3, 10], [1428, 4, 3, 2007, 3, 21], [1428, 4, 14, 2007, 4, 2],
|
||||
[1428, 4, 25, 2007, 4, 13], [1428, 5, 7, 2007, 4, 24], [1428, 5, 18, 2007, 5, 4],
|
||||
[1428, 5, 29, 2007, 5, 15], [1428, 6, 10, 2007, 5, 26], [1428, 6, 21, 2007, 6, 7],
|
||||
[1428, 7, 3, 2007, 6, 18], [1428, 7, 14, 2007, 6, 29], [1428, 7, 25, 2007, 7, 9],
|
||||
[1428, 8, 6, 2007, 7, 20], [1428, 8, 17, 2007, 7, 31], [1428, 8, 28, 2007, 8, 11],
|
||||
[1428, 9, 10, 2007, 8, 22], [1428, 9, 21, 2007, 9, 3], [1428, 10, 2, 2007, 9, 14],
|
||||
[1428, 10, 13, 2007, 9, 25], [1428, 10, 24, 2007, 10, 5], [1428, 11, 6, 2007, 10, 16],
|
||||
[1428, 11, 17, 2007, 10, 27], [1429, 1, 1, 2008, 0, 10], [1429, 1, 12, 2008, 0, 21],
|
||||
[1429, 1, 23, 2008, 1, 1], [1429, 2, 4, 2008, 1, 12], [1429, 2, 15, 2008, 1, 23],
|
||||
[1429, 2, 26, 2008, 2, 5], [1429, 3, 8, 2008, 2, 16], [1429, 3, 19, 2008, 2, 27],
|
||||
[1429, 3, 30, 2008, 3, 7], [1429, 4, 11, 2008, 3, 18], [1429, 4, 22, 2008, 3, 29],
|
||||
[1429, 5, 4, 2008, 4, 10], [1429, 5, 15, 2008, 4, 21], [1429, 5, 26, 2008, 5, 1],
|
||||
[1429, 6, 7, 2008, 5, 12], [1429, 6, 18, 2008, 5, 23], [1429, 6, 29, 2008, 6, 4],
|
||||
[1429, 7, 11, 2008, 6, 15], [1429, 7, 22, 2008, 6, 26], [1429, 8, 3, 2008, 7, 6],
|
||||
[1429, 8, 14, 2008, 7, 17], [1429, 8, 25, 2008, 7, 28], [1429, 9, 7, 2008, 8, 8],
|
||||
[1429, 9, 18, 2008, 8, 19], [1429, 9, 29, 2008, 8, 30], [1429, 10, 10, 2008, 9, 11],
|
||||
[1429, 10, 21, 2008, 9, 22], [1429, 11, 3, 2008, 10, 2], [1429, 11, 14, 2008, 10, 13],
|
||||
[1429, 11, 25, 2008, 10, 24], [1430, 1, 10, 2009, 0, 7], [1430, 1, 21, 2009, 0, 18],
|
||||
[1430, 2, 2, 2009, 0, 29], [1430, 2, 13, 2009, 1, 9], [1430, 2, 24, 2009, 1, 20],
|
||||
[1430, 3, 6, 2009, 2, 3], [1430, 3, 17, 2009, 2, 14], [1430, 3, 28, 2009, 2, 25],
|
||||
[1430, 4, 9, 2009, 3, 5], [1430, 4, 20, 2009, 3, 16], [1430, 5, 2, 2009, 3, 27],
|
||||
[1430, 5, 13, 2009, 4, 8], [1430, 5, 24, 2009, 4, 19], [1430, 6, 5, 2009, 4, 30],
|
||||
[1430, 6, 16, 2009, 5, 10], [1430, 6, 27, 2009, 5, 21], [1430, 7, 9, 2009, 6, 2],
|
||||
[1430, 7, 20, 2009, 6, 13], [1430, 8, 1, 2009, 6, 24], [1430, 8, 12, 2009, 7, 4],
|
||||
[1430, 8, 23, 2009, 7, 15], [1430, 9, 5, 2009, 7, 26], [1430, 9, 16, 2009, 8, 6],
|
||||
[1430, 9, 27, 2009, 8, 17], [1430, 10, 8, 2009, 8, 28], [1430, 10, 19, 2009, 9, 9],
|
||||
[1430, 11, 1, 2009, 9, 20], [1430, 11, 12, 2009, 9, 31], [1430, 11, 23, 2009, 10, 11],
|
||||
[1430, 12, 4, 2009, 10, 22], [1430, 12, 15, 2009, 11, 3], [1430, 12, 26, 2009, 11, 14],
|
||||
[1431, 1, 8, 2009, 11, 25], [1431, 1, 19, 2010, 0, 5], [1431, 1, 30, 2010, 0, 16],
|
||||
[1431, 2, 11, 2010, 0, 27], [1431, 2, 22, 2010, 1, 7], [1431, 3, 4, 2010, 1, 18],
|
||||
[1431, 3, 15, 2010, 2, 1], [1431, 3, 26, 2010, 2, 12], [1431, 4, 7, 2010, 2, 23],
|
||||
[1431, 4, 18, 2010, 3, 3], [1431, 4, 29, 2010, 3, 14], [1431, 5, 11, 2010, 3, 25],
|
||||
[1431, 5, 22, 2010, 4, 6], [1431, 6, 3, 2010, 4, 17], [1431, 6, 14, 2010, 4, 28],
|
||||
[1431, 6, 25, 2010, 5, 8], [1431, 7, 7, 2010, 5, 19], [1431, 7, 18, 2010, 5, 30],
|
||||
[1431, 7, 29, 2010, 6, 11], [1431, 8, 10, 2010, 6, 22], [1431, 8, 21, 2010, 7, 2],
|
||||
[1431, 9, 3, 2010, 7, 13], [1431, 9, 14, 2010, 7, 24], [1431, 9, 25, 2010, 8, 4],
|
||||
[1431, 10, 6, 2010, 8, 15], [1431, 10, 17, 2010, 8, 26], [1431, 10, 28, 2010, 9, 7],
|
||||
[1431, 11, 10, 2010, 9, 18], [1431, 11, 21, 2010, 9, 29], [1431, 12, 2, 2010, 10, 9],
|
||||
[1431, 12, 13, 2010, 10, 20], [1431, 12, 24, 2010, 11, 1], [1432, 1, 5, 2010, 11, 12],
|
||||
[1432, 1, 16, 2010, 11, 23], [1432, 1, 27, 2011, 0, 3], [1432, 2, 8, 2011, 0, 14],
|
||||
[1432, 2, 19, 2011, 0, 25], [1432, 3, 1, 2011, 1, 5], [1432, 3, 12, 2011, 1, 16],
|
||||
[1432, 3, 23, 2011, 1, 27], [1432, 4, 4, 2011, 2, 10], [1432, 4, 15, 2011, 2, 21],
|
||||
[1432, 4, 26, 2011, 3, 1], [1432, 5, 8, 2011, 3, 12], [1432, 5, 19, 2011, 3, 23],
|
||||
[1432, 5, 30, 2011, 4, 4], [1432, 6, 11, 2011, 4, 15], [1432, 6, 22, 2011, 4, 26],
|
||||
[1432, 7, 4, 2011, 5, 6], [1432, 7, 15, 2011, 5, 17], [1432, 7, 26, 2011, 5, 28],
|
||||
[1432, 8, 7, 2011, 6, 9], [1432, 8, 18, 2011, 6, 20], [1432, 8, 29, 2011, 6, 31],
|
||||
[1432, 9, 11, 2011, 7, 11], [1432, 9, 22, 2011, 7, 22], [1432, 10, 3, 2011, 8, 2],
|
||||
[1432, 10, 14, 2011, 8, 13], [1432, 10, 25, 2011, 8, 24], [1432, 11, 7, 2011, 9, 5],
|
||||
[1432, 11, 18, 2011, 9, 16], [1432, 11, 29, 2011, 9, 27], [1432, 12, 10, 2011, 10, 7],
|
||||
[1432, 12, 21, 2011, 10, 18], [1433, 1, 3, 2011, 10, 29], [1433, 2, 6, 2012, 0, 1],
|
||||
[1433, 2, 17, 2012, 0, 12], [1433, 2, 28, 2012, 0, 23], [1433, 3, 10, 2012, 1, 3],
|
||||
[1433, 3, 21, 2012, 1, 14], [1433, 4, 2, 2012, 1, 25], [1433, 4, 13, 2012, 2, 7],
|
||||
[1433, 4, 24, 2012, 2, 18], [1433, 5, 6, 2012, 2, 29], [1433, 5, 17, 2012, 3, 9],
|
||||
[1433, 5, 28, 2012, 3, 20], [1433, 6, 9, 2012, 4, 1], [1433, 6, 20, 2012, 4, 12],
|
||||
[1433, 7, 2, 2012, 4, 23], [1433, 7, 13, 2012, 5, 3], [1433, 7, 24, 2012, 5, 14],
|
||||
[1433, 8, 5, 2012, 5, 25], [1433, 8, 16, 2012, 6, 6], [1433, 8, 27, 2012, 6, 17],
|
||||
[1433, 9, 9, 2012, 6, 28], [1433, 9, 20, 2012, 7, 8], [1433, 10, 1, 2012, 7, 19],
|
||||
[1433, 10, 12, 2012, 7, 30], [1433, 10, 23, 2012, 8, 10], [1433, 11, 5, 2012, 8, 21],
|
||||
[1433, 11, 16, 2012, 9, 2], [1433, 11, 27, 2012, 9, 13], [1433, 12, 8, 2012, 9, 24],
|
||||
[1433, 12, 19, 2012, 10, 4], [1434, 1, 1, 2012, 10, 15], [1434, 1, 12, 2012, 10, 26],
|
||||
[1434, 2, 26, 2013, 0, 9], [1434, 3, 8, 2013, 0, 20], [1434, 3, 19, 2013, 0, 31],
|
||||
[1434, 3, 30, 2013, 1, 11], [1434, 4, 11, 2013, 1, 22], [1434, 4, 22, 2013, 2, 5],
|
||||
[1434, 5, 4, 2013, 2, 16], [1434, 5, 15, 2013, 2, 27], [1434, 5, 26, 2013, 3, 7],
|
||||
[1434, 6, 7, 2013, 3, 18], [1434, 6, 18, 2013, 3, 29], [1434, 6, 29, 2013, 4, 10],
|
||||
[1434, 7, 11, 2013, 4, 21], [1434, 7, 22, 2013, 5, 1], [1434, 8, 3, 2013, 5, 12],
|
||||
[1434, 8, 14, 2013, 5, 23], [1434, 8, 25, 2013, 6, 4], [1434, 9, 7, 2013, 6, 15],
|
||||
[1434, 9, 18, 2013, 6, 26], [1434, 9, 29, 2013, 7, 6], [1434, 10, 10, 2013, 7, 17],
|
||||
[1434, 10, 21, 2013, 7, 28], [1434, 11, 3, 2013, 8, 8], [1434, 11, 14, 2013, 8, 19],
|
||||
[1434, 11, 25, 2013, 8, 30], [1434, 12, 6, 2013, 9, 11], [1434, 12, 17, 2013, 9, 22],
|
||||
[1434, 12, 28, 2013, 10, 2], [1435, 1, 9, 2013, 10, 13], [1435, 1, 20, 2013, 10, 24],
|
||||
[1435, 2, 1, 2013, 11, 5], [1435, 2, 12, 2013, 11, 16], [1435, 2, 23, 2013, 11, 27],
|
||||
[1435, 3, 5, 2014, 0, 7], [1435, 3, 16, 2014, 0, 18], [1435, 3, 27, 2014, 0, 29],
|
||||
[1435, 4, 8, 2014, 1, 9], [1435, 4, 19, 2014, 1, 20], [1435, 5, 1, 2014, 2, 3],
|
||||
[1435, 5, 12, 2014, 2, 14], [1435, 5, 23, 2014, 2, 25], [1435, 6, 4, 2014, 3, 5],
|
||||
[1435, 6, 15, 2014, 3, 16], [1435, 6, 26, 2014, 3, 27], [1435, 7, 8, 2014, 4, 8],
|
||||
[1435, 7, 19, 2014, 4, 19], [1435, 7, 30, 2014, 4, 30], [1435, 8, 11, 2014, 5, 10],
|
||||
[1435, 8, 22, 2014, 5, 21], [1435, 9, 4, 2014, 6, 2], [1435, 9, 15, 2014, 6, 13],
|
||||
[1435, 9, 26, 2014, 6, 24], [1435, 10, 7, 2014, 7, 4], [1435, 10, 18, 2014, 7, 15],
|
||||
[1435, 10, 29, 2014, 7, 26], [1435, 11, 11, 2014, 8, 6], [1435, 11, 22, 2014, 8, 17],
|
||||
[1435, 12, 3, 2014, 8, 28], [1435, 12, 14, 2014, 9, 9], [1435, 12, 25, 2014, 9, 20],
|
||||
[1436, 1, 7, 2014, 9, 31], [1436, 1, 18, 2014, 10, 11], [1436, 1, 29, 2014, 10, 22],
|
||||
[1436, 2, 10, 2014, 11, 3], [1436, 2, 21, 2014, 11, 14], [1436, 3, 3, 2014, 11, 25],
|
||||
[1436, 3, 14, 2015, 0, 5], [1436, 3, 25, 2015, 0, 16], [1436, 4, 6, 2015, 0, 27],
|
||||
[1436, 4, 17, 2015, 1, 7], [1436, 4, 28, 2015, 1, 18], [1436, 5, 10, 2015, 2, 1],
|
||||
[1436, 5, 21, 2015, 2, 12], [1436, 6, 2, 2015, 2, 23], [1436, 6, 13, 2015, 3, 3],
|
||||
[1436, 6, 24, 2015, 3, 14], [1436, 7, 6, 2015, 3, 25], [1436, 7, 17, 2015, 4, 6],
|
||||
[1436, 7, 28, 2015, 4, 17], [1436, 8, 9, 2015, 4, 28], [1436, 8, 20, 2015, 5, 8],
|
||||
[1436, 9, 2, 2015, 5, 19], [1436, 9, 13, 2015, 5, 30], [1436, 9, 24, 2015, 6, 11],
|
||||
[1436, 10, 5, 2015, 6, 22], [1436, 10, 16, 2015, 7, 2], [1436, 10, 27, 2015, 7, 13],
|
||||
[1436, 11, 9, 2015, 7, 24], [1436, 11, 20, 2015, 8, 4], [1436, 12, 1, 2015, 8, 15],
|
||||
[1436, 12, 12, 2015, 8, 26], [1436, 12, 23, 2015, 9, 7], [1437, 1, 4, 2015, 9, 18],
|
||||
[1437, 1, 15, 2015, 9, 29], [1437, 1, 26, 2015, 10, 9], [1437, 2, 7, 2015, 10, 20],
|
||||
[1437, 3, 22, 2016, 0, 3], [1437, 4, 3, 2016, 0, 14], [1437, 4, 14, 2016, 0, 25],
|
||||
[1437, 4, 25, 2016, 1, 5], [1437, 5, 7, 2016, 1, 16], [1437, 5, 18, 2016, 1, 27],
|
||||
[1437, 5, 29, 2016, 2, 9], [1437, 6, 10, 2016, 2, 20], [1437, 6, 21, 2016, 2, 31],
|
||||
[1437, 7, 3, 2016, 3, 11], [1437, 7, 14, 2016, 3, 22], [1437, 7, 25, 2016, 4, 3],
|
||||
[1437, 8, 6, 2016, 4, 14], [1437, 8, 17, 2016, 4, 25], [1437, 8, 28, 2016, 5, 5],
|
||||
[1437, 9, 10, 2016, 5, 16], [1437, 9, 21, 2016, 5, 27], [1437, 10, 2, 2016, 6, 8],
|
||||
[1437, 10, 13, 2016, 6, 19], [1437, 10, 24, 2016, 6, 30], [1437, 11, 6, 2016, 7, 10],
|
||||
[1437, 11, 17, 2016, 7, 21], [1437, 11, 28, 2016, 8, 1], [1437, 12, 9, 2016, 8, 12],
|
||||
[1437, 12, 20, 2016, 8, 23], [1438, 1, 2, 2016, 9, 4], [1438, 1, 13, 2016, 9, 15],
|
||||
[1438, 1, 24, 2016, 9, 26], [1438, 2, 5, 2016, 10, 6], [1438, 2, 16, 2016, 10, 17],
|
||||
[1438, 2, 27, 2016, 10, 28], [1438, 4, 12, 2017, 0, 11], [1438, 4, 23, 2017, 0, 22],
|
||||
[1438, 5, 5, 2017, 1, 2], [1438, 5, 16, 2017, 1, 13], [1438, 5, 27, 2017, 1, 24],
|
||||
[1438, 6, 8, 2017, 2, 7], [1438, 6, 19, 2017, 2, 18], [1438, 7, 1, 2017, 2, 29],
|
||||
[1438, 7, 12, 2017, 3, 9], [1438, 7, 23, 2017, 3, 20], [1438, 8, 4, 2017, 4, 1],
|
||||
[1438, 8, 15, 2017, 4, 12], [1438, 8, 26, 2017, 4, 23], [1438, 9, 8, 2017, 5, 3],
|
||||
[1438, 9, 19, 2017, 5, 14], [1438, 9, 30, 2017, 5, 25], [1438, 10, 11, 2017, 6, 6],
|
||||
[1438, 10, 22, 2017, 6, 17], [1438, 11, 4, 2017, 6, 28], [1438, 11, 15, 2017, 7, 8],
|
||||
[1438, 11, 26, 2017, 7, 19], [1438, 12, 7, 2017, 7, 30], [1438, 12, 18, 2017, 8, 10],
|
||||
[1438, 12, 29, 2017, 8, 21], [1439, 1, 11, 2017, 9, 2], [1439, 1, 22, 2017, 9, 13],
|
||||
[1439, 2, 3, 2017, 9, 24], [1439, 2, 14, 2017, 10, 4], [1439, 2, 25, 2017, 10, 15],
|
||||
[1439, 3, 7, 2017, 10, 26], [1439, 3, 18, 2017, 11, 7], [1439, 3, 29, 2017, 11, 18],
|
||||
[1439, 4, 10, 2017, 11, 29], [1439, 4, 21, 2018, 0, 9], [1439, 5, 3, 2018, 0, 20],
|
||||
[1439, 5, 14, 2018, 0, 31], [1439, 5, 25, 2018, 1, 11], [1439, 6, 6, 2018, 1, 22],
|
||||
[1439, 6, 17, 2018, 2, 5], [1439, 6, 28, 2018, 2, 16], [1439, 7, 10, 2018, 2, 27],
|
||||
[1439, 7, 21, 2018, 3, 7], [1439, 8, 2, 2018, 3, 18], [1439, 8, 13, 2018, 3, 29],
|
||||
[1439, 8, 24, 2018, 4, 10], [1439, 9, 6, 2018, 4, 21], [1439, 9, 17, 2018, 5, 1],
|
||||
[1439, 9, 28, 2018, 5, 12], [1439, 10, 9, 2018, 5, 23], [1439, 10, 20, 2018, 6, 4],
|
||||
[1439, 11, 2, 2018, 6, 15], [1439, 11, 13, 2018, 6, 26], [1439, 11, 24, 2018, 7, 6],
|
||||
[1439, 12, 5, 2018, 7, 17], [1439, 12, 16, 2018, 7, 28], [1439, 12, 27, 2018, 8, 8],
|
||||
[1440, 1, 8, 2018, 8, 19], [1440, 1, 19, 2018, 8, 30], [1440, 1, 30, 2018, 9, 11],
|
||||
[1440, 2, 11, 2018, 9, 22], [1440, 2, 22, 2018, 10, 2], [1440, 3, 4, 2018, 10, 13],
|
||||
[1440, 3, 15, 2018, 10, 24], [1440, 3, 26, 2018, 11, 5], [1440, 4, 7, 2018, 11, 16],
|
||||
[1440, 4, 18, 2018, 11, 27], [1440, 4, 29, 2019, 0, 7], [1440, 5, 11, 2019, 0, 18],
|
||||
[1440, 5, 22, 2019, 0, 29], [1440, 6, 3, 2019, 1, 9], [1440, 6, 14, 2019, 1, 20],
|
||||
[1440, 6, 25, 2019, 2, 3], [1440, 7, 7, 2019, 2, 14], [1440, 7, 18, 2019, 2, 25],
|
||||
[1440, 7, 29, 2019, 3, 5], [1440, 8, 10, 2019, 3, 16], [1440, 8, 21, 2019, 3, 27],
|
||||
[1440, 9, 3, 2019, 4, 8], [1440, 9, 14, 2019, 4, 19], [1440, 9, 25, 2019, 4, 30],
|
||||
[1440, 10, 6, 2019, 5, 10], [1440, 10, 17, 2019, 5, 21], [1440, 10, 28, 2019, 6, 2],
|
||||
[1440, 11, 10, 2019, 6, 13], [1440, 11, 21, 2019, 6, 24], [1440, 12, 2, 2019, 7, 4],
|
||||
[1440, 12, 13, 2019, 7, 15], [1440, 12, 24, 2019, 7, 26], [1441, 1, 6, 2019, 8, 6],
|
||||
[1441, 1, 17, 2019, 8, 17], [1441, 1, 28, 2019, 8, 28], [1441, 2, 9, 2019, 9, 9],
|
||||
[1441, 2, 20, 2019, 9, 20], [1441, 3, 2, 2019, 9, 31], [1441, 3, 13, 2019, 10, 11],
|
||||
[1441, 3, 24, 2019, 10, 22], [1441, 5, 9, 2020, 0, 5], [1441, 5, 20, 2020, 0, 16],
|
||||
[1441, 6, 1, 2020, 0, 27], [1441, 6, 12, 2020, 1, 7], [1441, 6, 23, 2020, 1, 18],
|
||||
[1441, 7, 5, 2020, 1, 29], [1441, 7, 16, 2020, 2, 11], [1441, 7, 27, 2020, 2, 22],
|
||||
[1441, 8, 8, 2020, 3, 2], [1441, 8, 19, 2020, 3, 13], [1441, 9, 1, 2020, 3, 24],
|
||||
[1441, 9, 12, 2020, 4, 5], [1441, 9, 23, 2020, 4, 16], [1441, 10, 4, 2020, 4, 27],
|
||||
[1441, 10, 15, 2020, 5, 7], [1441, 10, 26, 2020, 5, 18], [1441, 11, 8, 2020, 5, 29],
|
||||
[1441, 11, 19, 2020, 6, 10], [1441, 11, 30, 2020, 6, 21], [1441, 12, 11, 2020, 7, 1],
|
||||
[1441, 12, 22, 2020, 7, 12], [1442, 1, 4, 2020, 7, 23], [1442, 1, 15, 2020, 8, 3],
|
||||
[1442, 1, 26, 2020, 8, 14], [1442, 2, 7, 2020, 8, 25], [1442, 2, 18, 2020, 9, 6],
|
||||
[1442, 2, 29, 2020, 9, 17], [1442, 3, 11, 2020, 9, 28], [1442, 3, 22, 2020, 10, 8],
|
||||
[1442, 4, 3, 2020, 10, 19], [1442, 4, 14, 2020, 10, 30], [1442, 5, 18, 2021, 0, 2],
|
||||
[1442, 5, 29, 2021, 0, 13], [1442, 6, 10, 2021, 0, 24], [1442, 6, 21, 2021, 1, 4],
|
||||
[1442, 7, 3, 2021, 1, 15], [1442, 7, 14, 2021, 1, 26], [1442, 7, 25, 2021, 2, 9],
|
||||
[1442, 8, 6, 2021, 2, 20], [1442, 8, 17, 2021, 2, 31], [1442, 8, 28, 2021, 3, 11],
|
||||
[1442, 9, 10, 2021, 3, 22], [1442, 9, 21, 2021, 4, 3], [1442, 10, 2, 2021, 4, 14],
|
||||
[1442, 10, 13, 2021, 4, 25], [1442, 10, 24, 2021, 5, 5], [1442, 11, 6, 2021, 5, 16],
|
||||
[1442, 11, 17, 2021, 5, 27], [1442, 11, 28, 2021, 6, 8], [1442, 12, 9, 2021, 6, 19],
|
||||
[1442, 12, 20, 2021, 6, 30], [1443, 1, 1, 2021, 7, 10], [1443, 1, 12, 2021, 7, 21],
|
||||
[1443, 1, 23, 2021, 8, 1], [1443, 2, 4, 2021, 8, 12], [1443, 2, 15, 2021, 8, 23],
|
||||
[1443, 2, 26, 2021, 9, 4], [1443, 3, 8, 2021, 9, 15], [1443, 3, 19, 2021, 9, 26],
|
||||
[1443, 3, 30, 2021, 10, 6], [1443, 4, 11, 2021, 10, 17], [1443, 4, 22, 2021, 10, 28],
|
||||
[1443, 6, 7, 2022, 0, 11], [1443, 6, 18, 2022, 0, 22], [1443, 6, 29, 2022, 1, 2],
|
||||
[1443, 7, 11, 2022, 1, 13], [1443, 7, 22, 2022, 1, 24], [1443, 8, 3, 2022, 2, 7],
|
||||
[1443, 8, 14, 2022, 2, 18], [1443, 8, 25, 2022, 2, 29], [1443, 9, 7, 2022, 3, 9],
|
||||
[1443, 9, 18, 2022, 3, 20], [1443, 9, 29, 2022, 4, 1], [1443, 10, 10, 2022, 4, 12],
|
||||
[1443, 10, 21, 2022, 4, 23], [1443, 11, 3, 2022, 5, 3], [1443, 11, 14, 2022, 5, 14],
|
||||
[1443, 11, 25, 2022, 5, 25], [1443, 12, 6, 2022, 6, 6], [1443, 12, 17, 2022, 6, 17],
|
||||
[1443, 12, 28, 2022, 6, 28], [1444, 1, 10, 2022, 7, 8], [1444, 1, 21, 2022, 7, 19],
|
||||
[1444, 2, 2, 2022, 7, 30], [1444, 2, 13, 2022, 8, 10], [1444, 2, 24, 2022, 8, 21],
|
||||
[1444, 3, 6, 2022, 9, 2], [1444, 3, 17, 2022, 9, 13], [1444, 3, 28, 2022, 9, 24],
|
||||
[1444, 4, 9, 2022, 10, 4], [1444, 4, 20, 2022, 10, 15], [1444, 5, 2, 2022, 10, 26],
|
||||
[1444, 6, 16, 2023, 0, 9], [1444, 6, 27, 2023, 0, 20], [1444, 7, 9, 2023, 0, 31],
|
||||
[1444, 7, 20, 2023, 1, 11], [1444, 8, 1, 2023, 1, 22], [1444, 8, 12, 2023, 2, 5],
|
||||
[1444, 8, 23, 2023, 2, 16], [1444, 9, 5, 2023, 2, 27], [1444, 9, 16, 2023, 3, 7],
|
||||
[1444, 9, 27, 2023, 3, 18], [1444, 10, 8, 2023, 3, 29], [1444, 10, 19, 2023, 4, 10],
|
||||
[1444, 11, 1, 2023, 4, 21], [1444, 11, 12, 2023, 5, 1], [1444, 11, 23, 2023, 5, 12],
|
||||
[1444, 12, 4, 2023, 5, 23], [1444, 12, 15, 2023, 6, 4], [1444, 12, 26, 2023, 6, 15],
|
||||
[1445, 1, 8, 2023, 6, 26], [1445, 1, 19, 2023, 7, 6], [1445, 1, 30, 2023, 7, 17],
|
||||
[1445, 2, 11, 2023, 7, 28], [1445, 2, 22, 2023, 8, 8], [1445, 3, 4, 2023, 8, 19],
|
||||
[1445, 3, 15, 2023, 8, 30], [1445, 3, 26, 2023, 9, 11], [1445, 4, 7, 2023, 9, 22],
|
||||
[1445, 4, 18, 2023, 10, 2], [1445, 4, 29, 2023, 10, 13], [1445, 5, 11, 2023, 10, 24],
|
||||
[1445, 6, 25, 2024, 0, 7], [1445, 7, 7, 2024, 0, 18], [1445, 7, 18, 2024, 0, 29],
|
||||
[1445, 7, 29, 2024, 1, 9], [1445, 8, 10, 2024, 1, 20], [1445, 8, 21, 2024, 2, 2],
|
||||
[1445, 9, 3, 2024, 2, 13], [1445, 9, 14, 2024, 2, 24], [1445, 9, 25, 2024, 3, 4],
|
||||
[1445, 10, 6, 2024, 3, 15], [1445, 10, 17, 2024, 3, 26], [1445, 10, 28, 2024, 4, 7],
|
||||
[1445, 11, 10, 2024, 4, 18], [1445, 11, 21, 2024, 4, 29], [1445, 12, 2, 2024, 5, 9],
|
||||
[1445, 12, 13, 2024, 5, 20], [1445, 12, 24, 2024, 6, 1], [1446, 1, 5, 2024, 6, 12],
|
||||
[1446, 1, 16, 2024, 6, 23], [1446, 1, 27, 2024, 7, 3], [1446, 2, 8, 2024, 7, 14],
|
||||
[1446, 2, 19, 2024, 7, 25], [1446, 3, 1, 2024, 8, 5], [1446, 3, 12, 2024, 8, 16],
|
||||
[1446, 3, 23, 2024, 8, 27], [1446, 4, 4, 2024, 9, 8], [1446, 4, 15, 2024, 9, 19],
|
||||
[1446, 4, 26, 2024, 9, 30], [1446, 5, 8, 2024, 10, 10], [1446, 5, 19, 2024, 10, 21],
|
||||
[1446, 7, 4, 2025, 0, 4], [1446, 7, 15, 2025, 0, 15], [1446, 7, 26, 2025, 0, 26],
|
||||
[1446, 8, 7, 2025, 1, 6], [1446, 8, 18, 2025, 1, 17], [1446, 8, 29, 2025, 1, 28],
|
||||
[1446, 9, 11, 2025, 2, 11], [1446, 9, 22, 2025, 2, 22], [1446, 10, 3, 2025, 3, 2],
|
||||
[1446, 10, 14, 2025, 3, 13], [1446, 10, 25, 2025, 3, 24], [1446, 11, 7, 2025, 4, 5],
|
||||
[1446, 11, 18, 2025, 4, 16], [1446, 11, 29, 2025, 4, 27], [1446, 12, 10, 2025, 5, 7],
|
||||
[1446, 12, 21, 2025, 5, 18], [1447, 1, 3, 2025, 5, 29], [1447, 1, 14, 2025, 6, 10],
|
||||
[1447, 1, 25, 2025, 6, 21], [1447, 2, 6, 2025, 7, 1], [1447, 2, 17, 2025, 7, 12],
|
||||
[1447, 2, 28, 2025, 7, 23], [1447, 3, 10, 2025, 8, 3], [1447, 3, 21, 2025, 8, 14],
|
||||
[1447, 4, 2, 2025, 8, 25], [1447, 4, 13, 2025, 9, 6], [1447, 4, 24, 2025, 9, 17],
|
||||
[1447, 5, 6, 2025, 9, 28], [1447, 5, 17, 2025, 10, 8], [1447, 5, 28, 2025, 10, 19],
|
||||
[1447, 6, 9, 2025, 10, 30], [1447, 7, 13, 2026, 0, 2], [1447, 7, 24, 2026, 0, 13],
|
||||
[1447, 8, 5, 2026, 0, 24], [1447, 8, 16, 2026, 1, 4], [1447, 8, 27, 2026, 1, 15],
|
||||
[1447, 9, 9, 2026, 1, 26], [1447, 9, 20, 2026, 2, 9], [1447, 10, 1, 2026, 2, 20],
|
||||
[1447, 10, 12, 2026, 2, 31], [1447, 10, 23, 2026, 3, 11], [1447, 11, 5, 2026, 3, 22],
|
||||
[1447, 11, 16, 2026, 4, 3], [1447, 11, 27, 2026, 4, 14], [1447, 12, 8, 2026, 4, 25],
|
||||
[1447, 12, 19, 2026, 5, 5], [1447, 12, 30, 2026, 5, 16], [1448, 1, 11, 2026, 5, 27],
|
||||
[1448, 1, 22, 2026, 6, 8], [1448, 2, 3, 2026, 6, 19], [1448, 2, 14, 2026, 6, 30],
|
||||
[1448, 2, 25, 2026, 7, 10], [1448, 3, 7, 2026, 7, 21], [1448, 3, 18, 2026, 8, 1],
|
||||
[1420, 8, 22, 1999, 11, 1], [1424, 10, 6, 2003, 11, 1], [1428, 11, 21, 2007, 11, 1],
|
||||
[1433, 1, 5, 2011, 11, 1]
|
||||
];
|
||||
|
||||
const calendar = new NgbCalendarIslamicCivilNOA11Y();
|
||||
describe('toGregorian', () => {
|
||||
DATE_TABLE.forEach(element => {
|
||||
let iDate = new NgbDate(element[0], element[1], element[2]);
|
||||
let gDate = new Date(element[3], element[4], element[5]);
|
||||
it('should convert correctly from Hijri to Gregorian',
|
||||
() => { expect(calendar.toGregorian(iDate).getTime()).toEqual(gDate.getTime()); });
|
||||
});
|
||||
});
|
||||
|
||||
describe('fromGregorian', () => {
|
||||
DATE_TABLE.forEach(element => {
|
||||
let iDate = new NgbDate(element[0], element[1], element[2]);
|
||||
const gDate = new Date(element[3], element[4], element[5]);
|
||||
let iDate2 = calendar.fromGregorian(gDate);
|
||||
it('should convert correctly from Gregorian to Hijri', () => { expect(iDate2.equals(iDate)).toBeTruthy(); });
|
||||
});
|
||||
});
|
||||
|
||||
it('should return number of days per week', () => { expect(calendar.getDaysPerWeek()).toBe(7); });
|
||||
|
||||
it('should return number of weeks per month', () => { expect(calendar.getWeeksPerMonth()).toBe(6); });
|
||||
|
||||
it('should return months of a year', () => {
|
||||
expect(calendar.getMonths()).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
|
||||
});
|
||||
|
||||
it('should return day of week', () => {
|
||||
expect(calendar.getWeekday(new NgbDate(1437, 12, 15))).toEqual(7);
|
||||
expect(calendar.getWeekday(new NgbDate(1437, 12, 16))).toEqual(1);
|
||||
expect(calendar.getWeekday(new NgbDate(1437, 12, 17))).toEqual(2);
|
||||
expect(calendar.getWeekday(new NgbDate(1437, 12, 18))).toEqual(3);
|
||||
expect(calendar.getWeekday(new NgbDate(1437, 12, 19))).toEqual(4);
|
||||
expect(calendar.getWeekday(new NgbDate(1437, 12, 20))).toEqual(5);
|
||||
expect(calendar.getWeekday(new NgbDate(1437, 12, 21))).toEqual(6);
|
||||
expect(calendar.getWeekday(new NgbDate(1431, 1, 11))).toEqual(1);
|
||||
expect(calendar.getWeekday(new NgbDate(1431, 7, 22))).toEqual(7);
|
||||
expect(calendar.getWeekday(new NgbDate(1431, 2, 3))).toEqual(2);
|
||||
expect(calendar.getWeekday(new NgbDate(1431, 3, 10))).toEqual(3);
|
||||
expect(calendar.getWeekday(new NgbDate(1431, 4, 23))).toEqual(4);
|
||||
expect(calendar.getWeekday(new NgbDate(1202, 2, 19))).toEqual(5);
|
||||
expect(calendar.getWeekday(new NgbDate(1431, 7, 21))).toEqual(6);
|
||||
});
|
||||
it('should add days to date', () => {
|
||||
expect(calendar.getNext(new NgbDate(1431, 1, 30))).toEqual(new NgbDate(1431, 2, 1));
|
||||
expect(calendar.getNext(new NgbDate(1437, 2, 28))).toEqual(new NgbDate(1437, 2, 29));
|
||||
expect(calendar.getNext(new NgbDate(1437, 2, 29))).toEqual(new NgbDate(1437, 3, 1));
|
||||
});
|
||||
|
||||
it('should subtract days from date', () => {
|
||||
expect(calendar.getPrev(new NgbDate(1431, 2, 1))).toEqual(new NgbDate(1431, 1, 30));
|
||||
expect(calendar.getPrev(new NgbDate(1431, 3, 1))).toEqual(new NgbDate(1431, 2, 29));
|
||||
expect(calendar.getPrev(new NgbDate(1437, 3, 5))).toEqual(new NgbDate(1437, 3, 4));
|
||||
});
|
||||
|
||||
it('should add months to date', () => {
|
||||
expect(calendar.getNext(new NgbDate(1437, 8, 22), 'm')).toEqual(new NgbDate(1437, 9, 1));
|
||||
expect(calendar.getNext(new NgbDate(1437, 8, 1), 'm')).toEqual(new NgbDate(1437, 9, 1));
|
||||
expect(calendar.getNext(new NgbDate(1437, 12, 22), 'm')).toEqual(new NgbDate(1438, 1, 1));
|
||||
});
|
||||
|
||||
it('should subtract months from date', () => {
|
||||
expect(calendar.getPrev(new NgbDate(1437, 8, 22), 'm')).toEqual(new NgbDate(1437, 7, 1));
|
||||
expect(calendar.getPrev(new NgbDate(1437, 9, 1), 'm')).toEqual(new NgbDate(1437, 8, 1));
|
||||
expect(calendar.getPrev(new NgbDate(1437, 1, 22), 'm')).toEqual(new NgbDate(1436, 12, 1));
|
||||
});
|
||||
|
||||
it('should add years to date', () => {
|
||||
expect(calendar.getNext(new NgbDate(1437, 2, 22), 'y')).toEqual(new NgbDate(1438, 1, 1));
|
||||
expect(calendar.getNext(new NgbDate(1438, 12, 22), 'y')).toEqual(new NgbDate(1439, 1, 1));
|
||||
});
|
||||
|
||||
it('should subtract years from date', () => {
|
||||
expect(calendar.getPrev(new NgbDate(1437, 12, 22), 'y')).toEqual(new NgbDate(1436, 1, 1));
|
||||
expect(calendar.getPrev(new NgbDate(1438, 2, 22), 'y')).toEqual(new NgbDate(1437, 1, 1));
|
||||
});
|
||||
|
||||
it('should return week number', () => {
|
||||
let week = [
|
||||
new NgbDate(1437, 1, 4), new NgbDate(1437, 1, 5), new NgbDate(1437, 1, 6), new NgbDate(1437, 1, 7),
|
||||
new NgbDate(1437, 1, 8), new NgbDate(1437, 1, 9), new NgbDate(1437, 1, 10)
|
||||
];
|
||||
expect(calendar.getWeekNumber(week, 7)).toEqual(2);
|
||||
week = [
|
||||
new NgbDate(1437, 12, 15), new NgbDate(1437, 12, 16), new NgbDate(1437, 12, 17), new NgbDate(1437, 12, 18),
|
||||
new NgbDate(1437, 12, 19), new NgbDate(1437, 12, 20), new NgbDate(1437, 12, 21)
|
||||
];
|
||||
expect(calendar.getWeekNumber(week, 7)).toEqual(50);
|
||||
week = [
|
||||
new NgbDate(1437, 12, 22), new NgbDate(1437, 12, 23), new NgbDate(1437, 12, 24), new NgbDate(1437, 12, 25),
|
||||
new NgbDate(1437, 12, 26), new NgbDate(1437, 12, 27), new NgbDate(1437, 12, 28)
|
||||
];
|
||||
expect(calendar.getWeekNumber(week, 7)).toEqual(51);
|
||||
});
|
||||
|
||||
describe('setDay', () => {
|
||||
it('should return correct value of day', () => {
|
||||
expect(calendar.setDay(new NgbDate(1202, 9, 1), 19).day).toEqual(19);
|
||||
expect(calendar.setDay(new NgbDate(1431, 1, 1), 1).day).toEqual(1);
|
||||
expect(calendar.setDay(new NgbDate(1431, 1, 1), 31).day).toEqual(1);
|
||||
expect(calendar.setDay(new NgbDate(1437, 1, 1), 61).day).toEqual(2);
|
||||
expect(calendar.setDay(new NgbDate(1431, 2, 1), 0).day).toEqual(30);
|
||||
expect(calendar.setDay(new NgbDate(1431, 2, 1), -1).day).toEqual(29);
|
||||
expect(calendar.setDay(new NgbDate(1431, 2, 1), -2).day).toEqual(28);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setMonth', () => {
|
||||
it('should return correct value of month', () => {
|
||||
expect(calendar.setMonth(new NgbDate(1202, 9, 1), 9).month).toEqual(9);
|
||||
expect(calendar.setMonth(new NgbDate(1431, 1, 30), 1).month).toEqual(1);
|
||||
expect(calendar.setDay(new NgbDate(1431, 1, 1), 31).month).toEqual(2);
|
||||
expect(calendar.setDay(new NgbDate(1437, 1, 1), 61).month).toEqual(3);
|
||||
expect(calendar.setDay(new NgbDate(1431, 2, 1), -1).month).toEqual(1);
|
||||
expect(calendar.setDay(new NgbDate(1431, 2, 1), -30).month).toEqual(12);
|
||||
expect(calendar.setMonth(new NgbDate(1431, 1, 1), 0).month).toEqual(12);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setYear', () => {
|
||||
it('should return correct value of yar', () => {
|
||||
expect(calendar.setYear(new NgbDate(1200, 1, 1), 1202).year).toEqual(1202);
|
||||
expect(calendar.setYear(new NgbDate(1430, 11, 30), 1431).year).toEqual(1431);
|
||||
expect(calendar.setDay(new NgbDate(1431, 12, 1), 31).year).toEqual(1432);
|
||||
expect(calendar.setMonth(new NgbDate(1431, 1, 1), 13).year).toEqual(1432);
|
||||
expect(calendar.setMonth(new NgbDate(1431, 1, 1), 25).year).toEqual(1433);
|
||||
expect(calendar.setDay(new NgbDate(1431, 1, 1), -1).year).toEqual(1430);
|
||||
expect(calendar.setMonth(new NgbDate(1431, 1, 1), 0).year).toEqual(1430);
|
||||
expect(calendar.setMonth(new NgbDate(1431, 1, 1), -13).year).toEqual(1429);
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,153 @@
|
||||
import {NgbCalendarHijriNOA11Y} from './ngb-calendar-hijri';
|
||||
import {NgbDate} from '../ngb-date';
|
||||
import {NgbPeriodNOA11Y} from '../ngb-calendar';
|
||||
import {Injectable} from '@angular/core';
|
||||
|
||||
function isGregorianLeapYear(date: Date): boolean {
|
||||
const year = date.getFullYear();
|
||||
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
||||
}
|
||||
|
||||
function mod(a: number, b: number): number {
|
||||
return a - b * Math.floor(a / b);
|
||||
}
|
||||
|
||||
/**
|
||||
* The civil calendar is one type of Hijri calendars used in islamic countries.
|
||||
* Uses a fixed cycle of alternating 29- and 30-day months,
|
||||
* with a leap day added to the last month of 11 out of every 30 years.
|
||||
* http://cldr.unicode.org/development/development-process/design-proposals/islamic-calendar-types
|
||||
* All the calculations here are based on the equations from "Calendrical Calculations" By Edward M. Reingold, Nachum
|
||||
* Dershowitz.
|
||||
*/
|
||||
|
||||
const GREGORIAN_EPOCH = 1721425.5;
|
||||
const ISLAMIC_EPOCH = 1948439.5;
|
||||
|
||||
@Injectable()
|
||||
export class NgbCalendarIslamicCivilNOA11Y extends NgbCalendarHijriNOA11Y {
|
||||
/**
|
||||
* Returns the equivalent islamic(civil) date value for a give input Gregorian date.
|
||||
* `gdate` is a JS Date to be converted to Hijri.
|
||||
*/
|
||||
fromGregorian(gdate: Date): NgbDate {
|
||||
const date = new Date(gdate);
|
||||
const gYear = date.getFullYear(), gMonth = date.getMonth(), gDay = date.getDate();
|
||||
|
||||
let julianDay = GREGORIAN_EPOCH - 1 + 365 * (gYear - 1) + Math.floor((gYear - 1) / 4) +
|
||||
-Math.floor((gYear - 1) / 100) + Math.floor((gYear - 1) / 400) +
|
||||
Math.floor(
|
||||
(367 * (gMonth + 1) - 362) / 12 + (gMonth + 1 <= 2 ? 0 : isGregorianLeapYear(date) ? -1 : -2) + gDay);
|
||||
julianDay = Math.floor(julianDay) + 0.5;
|
||||
|
||||
const days = julianDay - ISLAMIC_EPOCH;
|
||||
const hYear = Math.floor((30 * days + 10646) / 10631.0);
|
||||
let hMonth = Math.ceil((days - 29 - this._getYearStart(hYear)) / 29.5);
|
||||
hMonth = Math.min(hMonth, 11);
|
||||
const hDay = Math.ceil(days - this._getMonthStart(hYear, hMonth)) + 1;
|
||||
return new NgbDate(hYear, hMonth + 1, hDay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the equivalent JS date value for a give input islamic(civil) date.
|
||||
* `hijriDate` is an islamic(civil) date to be converted to Gregorian.
|
||||
*/
|
||||
toGregorian(hijriDate: NgbDate): Date {
|
||||
const hYear = hijriDate.year;
|
||||
const hMonth = hijriDate.month - 1;
|
||||
const hDate = hijriDate.day;
|
||||
const julianDay =
|
||||
hDate + Math.ceil(29.5 * hMonth) + (hYear - 1) * 354 + Math.floor((3 + 11 * hYear) / 30) + ISLAMIC_EPOCH - 1;
|
||||
|
||||
const wjd = Math.floor(julianDay - 0.5) + 0.5, depoch = wjd - GREGORIAN_EPOCH,
|
||||
quadricent = Math.floor(depoch / 146097), dqc = mod(depoch, 146097), cent = Math.floor(dqc / 36524),
|
||||
dcent = mod(dqc, 36524), quad = Math.floor(dcent / 1461), dquad = mod(dcent, 1461),
|
||||
yindex = Math.floor(dquad / 365);
|
||||
let year = quadricent * 400 + cent * 100 + quad * 4 + yindex;
|
||||
if (!(cent === 4 || yindex === 4)) {
|
||||
year++;
|
||||
}
|
||||
|
||||
const gYearStart = GREGORIAN_EPOCH + 365 * (year - 1) + Math.floor((year - 1) / 4) - Math.floor((year - 1) / 100) +
|
||||
Math.floor((year - 1) / 400);
|
||||
|
||||
const yearday = wjd - gYearStart;
|
||||
|
||||
const tjd = GREGORIAN_EPOCH - 1 + 365 * (year - 1) + Math.floor((year - 1) / 4) - Math.floor((year - 1) / 100) +
|
||||
Math.floor((year - 1) / 400) + Math.floor(739 / 12 + (isGregorianLeapYear(new Date(year, 3, 1)) ? -1 : -2) + 1);
|
||||
|
||||
const leapadj = wjd < tjd ? 0 : isGregorianLeapYear(new Date(year, 3, 1)) ? 1 : 2;
|
||||
|
||||
const month = Math.floor(((yearday + leapadj) * 12 + 373) / 367);
|
||||
const tjd2 = GREGORIAN_EPOCH - 1 + 365 * (year - 1) + Math.floor((year - 1) / 4) - Math.floor((year - 1) / 100) +
|
||||
Math.floor((year - 1) / 400) +
|
||||
Math.floor(
|
||||
(367 * month - 362) / 12 + (month <= 2 ? 0 : isGregorianLeapYear(new Date(year, month - 1, 1)) ? -1 : -2) +
|
||||
1);
|
||||
|
||||
const day = wjd - tjd2 + 1;
|
||||
|
||||
return new Date(year, month - 1, day);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of days in a specific Hijri month.
|
||||
* `month` is 1 for Muharram, 2 for Safar, etc.
|
||||
* `year` is any Hijri year.
|
||||
*/
|
||||
getDaysInIslamicMonth(month: number, year: number): number {
|
||||
year = year + Math.floor(month / 13);
|
||||
month = ((month - 1) % 12) + 1;
|
||||
let length = 29 + month % 2;
|
||||
if (month === 12 && this._isIslamicLeapYear(year)) {
|
||||
length++;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
getNext(date: NgbDate, period: NgbPeriodNOA11Y = 'd', number = 1) {
|
||||
date = NgbDate.from(date);
|
||||
|
||||
switch (period) {
|
||||
case 'y':
|
||||
date = this.setYear(date, date.year + number);
|
||||
date.month = 1;
|
||||
date.day = 1;
|
||||
return date;
|
||||
case 'm':
|
||||
date = this.setMonth(date, date.month + number);
|
||||
date.day = 1;
|
||||
return date;
|
||||
case 'd':
|
||||
return this.setDay(date, date.day + number);
|
||||
default:
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
getPrev(date: NgbDate, period: NgbPeriodNOA11Y = 'd', number = 1) { return this.getNext(date, period, -number); }
|
||||
|
||||
getWeekday(date: NgbDate) {
|
||||
const day = this.toGregorian(date).getDay();
|
||||
// in JS Date Sun=0, in ISO 8601 Sun=7
|
||||
return day === 0 ? 7 : day;
|
||||
}
|
||||
|
||||
getWeekNumber(week: NgbDate[], firstDayOfWeek: number) {
|
||||
// in JS Date Sun=0, in ISO 8601 Sun=7
|
||||
if (firstDayOfWeek === 7) {
|
||||
firstDayOfWeek = 0;
|
||||
}
|
||||
|
||||
const thursdayIndex = (4 + 7 - firstDayOfWeek) % 7;
|
||||
const date = week[thursdayIndex];
|
||||
|
||||
const jsDate = this.toGregorian(date);
|
||||
jsDate.setDate(jsDate.getDate() + 4 - (jsDate.getDay() || 7)); // Thursday
|
||||
const time = jsDate.getTime();
|
||||
const MuhDate = this.toGregorian(new NgbDate(date.year, 1, 1)); // Compare with Muharram 1
|
||||
return Math.floor(Math.round((time - MuhDate.getTime()) / 86400000) / 7) + 1;
|
||||
}
|
||||
|
||||
getToday(): NgbDate { return this.fromGregorian(new Date()); }
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
import {NgbDate} from './ngb-date';
|
||||
import {Injectable} from '@angular/core';
|
||||
import {isInteger} from '../util/util';
|
||||
|
||||
function fromJSDate(jsDate: Date) {
|
||||
return new NgbDate(jsDate.getFullYear(), jsDate.getMonth() + 1, jsDate.getDate());
|
||||
}
|
||||
function toJSDate(date: NgbDate) {
|
||||
const jsDate = new Date(date.year, date.month - 1, date.day, 12);
|
||||
// this is done avoid 30 -> 1930 conversion
|
||||
if (!isNaN(jsDate.getTime())) {
|
||||
jsDate.setFullYear(date.year);
|
||||
}
|
||||
return jsDate;
|
||||
}
|
||||
|
||||
export type NgbPeriodNOA11Y = 'y' | 'm' | 'd';
|
||||
|
||||
@Injectable()
|
||||
export abstract class NgbCalendarNOA11Y {
|
||||
abstract getDaysPerWeek(): number;
|
||||
abstract getMonths(): number[];
|
||||
abstract getWeeksPerMonth(): number;
|
||||
abstract getWeekday(date: NgbDate): number;
|
||||
|
||||
abstract getNext(date: NgbDate, period?: NgbPeriodNOA11Y, number?: number): NgbDate;
|
||||
abstract getPrev(date: NgbDate, period?: NgbPeriodNOA11Y, number?: number): NgbDate;
|
||||
|
||||
abstract getWeekNumber(week: NgbDate[], firstDayOfWeek: number): number;
|
||||
|
||||
abstract getToday(): NgbDate;
|
||||
|
||||
abstract isValid(date: NgbDate): boolean;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class NgbCalendarGregorianNOA11Y extends NgbCalendarNOA11Y {
|
||||
getDaysPerWeek() { return 7; }
|
||||
|
||||
getMonths() { return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; }
|
||||
|
||||
getWeeksPerMonth() { return 6; }
|
||||
|
||||
getNext(date: NgbDate, period: NgbPeriodNOA11Y = 'd', number = 1) {
|
||||
let jsDate = toJSDate(date);
|
||||
switch (period) {
|
||||
case 'y':
|
||||
return new NgbDate(date.year + number, 1, 1);
|
||||
case 'm':
|
||||
jsDate = new Date(date.year, date.month + number - 1, 1, 12);
|
||||
break;
|
||||
case 'd':
|
||||
jsDate.setDate(jsDate.getDate() + number);
|
||||
break;
|
||||
default:
|
||||
return date;
|
||||
}
|
||||
|
||||
return fromJSDate(jsDate);
|
||||
}
|
||||
|
||||
getPrev(date: NgbDate, period: NgbPeriodNOA11Y = 'd', number = 1) { return this.getNext(date, period, -number); }
|
||||
|
||||
getWeekday(date: NgbDate) {
|
||||
let jsDate = toJSDate(date);
|
||||
let day = jsDate.getDay();
|
||||
// in JS Date Sun=0, in ISO 8601 Sun=7
|
||||
return day === 0 ? 7 : day;
|
||||
}
|
||||
|
||||
getWeekNumber(week: NgbDate[], firstDayOfWeek: number) {
|
||||
// in JS Date Sun=0, in ISO 8601 Sun=7
|
||||
if (firstDayOfWeek === 7) {
|
||||
firstDayOfWeek = 0;
|
||||
}
|
||||
|
||||
const thursdayIndex = (4 + 7 - firstDayOfWeek) % 7;
|
||||
let date = week[thursdayIndex];
|
||||
|
||||
const jsDate = toJSDate(date);
|
||||
jsDate.setDate(jsDate.getDate() + 4 - (jsDate.getDay() || 7)); // Thursday
|
||||
const time = jsDate.getTime();
|
||||
jsDate.setMonth(0); // Compare with Jan 1
|
||||
jsDate.setDate(1);
|
||||
return Math.floor(Math.round((time - jsDate.getTime()) / 86400000) / 7) + 1;
|
||||
}
|
||||
|
||||
getToday(): NgbDate { return fromJSDate(new Date()); }
|
||||
|
||||
isValid(date: NgbDate): boolean {
|
||||
if (!date || !isInteger(date.year) || !isInteger(date.month) || !isInteger(date.day)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const jsDate = toJSDate(date);
|
||||
|
||||
return !isNaN(jsDate.getTime()) && jsDate.getFullYear() === date.year && jsDate.getMonth() + 1 === date.month &&
|
||||
jsDate.getDate() === date.day;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
export interface NgbDataTemplateStruct {
|
||||
/**
|
||||
* Il template selezionato
|
||||
*/
|
||||
template: number;
|
||||
|
||||
/**
|
||||
* Il numero del giorno
|
||||
*/
|
||||
day: number;
|
||||
|
||||
/**
|
||||
* Il numero del mese
|
||||
*/
|
||||
month: number;
|
||||
|
||||
/**
|
||||
* Il numero dell'anno
|
||||
*/
|
||||
year: number;
|
||||
/**
|
||||
* Se i dati sono validi o meno
|
||||
*/
|
||||
valid: boolean;
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
import { NbpCalendarPattern, NbpDateSeparator } from '../../nbp-calendar-generic.enum';
|
||||
import {padNumber, toInteger, isNumber} from '../util/util';
|
||||
import {NgbDateStruct} from './ngb-date-struct';
|
||||
|
||||
/**
|
||||
* Abstract type serving as a DI token for the service parsing and formatting dates for the NgbInputDatepicker
|
||||
* directive. A default implementation using the ISO 8601 format is provided, but you can provide another implementation
|
||||
* to use an alternative format.
|
||||
*/
|
||||
export abstract class NgbDateParserFormatterNOA11Y {
|
||||
/**
|
||||
* Parses the given value to an NgbDateStruct. Implementations should try their best to provide a result, even
|
||||
* partial. They must return null if the value can't be parsed.
|
||||
* @param value the value to parse
|
||||
*/
|
||||
abstract parse(value: string, pattern?: NbpCalendarPattern): NgbDateStruct;
|
||||
|
||||
/**
|
||||
* Formats the given date to a string. Implementations should return an empty string if the given date is null,
|
||||
* and try their best to provide a partial result if the given date is incomplete or invalid.
|
||||
* @param date the date to format as a string
|
||||
*/
|
||||
abstract format(date: NgbDateStruct, pattern?: NbpCalendarPattern, separator?: NbpDateSeparator): string;
|
||||
}
|
||||
|
||||
export class NgbDateISOParserFormatterNOA11Y extends NgbDateParserFormatterNOA11Y {
|
||||
parse(value: string): NgbDateStruct {
|
||||
if (value) {
|
||||
const dateParts = value.trim().split('-');
|
||||
if (dateParts.length === 1 && isNumber(dateParts[0])) {
|
||||
return {year: toInteger(dateParts[0]), month: null, day: null};
|
||||
} else if (dateParts.length === 2 && isNumber(dateParts[0]) && isNumber(dateParts[1])) {
|
||||
return {year: toInteger(dateParts[0]), month: toInteger(dateParts[1]), day: null};
|
||||
} else if (dateParts.length === 3 && isNumber(dateParts[0]) && isNumber(dateParts[1]) && isNumber(dateParts[2])) {
|
||||
return {year: toInteger(dateParts[0]), month: toInteger(dateParts[1]), day: toInteger(dateParts[2])};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
format(date: NgbDateStruct): string {
|
||||
return date ?
|
||||
`${date.year}-${isNumber(date.month) ? padNumber(date.month) : ''}-${isNumber(date.day) ? padNumber(date.day) : ''}` :
|
||||
'';
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Interface of the model of the NgbDatepicker and NgbInputDatepicker directives
|
||||
*/
|
||||
export interface NgbDateStruct {
|
||||
/**
|
||||
* The year, for example 2016
|
||||
*/
|
||||
year: number;
|
||||
|
||||
/**
|
||||
* The month, with default calendar we use ISO 8601: 1=Jan ... 12=Dec
|
||||
*/
|
||||
month: number;
|
||||
|
||||
/**
|
||||
* The day of month, starting at 1
|
||||
*/
|
||||
day: number;
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
export class NgbDate {
|
||||
static from(date: {year: number, month: number, day?: number}) {
|
||||
return date ? new NgbDate(date.year, date.month, date.day ? date.day : 1) : null;
|
||||
}
|
||||
|
||||
constructor(public year: number, public month: number, public day: number) {}
|
||||
|
||||
equals(other: NgbDate) {
|
||||
return other && this.year === other.year && this.month === other.month && this.day === other.day;
|
||||
}
|
||||
|
||||
before(other: NgbDate) {
|
||||
if (!other) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.year === other.year) {
|
||||
if (this.month === other.month) {
|
||||
return this.day === other.day ? false : this.day < other.day;
|
||||
} else {
|
||||
return this.month < other.month;
|
||||
}
|
||||
} else {
|
||||
return this.year < other.year;
|
||||
}
|
||||
}
|
||||
|
||||
after(other: NgbDate) {
|
||||
if (!other) {
|
||||
return false;
|
||||
}
|
||||
if (this.year === other.year) {
|
||||
if (this.month === other.month) {
|
||||
return this.day === other.day ? false : this.day > other.day;
|
||||
} else {
|
||||
return this.month > other.month;
|
||||
}
|
||||
} else {
|
||||
return this.year > other.year;
|
||||
}
|
||||
}
|
||||
|
||||
toStruct() { return {year: this.year, month: this.month, day: this.day}; }
|
||||
|
||||
toString() { return `${this.year}-${this.month}-${this.day}`; }
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Interface of the model of the NgbDatepicker and NgbInputDatepicker directives
|
||||
*/
|
||||
export interface NgbMeseStruct {
|
||||
/**
|
||||
* Il nome del mese
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Il numero del mese
|
||||
*/
|
||||
number: number;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Interface of the model of the NgbDatepicker and NgbInputDatepicker directives
|
||||
*/
|
||||
export interface NgbYearStruct {
|
||||
/**
|
||||
* Il nome del mese
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Il numero del mese
|
||||
*/
|
||||
number: number;
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
import {
|
||||
Injector,
|
||||
TemplateRef,
|
||||
ViewRef,
|
||||
ViewContainerRef,
|
||||
Renderer2,
|
||||
ComponentRef,
|
||||
ComponentFactory,
|
||||
ComponentFactoryResolver
|
||||
} from '@angular/core';
|
||||
|
||||
export class ContentRef {
|
||||
constructor(public nodes: any[], public viewRef?: ViewRef, public componentRef?: ComponentRef<any>) {}
|
||||
}
|
||||
|
||||
export class PopupService<T> {
|
||||
private _windowFactory: ComponentFactory<T>;
|
||||
private _windowRef: ComponentRef<T>;
|
||||
private _contentRef: ContentRef;
|
||||
|
||||
constructor(
|
||||
type: any, private _injector: Injector, private _viewContainerRef: ViewContainerRef, private _renderer: Renderer2,
|
||||
componentFactoryResolver: ComponentFactoryResolver) {
|
||||
this._windowFactory = componentFactoryResolver.resolveComponentFactory<T>(type);
|
||||
}
|
||||
|
||||
open(content?: string | TemplateRef<any>, context?: any): ComponentRef<T> {
|
||||
if (!this._windowRef) {
|
||||
this._contentRef = this._getContentRef(content, context);
|
||||
this._windowRef =
|
||||
this._viewContainerRef.createComponent(this._windowFactory, 0, this._injector, this._contentRef.nodes);
|
||||
}
|
||||
|
||||
return this._windowRef;
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this._windowRef) {
|
||||
this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._windowRef.hostView));
|
||||
this._windowRef = null;
|
||||
|
||||
if (this._contentRef.viewRef) {
|
||||
this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._contentRef.viewRef));
|
||||
this._contentRef = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _getContentRef(content: string | TemplateRef<any>, context?: any): ContentRef {
|
||||
if (!content) {
|
||||
return new ContentRef([]);
|
||||
} else if (content instanceof TemplateRef) {
|
||||
const viewRef = this._viewContainerRef.createEmbeddedView(<TemplateRef<T>>content, context);
|
||||
return new ContentRef([viewRef.rootNodes], viewRef);
|
||||
} else {
|
||||
return new ContentRef([[this._renderer.createText(`${content}`)]]);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
import {Positioning} from './positioning';
|
||||
|
||||
describe('Positioning', () => {
|
||||
const positioning = new Positioning();
|
||||
const documentMargin = document.documentElement.style.margin;
|
||||
const bodyMargin = document.body.style.margin;
|
||||
const bodyHeight = document.body.style.height;
|
||||
const bodyWidth = document.body.style.width;
|
||||
|
||||
function createElement(height: number, width: number, marginTop: number, marginLeft: number): HTMLElement {
|
||||
let element = document.createElement('div');
|
||||
element.style.display = 'inline-block';
|
||||
element.style.height = height + 'px';
|
||||
element.style.width = width + 'px';
|
||||
element.style.marginTop = marginTop + 'px';
|
||||
element.style.marginLeft = marginLeft + 'px';
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
let element = createElement(200, 300, 100, 150);
|
||||
document.body.appendChild(element);
|
||||
let targetElement = createElement(50, 100, 10, 20);
|
||||
document.body.appendChild(targetElement);
|
||||
|
||||
document.documentElement.style.margin = '0';
|
||||
document.body.style.margin = '0';
|
||||
document.body.style.height = '2000px';
|
||||
document.body.style.width = '2000px';
|
||||
|
||||
it('should calculate the element offset', () => {
|
||||
let position = positioning.offset(element);
|
||||
|
||||
expect(position.height).toBe(200);
|
||||
expect(position.width).toBe(300);
|
||||
expect(position.top).toBe(100);
|
||||
expect(position.bottom).toBe(300);
|
||||
expect(position.left).toBe(150);
|
||||
expect(position.right).toBe(450);
|
||||
});
|
||||
|
||||
it('should calculate the element offset when scrolled', () => {
|
||||
document.documentElement.scrollTop = 1000;
|
||||
document.documentElement.scrollLeft = 1000;
|
||||
|
||||
let position = positioning.offset(element);
|
||||
|
||||
expect(position.top).toBe(100);
|
||||
expect(position.bottom).toBe(300);
|
||||
expect(position.left).toBe(150);
|
||||
expect(position.right).toBe(450);
|
||||
|
||||
document.documentElement.scrollTop = 0;
|
||||
document.documentElement.scrollLeft = 0;
|
||||
});
|
||||
|
||||
it('should calculate the element position', () => {
|
||||
let position = positioning.position(element);
|
||||
|
||||
expect(position.height).toBe(200);
|
||||
expect(position.width).toBe(300);
|
||||
expect(position.top).toBe(100);
|
||||
expect(position.bottom).toBe(300);
|
||||
expect(position.left).toBe(150);
|
||||
expect(position.right).toBe(450);
|
||||
});
|
||||
|
||||
it('should calculate the element position when scrolled', () => {
|
||||
document.documentElement.scrollTop = 1000;
|
||||
document.documentElement.scrollLeft = 1000;
|
||||
|
||||
let position = positioning.position(element);
|
||||
|
||||
expect(position.top).toBe(100);
|
||||
expect(position.bottom).toBe(300);
|
||||
expect(position.left).toBe(150);
|
||||
expect(position.right).toBe(450);
|
||||
|
||||
document.documentElement.scrollTop = 0;
|
||||
document.documentElement.scrollLeft = 0;
|
||||
});
|
||||
|
||||
it('should calculate the element position on positioned ancestor', () => {
|
||||
let childElement = createElement(100, 150, 50, 75);
|
||||
|
||||
element.style.position = 'relative';
|
||||
element.appendChild(childElement);
|
||||
|
||||
let position = positioning.position(childElement);
|
||||
|
||||
expect(position.top).toBe(50);
|
||||
expect(position.bottom).toBe(150);
|
||||
expect(position.left).toBe(75);
|
||||
expect(position.right).toBe(225);
|
||||
|
||||
element.style.position = '';
|
||||
element.removeChild(childElement);
|
||||
});
|
||||
|
||||
it('should position the element top-left', () => {
|
||||
let position = positioning.positionElements(element, targetElement, 'top-left');
|
||||
|
||||
expect(position.top).toBe(50);
|
||||
expect(position.left).toBe(150);
|
||||
});
|
||||
|
||||
it('should position the element top-center', () => {
|
||||
let position = positioning.positionElements(element, targetElement, 'top');
|
||||
|
||||
expect(position.top).toBe(50);
|
||||
expect(position.left).toBe(250);
|
||||
});
|
||||
|
||||
it('should position the element top-right', () => {
|
||||
let position = positioning.positionElements(element, targetElement, 'top-right');
|
||||
|
||||
expect(position.top).toBe(50);
|
||||
expect(position.left).toBe(350);
|
||||
});
|
||||
|
||||
it('should position the element bottom-left', () => {
|
||||
let position = positioning.positionElements(element, targetElement, 'bottom-left');
|
||||
|
||||
expect(position.top).toBe(300);
|
||||
expect(position.left).toBe(150);
|
||||
});
|
||||
|
||||
it('should position the element bottom-center', () => {
|
||||
let position = positioning.positionElements(element, targetElement, 'bottom');
|
||||
|
||||
expect(position.top).toBe(300);
|
||||
expect(position.left).toBe(250);
|
||||
});
|
||||
|
||||
it('should position the element bottom-right', () => {
|
||||
let position = positioning.positionElements(element, targetElement, 'bottom-right');
|
||||
|
||||
expect(position.top).toBe(300);
|
||||
expect(position.left).toBe(350);
|
||||
});
|
||||
|
||||
it('should position the element left-top', () => {
|
||||
let position = positioning.positionElements(element, targetElement, 'left-top');
|
||||
|
||||
expect(position.top).toBe(100);
|
||||
expect(position.left).toBe(50);
|
||||
});
|
||||
|
||||
it('should position the element left-center', () => {
|
||||
let position = positioning.positionElements(element, targetElement, 'left');
|
||||
|
||||
expect(position.top).toBe(175);
|
||||
expect(position.left).toBe(50);
|
||||
});
|
||||
|
||||
it('should position the element left-bottom', () => {
|
||||
let position = positioning.positionElements(element, targetElement, 'left-bottom');
|
||||
|
||||
expect(position.top).toBe(250);
|
||||
expect(position.left).toBe(50);
|
||||
});
|
||||
|
||||
it('should position the element right-top', () => {
|
||||
let position = positioning.positionElements(element, targetElement, 'right-top');
|
||||
|
||||
expect(position.top).toBe(100);
|
||||
expect(position.left).toBe(450);
|
||||
});
|
||||
|
||||
it('should position the element right-center', () => {
|
||||
let position = positioning.positionElements(element, targetElement, 'right');
|
||||
|
||||
expect(position.top).toBe(175);
|
||||
expect(position.left).toBe(450);
|
||||
});
|
||||
|
||||
it('should position the element right-bottom', () => {
|
||||
let position = positioning.positionElements(element, targetElement, 'right-bottom');
|
||||
|
||||
expect(position.top).toBe(250);
|
||||
expect(position.left).toBe(450);
|
||||
});
|
||||
|
||||
it('cleanUp', () => {
|
||||
document.body.removeChild(element);
|
||||
document.body.removeChild(targetElement);
|
||||
document.documentElement.style.margin = documentMargin;
|
||||
document.body.style.margin = bodyMargin;
|
||||
document.body.style.height = bodyHeight;
|
||||
document.body.style.width = bodyWidth;
|
||||
});
|
||||
});
|
@ -0,0 +1,151 @@
|
||||
// previous version:
|
||||
// https://github.com/angular-ui/bootstrap/blob/07c31d0731f7cb068a1932b8e01d2312b796b4ec/src/position/position.js
|
||||
export class Positioning {
|
||||
private getStyle(element: HTMLElement, prop: string): string { return window.getComputedStyle(element)[prop]; }
|
||||
|
||||
private isStaticPositioned(element: HTMLElement): boolean {
|
||||
return (this.getStyle(element, 'position') || 'static') === 'static';
|
||||
}
|
||||
|
||||
private offsetParent(element: HTMLElement): HTMLElement {
|
||||
let offsetParentEl = <HTMLElement>element.offsetParent || document.documentElement;
|
||||
|
||||
while (offsetParentEl && offsetParentEl !== document.documentElement && this.isStaticPositioned(offsetParentEl)) {
|
||||
offsetParentEl = <HTMLElement>offsetParentEl.offsetParent;
|
||||
}
|
||||
|
||||
return offsetParentEl || document.documentElement;
|
||||
}
|
||||
|
||||
position(element: HTMLElement, round = true): ClientRect {
|
||||
let elPosition: ClientRect;
|
||||
let parentOffset: ClientRect = {width: 0, height: 0, top: 0, bottom: 0, left: 0, right: 0};
|
||||
|
||||
if (this.getStyle(element, 'position') === 'fixed') {
|
||||
elPosition = element.getBoundingClientRect();
|
||||
} else {
|
||||
const offsetParentEl = this.offsetParent(element);
|
||||
|
||||
elPosition = this.offset(element, false);
|
||||
|
||||
if (offsetParentEl !== document.documentElement) {
|
||||
parentOffset = this.offset(offsetParentEl, false);
|
||||
}
|
||||
|
||||
parentOffset.top += offsetParentEl.clientTop;
|
||||
parentOffset.left += offsetParentEl.clientLeft;
|
||||
}
|
||||
|
||||
elPosition.top -= parentOffset.top;
|
||||
elPosition.bottom -= parentOffset.top;
|
||||
elPosition.left -= parentOffset.left;
|
||||
elPosition.right -= parentOffset.left;
|
||||
|
||||
if (round) {
|
||||
elPosition.top = Math.round(elPosition.top);
|
||||
elPosition.bottom = Math.round(elPosition.bottom);
|
||||
elPosition.left = Math.round(elPosition.left);
|
||||
elPosition.right = Math.round(elPosition.right);
|
||||
}
|
||||
|
||||
return elPosition;
|
||||
}
|
||||
|
||||
offset(element: HTMLElement, round = true): ClientRect {
|
||||
const elBcr = element.getBoundingClientRect();
|
||||
const viewportOffset = {
|
||||
top: window.pageYOffset - document.documentElement.clientTop,
|
||||
left: window.pageXOffset - document.documentElement.clientLeft
|
||||
};
|
||||
|
||||
let elOffset = {
|
||||
height: elBcr.height || element.offsetHeight,
|
||||
width: elBcr.width || element.offsetWidth,
|
||||
top: elBcr.top + viewportOffset.top,
|
||||
bottom: elBcr.bottom + viewportOffset.top,
|
||||
left: elBcr.left + viewportOffset.left,
|
||||
right: elBcr.right + viewportOffset.left
|
||||
};
|
||||
|
||||
if (round) {
|
||||
elOffset.height = Math.round(elOffset.height);
|
||||
elOffset.width = Math.round(elOffset.width);
|
||||
elOffset.top = Math.round(elOffset.top);
|
||||
elOffset.bottom = Math.round(elOffset.bottom);
|
||||
elOffset.left = Math.round(elOffset.left);
|
||||
elOffset.right = Math.round(elOffset.right);
|
||||
}
|
||||
|
||||
return elOffset;
|
||||
}
|
||||
|
||||
positionElements(hostElement: HTMLElement, targetElement: HTMLElement, placement: string, appendToBody?: boolean):
|
||||
ClientRect {
|
||||
const hostElPosition = appendToBody ? this.offset(hostElement, false) : this.position(hostElement, false);
|
||||
const targetElBCR = targetElement.getBoundingClientRect();
|
||||
const placementPrimary = placement.split('-')[0] || 'top';
|
||||
const placementSecondary = placement.split('-')[1] || 'center';
|
||||
|
||||
let targetElPosition: ClientRect = {
|
||||
'height': targetElBCR.height || targetElement.offsetHeight,
|
||||
'width': targetElBCR.width || targetElement.offsetWidth,
|
||||
'top': 0,
|
||||
'bottom': targetElBCR.height || targetElement.offsetHeight,
|
||||
'left': 0,
|
||||
'right': targetElBCR.width || targetElement.offsetWidth
|
||||
};
|
||||
|
||||
switch (placementPrimary) {
|
||||
case 'top':
|
||||
targetElPosition.top = hostElPosition.top - targetElement.offsetHeight;
|
||||
break;
|
||||
case 'bottom':
|
||||
targetElPosition.top = hostElPosition.top + hostElPosition.height;
|
||||
break;
|
||||
case 'left':
|
||||
targetElPosition.left = hostElPosition.left - targetElement.offsetWidth;
|
||||
break;
|
||||
case 'right':
|
||||
targetElPosition.left = hostElPosition.left + hostElPosition.width;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (placementSecondary) {
|
||||
case 'top':
|
||||
targetElPosition.top = hostElPosition.top;
|
||||
break;
|
||||
case 'bottom':
|
||||
targetElPosition.top = hostElPosition.top + hostElPosition.height - targetElement.offsetHeight;
|
||||
break;
|
||||
case 'left':
|
||||
targetElPosition.left = hostElPosition.left;
|
||||
break;
|
||||
case 'right':
|
||||
targetElPosition.left = hostElPosition.left + hostElPosition.width - targetElement.offsetWidth;
|
||||
break;
|
||||
case 'center':
|
||||
if (placementPrimary === 'top' || placementPrimary === 'bottom') {
|
||||
targetElPosition.left = hostElPosition.left + hostElPosition.width / 2 - targetElement.offsetWidth / 2;
|
||||
} else {
|
||||
targetElPosition.top = hostElPosition.top + hostElPosition.height / 2 - targetElement.offsetHeight / 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
targetElPosition.top = Math.round(targetElPosition.top);
|
||||
targetElPosition.bottom = Math.round(targetElPosition.bottom);
|
||||
targetElPosition.left = Math.round(targetElPosition.left);
|
||||
targetElPosition.right = Math.round(targetElPosition.right);
|
||||
|
||||
return targetElPosition;
|
||||
}
|
||||
}
|
||||
|
||||
const positionService = new Positioning();
|
||||
export function positionElements(
|
||||
hostElement: HTMLElement, targetElement: HTMLElement, placement: string, appendToBody?: boolean): void {
|
||||
const pos = positionService.positionElements(hostElement, targetElement, placement, appendToBody);
|
||||
|
||||
targetElement.style.top = `${pos.top}px`;
|
||||
targetElement.style.left = `${pos.left}px`;
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
import {parseTriggers} from './triggers';
|
||||
|
||||
describe('triggers', () => {
|
||||
|
||||
describe('parseTriggers', () => {
|
||||
|
||||
it('should parse single trigger', () => {
|
||||
const t = parseTriggers('foo');
|
||||
|
||||
expect(t.length).toBe(1);
|
||||
expect(t[0].open).toBe('foo');
|
||||
expect(t[0].close).toBe('foo');
|
||||
});
|
||||
|
||||
it('should parse open:close form', () => {
|
||||
const t = parseTriggers('foo:bar');
|
||||
|
||||
expect(t.length).toBe(1);
|
||||
expect(t[0].open).toBe('foo');
|
||||
expect(t[0].close).toBe('bar');
|
||||
});
|
||||
|
||||
it('should parse multiple triggers', () => {
|
||||
const t = parseTriggers('foo:bar bar:baz');
|
||||
|
||||
expect(t.length).toBe(2);
|
||||
expect(t[0].open).toBe('foo');
|
||||
expect(t[0].close).toBe('bar');
|
||||
expect(t[1].open).toBe('bar');
|
||||
expect(t[1].close).toBe('baz');
|
||||
});
|
||||
|
||||
it('should parse multiple triggers with mixed forms', () => {
|
||||
const t = parseTriggers('foo bar:baz');
|
||||
|
||||
expect(t.length).toBe(2);
|
||||
expect(t[0].open).toBe('foo');
|
||||
expect(t[0].close).toBe('foo');
|
||||
expect(t[1].open).toBe('bar');
|
||||
expect(t[1].close).toBe('baz');
|
||||
});
|
||||
|
||||
it('should properly trim excessive white-spaces', () => {
|
||||
const t = parseTriggers('foo bar \n baz ');
|
||||
|
||||
expect(t.length).toBe(3);
|
||||
expect(t[0].open).toBe('foo');
|
||||
expect(t[0].close).toBe('foo');
|
||||
expect(t[1].open).toBe('bar');
|
||||
expect(t[1].close).toBe('bar');
|
||||
expect(t[2].open).toBe('baz');
|
||||
expect(t[2].close).toBe('baz');
|
||||
});
|
||||
|
||||
it('should lookup and translate special aliases', () => {
|
||||
const t = parseTriggers('hover');
|
||||
|
||||
expect(t.length).toBe(1);
|
||||
expect(t[0].open).toBe('mouseenter');
|
||||
expect(t[0].close).toBe('mouseleave');
|
||||
});
|
||||
|
||||
it('should detect manual triggers', () => {
|
||||
const t = parseTriggers('manual');
|
||||
|
||||
expect(t[0].isManual).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should ignore empty inputs', () => {
|
||||
expect(parseTriggers(null).length).toBe(0);
|
||||
expect(parseTriggers(undefined).length).toBe(0);
|
||||
expect(parseTriggers('').length).toBe(0);
|
||||
});
|
||||
|
||||
it('should throw when more than one manual trigger detected', () => {
|
||||
expect(() => {
|
||||
parseTriggers('manual click manual');
|
||||
}).toThrow('Triggers parse error: only one manual trigger is allowed');
|
||||
});
|
||||
|
||||
it('should throw when manual trigger is mixed with other triggers', () => {
|
||||
expect(() => {
|
||||
parseTriggers('click manual');
|
||||
}).toThrow(`Triggers parse error: manual trigger can\'t be mixed with other triggers`);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
@ -0,0 +1,60 @@
|
||||
export class Trigger {
|
||||
constructor(public open: string, public close?: string) {
|
||||
if (!close) {
|
||||
this.close = open;
|
||||
}
|
||||
}
|
||||
|
||||
isManual() { return this.open === 'manual' || this.close === 'manual'; }
|
||||
}
|
||||
|
||||
const DEFAULT_ALIASES = {
|
||||
'hover': ['mouseenter', 'mouseleave']
|
||||
};
|
||||
|
||||
export function parseTriggers(triggers: string, aliases = DEFAULT_ALIASES): Trigger[] {
|
||||
const trimmedTriggers = (triggers || '').trim();
|
||||
|
||||
if (trimmedTriggers.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const parsedTriggers = trimmedTriggers.split(/\s+/).map(trigger => trigger.split(':')).map((triggerPair) => {
|
||||
let alias = aliases[triggerPair[0]] || triggerPair;
|
||||
return new Trigger(alias[0], alias[1]);
|
||||
});
|
||||
|
||||
const manualTriggers = parsedTriggers.filter(triggerPair => triggerPair.isManual());
|
||||
|
||||
if (manualTriggers.length > 1) {
|
||||
throw 'Triggers parse error: only one manual trigger is allowed';
|
||||
}
|
||||
|
||||
if (manualTriggers.length === 1 && parsedTriggers.length > 1) {
|
||||
throw 'Triggers parse error: manual trigger can\'t be mixed with other triggers';
|
||||
}
|
||||
|
||||
return parsedTriggers;
|
||||
}
|
||||
|
||||
const noopFn = () => {};
|
||||
|
||||
export function listenToTriggers(renderer: any, nativeElement: any, triggers: string, openFn, closeFn, toggleFn) {
|
||||
const parsedTriggers = parseTriggers(triggers);
|
||||
const listeners = [];
|
||||
|
||||
if (parsedTriggers.length === 1 && parsedTriggers[0].isManual()) {
|
||||
return noopFn;
|
||||
}
|
||||
|
||||
parsedTriggers.forEach((trigger: Trigger) => {
|
||||
if (trigger.open === trigger.close) {
|
||||
listeners.push(renderer.listen(nativeElement, trigger.open, toggleFn));
|
||||
} else {
|
||||
listeners.push(
|
||||
renderer.listen(nativeElement, trigger.open, openFn), renderer.listen(nativeElement, trigger.close, closeFn));
|
||||
}
|
||||
});
|
||||
|
||||
return () => { listeners.forEach(unsubscribeFn => unsubscribeFn()); };
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
import {toInteger, toString, getValueInRange, isInteger, isString} from './util';
|
||||
|
||||
describe('util', () => {
|
||||
|
||||
describe('toInteger', () => {
|
||||
|
||||
it('should be noop for integers', () => {
|
||||
expect(toInteger(0)).toBe(0);
|
||||
expect(toInteger(10)).toBe(10);
|
||||
});
|
||||
|
||||
it('should act as Math.floor for numbers', () => {
|
||||
expect(toInteger(0.1)).toBe(0);
|
||||
expect(toInteger(0.9)).toBe(0);
|
||||
});
|
||||
|
||||
it('should parse strings', () => {
|
||||
expect(toInteger('0')).toBe(0);
|
||||
expect(toInteger('10')).toBe(10);
|
||||
expect(toInteger('10.1')).toBe(10);
|
||||
expect(toInteger('10.9')).toBe(10);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('toString', () => {
|
||||
|
||||
it('should be noop for strings', () => { expect(toString('foo')).toBe('foo'); });
|
||||
|
||||
it('should return empty string for undefined values', () => {
|
||||
expect(toString(null)).toBe('');
|
||||
expect(toString(undefined)).toBe('');
|
||||
});
|
||||
|
||||
it('should stringify non-string values', () => {
|
||||
expect(toString(10)).toBe('10');
|
||||
expect(toString(false)).toBe('false');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('getValueInRange', () => {
|
||||
|
||||
it('should be noop for numbers in range', () => { expect(getValueInRange(5, 10, 0)).toBe(5); });
|
||||
|
||||
it('should do corrections in range', () => {
|
||||
expect(getValueInRange(11, 10, 0)).toBe(10);
|
||||
expect(getValueInRange(-1, 10, 0)).toBe(0);
|
||||
});
|
||||
|
||||
it('should take 0 as a default min bound', () => {
|
||||
expect(getValueInRange(11, 10)).toBe(10);
|
||||
expect(getValueInRange(-1, 10)).toBe(0);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('isInteger', () => {
|
||||
|
||||
it('should recognize integers', () => {
|
||||
expect(isInteger(0)).toBeTruthy();
|
||||
expect(isInteger(10)).toBeTruthy();
|
||||
expect(isInteger(-110)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should recognize non-integers', () => {
|
||||
expect(isInteger(null)).toBeFalsy();
|
||||
expect(isString([])).toBeFalsy();
|
||||
expect(isString(undefined)).toBeFalsy();
|
||||
expect(isInteger('2048')).toBeFalsy();
|
||||
expect(isInteger(14.1)).toBeFalsy();
|
||||
expect(isInteger(-14.1)).toBeFalsy();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('isString', () => {
|
||||
|
||||
it('should recognize strings', () => {
|
||||
expect(isString('string')).toBeTruthy();
|
||||
expect(isString('')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should recognize non-strings', () => {
|
||||
expect(isString(null)).toBeFalsy();
|
||||
expect(isString(2048)).toBeFalsy();
|
||||
expect(isString([])).toBeFalsy();
|
||||
expect(isString(undefined)).toBeFalsy();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,39 @@
|
||||
export function toInteger(value: any): number {
|
||||
return parseInt(`${value}`, 10);
|
||||
}
|
||||
|
||||
export function toString(value: any): string {
|
||||
return (value !== undefined && value !== null) ? `${value}` : '';
|
||||
}
|
||||
|
||||
export function getValueInRange(value: number, max: number, min = 0): number {
|
||||
return Math.max(Math.min(value, max), min);
|
||||
}
|
||||
|
||||
export function isString(value: any): value is string {
|
||||
return typeof value === 'string';
|
||||
}
|
||||
|
||||
export function isNumber(value: any): value is number {
|
||||
return !isNaN(toInteger(value));
|
||||
}
|
||||
|
||||
export function isInteger(value: any): value is number {
|
||||
return typeof value === 'number' && isFinite(value) && Math.floor(value) === value;
|
||||
}
|
||||
|
||||
export function isDefined(value: any): boolean {
|
||||
return value !== undefined && value !== null;
|
||||
}
|
||||
|
||||
export function padNumber(value: number) {
|
||||
if (isNumber(value)) {
|
||||
return `0${value}`.slice(-2);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export function regExpEscape(text) {
|
||||
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
export enum NbpCalendarPattern {
|
||||
GGMMAAAA = 'gg/mm/aaaa',
|
||||
MMAAAA = 'mm/aaaa',
|
||||
MMGGAAAA = 'mm/gg/aaaa',
|
||||
AAAAMMGG = 'aaaa/mm/gg'
|
||||
}
|
||||
|
||||
export enum NbpCalendarPosition {
|
||||
LEFT = 'left',
|
||||
RIGHT = 'right',
|
||||
TOP = 'top',
|
||||
TOP_LEFT = 'top-left',
|
||||
TOP_RIGHT = 'top-right',
|
||||
BOTTOM = 'bottom',
|
||||
BOTTOM_LEFT = 'bottom-left',
|
||||
BOTTOM_RIGHT = 'bottom-right'
|
||||
}
|
||||
|
||||
export enum NbpDateSeparator {
|
||||
DOT = '.',
|
||||
SLASH = '/',
|
||||
HYPHEN = '-'
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class EnabledRangeService {
|
||||
startDate: any = {};
|
||||
endDate: any = {};
|
||||
}
|
||||
|
@ -1,583 +0,0 @@
|
||||
<!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">
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600&display=swap" rel="stylesheet">
|
||||
<meta charset="UTF-8">
|
||||
<title>Datepicker Multi-Livello</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Open Sans', Arial, sans-serif;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
body * {
|
||||
font-family: 'Open Sans', Arial, sans-serif;
|
||||
}
|
||||
|
||||
.calendar {
|
||||
font-size: 12px;
|
||||
padding: 15px;
|
||||
border: 1px solid #e6e6e6;
|
||||
color: #333333;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.calendar-popup {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
display: none;
|
||||
|
||||
min-width: 160px;
|
||||
padding: 5px 0;
|
||||
margin: 2px 0 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: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.view-days .calendar-header {
|
||||
grid-template-columns: 1fr 5fr 1fr;
|
||||
}
|
||||
|
||||
.view-years .calendar-header {
|
||||
grid-template-columns: 1fr 3fr 1fr;
|
||||
}
|
||||
|
||||
.view-months .calendar-cell,
|
||||
.view-years .calendar-cell {
|
||||
padding: 6px 20px;
|
||||
}
|
||||
|
||||
.calendar-cell {
|
||||
padding: 5px 10px;
|
||||
line-height: 1.5;
|
||||
font-size: 12px;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #e6e6e6;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
|
||||
-webkit-transition: all 0.1s;
|
||||
-o-transition: all 0.1s;
|
||||
transition: all 0.1s;
|
||||
}
|
||||
|
||||
.calendar-cell:not(.disabled):not(.selected):hover {
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
|
||||
#monthYear {
|
||||
font-weight: bold;
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.calendar-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
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-size: 11px;
|
||||
line-height: 1.5;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.calendar-grid .selected {
|
||||
background-color: #1797be;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.calendar-grid .selected:hover {
|
||||
background-color: #137d9f;
|
||||
border-color: #0e5d76;
|
||||
}
|
||||
|
||||
.calendar-grid .other-month {
|
||||
color: #909fa7;
|
||||
}
|
||||
|
||||
.calendar-grid .today {
|
||||
color: #23b7e5;
|
||||
}
|
||||
|
||||
.calendar-grid:not(:has(.selected)) .today {
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
|
||||
.calendar-grid .disabled {
|
||||
color: #989898;
|
||||
background-color: #edf1f2;
|
||||
border-color: #dde6e9;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.calendar-actions {
|
||||
padding: 10px 9px 2px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.calendar-actions button {
|
||||
font-size: 12px;
|
||||
padding: 5px 10px;
|
||||
line-height: 1.5;
|
||||
background-color: #eb690b;
|
||||
color: #fff;
|
||||
border: 1px solid #e6e6e6;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.calendar-actions button#todayBtn {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.calendar-actions button#clearBtn {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-left-width: 0;
|
||||
background-color: #fff;
|
||||
color: #eb690b;
|
||||
}
|
||||
|
||||
.calendar-actions button#confirmBtn {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.datepicker-wrapper {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.datepicker-input {
|
||||
padding: 5px;
|
||||
height: 22px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #ccc;
|
||||
border-right-width: 0;
|
||||
background: #fff;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.datepicker-input::placeholder {
|
||||
color: #909fa7;
|
||||
}
|
||||
|
||||
.datepicker-input:focus {
|
||||
border-color: #66afe9;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.datepicker-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 13.5px;
|
||||
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
height: 22px;
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border-bottom-right-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.datepicker-icon:active,
|
||||
.datepicker-icon:hover,
|
||||
.datepicker-icon:focus {
|
||||
background-color: #e6e6e6;
|
||||
border-color: #cbcbcb;
|
||||
}
|
||||
|
||||
.datepicker-icon:hover:active {
|
||||
background-color: #d4d4d4;
|
||||
border-color: #aaaaaa;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="datepicker-wrapper">
|
||||
<input id="dateInput" class="datepicker-input" type="text" placeholder="DD/MM/YYYY" />
|
||||
<i id="calendarIcon" class="datepicker-icon fa fa-calendar"></i>
|
||||
<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 toggleCalendar() {
|
||||
if (calendarPopup.style.display === 'block') {
|
||||
hideCalendar();
|
||||
} else {
|
||||
showCalendar();
|
||||
}
|
||||
}
|
||||
|
||||
function hideCalendar() {
|
||||
calendarPopup.style.display = 'none';
|
||||
document.removeEventListener('mousedown', onClickOutside);
|
||||
|
||||
if (selectedDate) {
|
||||
currentDate = new Date(selectedDate);
|
||||
} else {
|
||||
currentDate = new Date();
|
||||
}
|
||||
}
|
||||
function onClickOutside(e) {
|
||||
if (!calendarPopup.contains(e.target) && e.target !== dateInput && e.target !== document.getElementById('calendarIcon')) {
|
||||
hideCalendar();
|
||||
}
|
||||
}
|
||||
|
||||
// --- SOVRASCRIVI RENDERING ---
|
||||
function renderCalendar() {
|
||||
// Gestione classi view-* su calendarPopup
|
||||
calendarPopup.classList.remove('view-days', 'view-months', 'view-years');
|
||||
if (view === 'days') calendarPopup.classList.add('view-days');
|
||||
else if (view === 'months') calendarPopup.classList.add('view-months');
|
||||
else if (view === 'years') calendarPopup.classList.add('view-years');
|
||||
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 MODIFICATA: disabilita tutte le date inferiori al 9/05/2025 ---
|
||||
function isDateDisabled(date) {
|
||||
const minDate = new Date(2025, 4, 9, 0, 0, 0, 0); // 9 maggio 2025
|
||||
if (date < minDate) return true;
|
||||
// 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");
|
||||
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 (sameDate(new Date(), thisDate)) div.classList.add("today");
|
||||
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 = ['gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre'];
|
||||
monthYearEl.textContent = currentDate.getFullYear();
|
||||
months.forEach((m, idx) => {
|
||||
const div = document.createElement("div");
|
||||
div.textContent = m;
|
||||
div.classList.add("calendar-cell");
|
||||
const now = new Date();
|
||||
if (currentDate.getFullYear() === now.getFullYear() && idx === now.getMonth()) {
|
||||
div.classList.add("today");
|
||||
}
|
||||
// Aggiungi la classe 'selected' se il mese corrisponde a selectedDate
|
||||
if (selectedDate && currentDate.getFullYear() === selectedDate.getFullYear() && idx === selectedDate.getMonth()) {
|
||||
div.classList.add("selected");
|
||||
}
|
||||
// Disabilita mese se tutto il mese è inferiore alla data minima
|
||||
const minDate = new Date(2025, 4, 9, 0, 0, 0, 0);
|
||||
const firstDay = new Date(currentDate.getFullYear(), idx, 1);
|
||||
const lastDay = new Date(currentDate.getFullYear(), idx + 1, 0, 23, 59, 59, 999);
|
||||
let disableMonth = lastDay < minDate;
|
||||
if (disableMonth) {
|
||||
div.classList.add("disabled");
|
||||
} else {
|
||||
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 === new Date().getFullYear()) div.classList.add("today");
|
||||
if (selectedDate && y === selectedDate.getFullYear()) div.classList.add("selected");
|
||||
// Disabilita anno se tutto l'anno è inferiore alla data minima
|
||||
const minDate = new Date(2025, 4, 9, 0, 0, 0, 0);
|
||||
const lastDayOfYear = new Date(y, 11, 31, 23, 59, 59, 999);
|
||||
let disableYear = lastDayOfYear < minDate;
|
||||
if (disableYear) {
|
||||
div.classList.add("disabled");
|
||||
} else {
|
||||
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() - 20);
|
||||
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() + 20);
|
||||
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
|
||||
|
||||
// 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', toggleCalendar);
|
||||
// Espone showCalendar globalmente solo se serve (compatibilità)
|
||||
window.showCalendar = showCalendar;
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -0,0 +1,33 @@
|
||||
<div class="nbp-fid-calendar-container">
|
||||
<div class="input-group">
|
||||
<input #inputElement
|
||||
type="text"
|
||||
class="form-control"
|
||||
[placeholder]="placeholder"
|
||||
[disabled]="disabled"
|
||||
[required]="required"
|
||||
#datepickerInput="rplFidCalendarNOA11Y"
|
||||
rplFidCalendarNOA11Y
|
||||
[nbpLabelPattern]="datePattern"
|
||||
[nbpDateSeparator]="dateSeparator"
|
||||
[minDate]="minDate"
|
||||
[maxDate]="maxDate"
|
||||
[startDate]="startDate"
|
||||
[placement]="placementPosition"
|
||||
[showWeekNumbers]="showWeekNumbers"
|
||||
[showWeekdays]="showWeekdays"
|
||||
[showNavigation]="showNavigation"
|
||||
[outsideDays]="outsideDays"
|
||||
[displayMonths]="displayMonths"
|
||||
(dateSelect)="onDateSelect($event)"
|
||||
(navigate)="onDateChange($event)">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-secondary calendar-button"
|
||||
type="button"
|
||||
[disabled]="disabled"
|
||||
(click)="toggle()">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,91 @@
|
||||
.nbp-fid-calendar-container {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
|
||||
.input-group {
|
||||
width: 100%;
|
||||
|
||||
.form-control {
|
||||
height: 38px;
|
||||
border-radius: 4px 0 0 4px;
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
border-color: #80bdff;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: #e9ecef;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.input-group-append {
|
||||
.calendar-button {
|
||||
height: 38px;
|
||||
border-radius: 0 4px 4px 0;
|
||||
background-color: #f8f9fa;
|
||||
border-color: #ced4da;
|
||||
color: #495057;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Personalizzazione del dropdown del datepicker
|
||||
::ng-deep {
|
||||
.dropdown-menu {
|
||||
padding: 10px !important;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
||||
|
||||
.btn-light {
|
||||
background-color: #f8f9fa;
|
||||
border-color: #f8f9fa;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background-color: #e9ecef;
|
||||
border-color: #e9ecef;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #007bff;
|
||||
border-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.ngb-dp-header {
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
|
||||
.ngb-dp-navigation-select {
|
||||
select {
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ngb-dp-day {
|
||||
&.disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
import { Component, Input, Output, EventEmitter, ViewChild, ElementRef, OnInit } from '@angular/core';
|
||||
import { NgbInputDatepickerNOA11Y } from './@ng-bootstrap-noa11y/datepicker/datepicker-input';
|
||||
import { NbpCalendarPattern, NbpCalendarPosition, NbpDateSeparator } from './nbp-calendar-generic.enum';
|
||||
import { NgbDateStruct } from './@ng-bootstrap-noa11y/datepicker/ngb-date-struct';
|
||||
import { EventManager } from '@isp/xdce-arch-core-base';
|
||||
|
||||
@Component({
|
||||
selector: 'nbp-fid-calendar-generic',
|
||||
templateUrl: './nbp-fid-calendar-generic.component.html',
|
||||
styleUrls: ['./nbp-fid-calendar-generic.component.scss']
|
||||
})
|
||||
export class NbpFidCalendarGenericComponent implements OnInit {
|
||||
@ViewChild('datepickerInput') datepickerInput: NgbInputDatepickerNOA11Y;
|
||||
@ViewChild('inputElement') inputElement: ElementRef;
|
||||
|
||||
@Input() placeholder: string = '';
|
||||
@Input() disabled: boolean = false;
|
||||
@Input() required: boolean = false;
|
||||
@Input() datePattern: NbpCalendarPattern = NbpCalendarPattern.GGMMAAAA;
|
||||
@Input() dateSeparator: NbpDateSeparator = NbpDateSeparator.SLASH;
|
||||
@Input() placementPosition: NbpCalendarPosition = NbpCalendarPosition.BOTTOM;
|
||||
@Input() minDate: NgbDateStruct;
|
||||
@Input() maxDate: NgbDateStruct;
|
||||
@Input() startDate: NgbDateStruct;
|
||||
@Input() showWeekNumbers: boolean = false;
|
||||
@Input() showWeekdays: boolean = true;
|
||||
@Input() showNavigation: boolean = true;
|
||||
@Input() outsideDays: 'visible' | 'collapsed' | 'hidden' = 'visible';
|
||||
@Input() displayMonths: number = 1;
|
||||
|
||||
@Output() dateSelected = new EventEmitter<NgbDateStruct>();
|
||||
@Output() dateChanged = new EventEmitter<NgbDateStruct>();
|
||||
@Output() datepickerClosed = new EventEmitter<void>();
|
||||
|
||||
constructor(private eventManager: EventManager) { }
|
||||
|
||||
ngOnInit() {
|
||||
// Sottoscrizione all'evento di chiusura del datepicker
|
||||
this.eventManager.subscribeToEvent('DATEPICKER_CLOSE', () => {
|
||||
this.datepickerClosed.emit();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Apre il datepicker
|
||||
*/
|
||||
open() {
|
||||
if (this.datepickerInput && !this.disabled) {
|
||||
this.datepickerInput.open(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Chiude il datepicker
|
||||
*/
|
||||
close() {
|
||||
if (this.datepickerInput) {
|
||||
this.datepickerInput.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alterna l'apertura e la chiusura del datepicker
|
||||
*/
|
||||
toggle() {
|
||||
if (this.datepickerInput && !this.disabled) {
|
||||
this.datepickerInput.toggle(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gestisce l'evento di selezione della data
|
||||
* @param date La data selezionata
|
||||
*/
|
||||
onDateSelect(date: NgbDateStruct) {
|
||||
this.dateSelected.emit(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gestisce l'evento di modifica della data
|
||||
* @param date La nuova data
|
||||
*/
|
||||
onDateChange(date: NgbDateStruct) {
|
||||
this.dateChanged.emit(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Imposta il focus sull'input
|
||||
*/
|
||||
focus() {
|
||||
if (this.inputElement) {
|
||||
this.inputElement.nativeElement.focus();
|
||||
}
|
||||
}
|
||||
}
|
@ -77,6 +77,12 @@
|
||||
</nbp-calendar-generic>
|
||||
</nbp-input-container>
|
||||
</div>
|
||||
<div>
|
||||
<nbp-fid-calendar-generic [placeholder]="'Seleziona data'" [datePattern]="_nbpCalendarPattern.GGMMAAAA"
|
||||
[dateSeparator]="_nbpDateSeparator.SLASH" [placementPosition]="_nbpCalendarPosition.BOTTOM"
|
||||
(dateSelected)="onDateSelect($event)">
|
||||
</nbp-fid-calendar-generic>
|
||||
</div>
|
||||
|
||||
<p class="new-part">Combo (nbp-input-container + nbp-combo)</p>
|
||||
<div>
|
||||
@ -87,7 +93,8 @@
|
||||
</nbp-input-container>
|
||||
<nbp-input-container [nbpStyle]="_nbpStyle.DEFAULT" [nbpLabel]="'Default'">
|
||||
<nbp-combo [id]="'comboDefault'" [name]="'comboDefault'" [nbpStyle]="_nbpStyle.DEFAULT"
|
||||
[nbpDataSource]="comboDatasource" [(ngModel)]="comboSelectedValue" [nbpShowEmptyValue]="true" [disabled]="true">
|
||||
[nbpDataSource]="comboDatasource" [(ngModel)]="comboSelectedValue" [nbpShowEmptyValue]="true"
|
||||
[disabled]="true">
|
||||
</nbp-combo>
|
||||
</nbp-input-container>
|
||||
</div>
|
||||
@ -149,8 +156,7 @@
|
||||
[nbpDataSource]="tableDs" [nbpAutoBind]="true" [nbpSelectionType]="tableSelectionType"
|
||||
[nbpLayoutAuto]="true">
|
||||
|
||||
<nbp-table-column nbpId='headerField' nbpTitle='Header field' nbpField='headerField'
|
||||
[nbpVisible]='true'>
|
||||
<nbp-table-column nbpId='headerField' nbpTitle='Header field' nbpField='headerField' [nbpVisible]='true'>
|
||||
</nbp-table-column>
|
||||
|
||||
<nbp-table-column nbpId='headerField2' nbpTitle='Header field 2' nbpField='headerField2'
|
||||
@ -171,12 +177,12 @@
|
||||
[nbpDataSource]="campiStandardData" ariaLabel="multi selection table" [nbpAutoBind]="true"
|
||||
[nbpSelectionType]="multi">
|
||||
|
||||
<nbp-table-column nbpId='headerField' nbpTitle='Header field' nbpField='headerField'
|
||||
[nbpSortable]='true' [nbpVisible]='true'>
|
||||
<nbp-table-column nbpId='headerField' nbpTitle='Header field' nbpField='headerField' [nbpSortable]='true'
|
||||
[nbpVisible]='true'>
|
||||
</nbp-table-column>
|
||||
|
||||
<nbp-table-column nbpId='headerField2' nbpTitle='Header field 2' nbpField='headerField2'
|
||||
[nbpSortable]='true' [nbpVisible]='true'>
|
||||
<nbp-table-column nbpId='headerField2' nbpTitle='Header field 2' nbpField='headerField2' [nbpSortable]='true'
|
||||
[nbpVisible]='true'>
|
||||
</nbp-table-column>
|
||||
|
||||
</nbp-table>
|
||||
|
@ -5,7 +5,10 @@ import {
|
||||
NbpCalendarPattern, NbpCalendarPosition, NbpComboMultiComponent,
|
||||
NbpDataSource, NbpStyle, NbpTableSelectionType, NgbDateStruct,
|
||||
RowAction, RowDataExpander, RowModel,
|
||||
NbpComboComponent
|
||||
NbpComboComponent,
|
||||
NgbDatepickerConfig,
|
||||
NbpDatepickerConfiguration,
|
||||
NbpCalendarGenericComponentNOA11Y
|
||||
} from '@isp/xdce-widget';
|
||||
|
||||
@Component({
|
||||
@ -17,6 +20,8 @@ export class Showcase1Component extends NbpBaseComponent {
|
||||
|
||||
public _nbpStyle = NbpStyle;
|
||||
|
||||
x : NbpCalendarGenericComponentNOA11Y
|
||||
|
||||
//
|
||||
// TABBAR
|
||||
items: Array<ITabItem<void>> = [
|
||||
@ -181,8 +186,9 @@ export class Showcase1Component extends NbpBaseComponent {
|
||||
campiStandardData: NbpDataSource<any>;
|
||||
//
|
||||
|
||||
constructor(injector: Injector) {
|
||||
constructor(injector: Injector, private calendarConfig: NgbDatepickerConfig) {
|
||||
super(injector);
|
||||
calendarConfig.outsideDays = "visible";
|
||||
// table2
|
||||
this.setDataRowExpander(this.table2Rows[0], 0);
|
||||
this.campiStandardData = new NbpDataSource<any>(this.oggetti);
|
||||
|
@ -1,99 +0,0 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
REM Script to switch between Fideuram (fid) and Armundia (arm) Git environments
|
||||
REM This script compresses the current .git folder and extracts the other one
|
||||
|
||||
echo Switching Git environment...
|
||||
|
||||
REM Check if .git folder exists
|
||||
if exist ".git" (
|
||||
REM Determine which environment to switch to
|
||||
if exist "fid-git.zip" (
|
||||
REM Current environment is Armundia, switch to Fideuram
|
||||
echo Current environment: Armundia
|
||||
echo Switching to Fideuram environment...
|
||||
|
||||
REM Compress Armundia .git folder
|
||||
echo Compressing Armundia .git folder...
|
||||
powershell -command "Compress-Archive -Path '.git' -DestinationPath 'arm-git.zip' -Force"
|
||||
|
||||
REM Remove current .git folder
|
||||
echo Removing current .git folder...
|
||||
rmdir /s /q .git
|
||||
|
||||
REM Extract Fideuram .git folder
|
||||
echo Extracting Fideuram .git folder...
|
||||
powershell -command "Expand-Archive -Path 'fid-git.zip' -DestinationPath '.' -Force"
|
||||
|
||||
REM Delete the zip file after extraction
|
||||
echo Removing the Fideuram zip file...
|
||||
del /f /q fid-git.zip
|
||||
|
||||
echo Successfully switched to Fideuram environment.
|
||||
) else if exist "arm-git.zip" (
|
||||
REM Current environment is Fideuram, switch to Armundia
|
||||
echo Current environment: Fideuram
|
||||
echo Switching to Armundia environment...
|
||||
|
||||
REM Compress Fideuram .git folder
|
||||
echo Compressing Fideuram .git folder...
|
||||
powershell -command "Compress-Archive -Path '.git' -DestinationPath 'fid-git.zip' -Force"
|
||||
|
||||
REM Remove current .git folder
|
||||
echo Removing current .git folder...
|
||||
rmdir /s /q .git
|
||||
|
||||
REM Extract Armundia .git folder
|
||||
echo Extracting Armundia .git folder...
|
||||
powershell -command "Expand-Archive -Path 'arm-git.zip' -DestinationPath '.' -Force"
|
||||
|
||||
REM Delete the zip file after extraction
|
||||
echo Removing the Armundia zip file...
|
||||
del /f /q arm-git.zip
|
||||
|
||||
echo Successfully switched to Armundia environment.
|
||||
) else (
|
||||
REM First run - no compressed Git folders exist yet
|
||||
echo This appears to be the first run.
|
||||
echo Current .git folder will be considered as Fideuram environment.
|
||||
|
||||
REM Compress current .git as Fideuram
|
||||
echo Compressing current .git folder as Fideuram...
|
||||
powershell -command "Compress-Archive -Path '.git' -DestinationPath 'fid-git.zip' -Force"
|
||||
|
||||
echo Please initialize the Armundia Git repository and run this script again.
|
||||
echo You can initialize a new Git repository with: git init
|
||||
)
|
||||
) else (
|
||||
REM No .git folder exists
|
||||
if exist "fid-git.zip" (
|
||||
REM Extract Fideuram .git folder
|
||||
echo No .git folder found. Extracting Fideuram environment...
|
||||
powershell -command "Expand-Archive -Path 'fid-git.zip' -DestinationPath '.' -Force"
|
||||
|
||||
REM Delete the zip file after extraction
|
||||
echo Removing the Fideuram zip file...
|
||||
del /f /q fid-git.zip
|
||||
|
||||
echo Successfully switched to Fideuram environment.
|
||||
) else if exist "arm-git.zip" (
|
||||
REM Extract Armundia .git folder
|
||||
echo No .git folder found. Extracting Armundia environment...
|
||||
powershell -command "Expand-Archive -Path 'arm-git.zip' -DestinationPath '.' -Force"
|
||||
|
||||
REM Delete the zip file after extraction
|
||||
echo Removing the Armundia zip file...
|
||||
del /f /q arm-git.zip
|
||||
|
||||
echo Successfully switched to Armundia environment.
|
||||
) else (
|
||||
REM No Git environments found
|
||||
echo No Git environments found.
|
||||
echo Please initialize a Git repository with: git init
|
||||
)
|
||||
)
|
||||
|
||||
echo.
|
||||
echo Done!
|
||||
pause
|
Loading…
x
Reference in New Issue
Block a user