Skip to content

Commit

Permalink
Merge pull request #14196 from gizm0bill/bugfix/10358_date_select_wit…
Browse files Browse the repository at this point in the history
…hin_the_hour

#10358: fix date restriction within the hour issue
  • Loading branch information
cetincakiroglu authored Mar 22, 2024
2 parents f576adb + 19f61f0 commit b4cb0cf
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 77 deletions.
40 changes: 40 additions & 0 deletions src/app/components/calendar/calendar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1901,4 +1901,44 @@ describe('Calendar', () => {
expect(calendar.currentMinute).toEqual(10);
expect(calendar.pm).toEqual(false);
});

it('should allow changing time when min and max date times are within the hour', () => {
const event = { preventDefault: () => { } };
const now = new Date('2023-01-01T12:14:00.000Z'); // 1 minute before max date
const minDate = new Date('2023-01-01T11:45:00.000Z'); // quarter to now date hour
const maxDate = new Date('2023-01-01T12:15:01.000Z'); // quarter past now date hour, 1 minute and 1 second after now date
const maxDateISO = maxDate.toISOString();
const minDateISO = minDate.toISOString();
calendar.defaultDate = now;
calendar.value = now;
calendar.showTime = true;
calendar.showSeconds = true;
calendar.minDate = minDate;
calendar.maxDate = maxDate;
fixture.detectChanges();

calendar.incrementMinute(event);
// increment 2 seconds, should clamp to max date
calendar.incrementSecond(event);
calendar.incrementSecond(event);
calendar.updateTime();
expect((calendar.value as Date).toISOString()).toBe(maxDateISO);
// decrement back 1 minute and 1 second
calendar.decrementMinute(event);
calendar.decrementSecond(event);
calendar.updateTime();
// try increment 2 minutes, should clamp to max date
calendar.incrementMinute(event);
calendar.incrementMinute(event);
calendar.updateTime();
expect((calendar.value as Date).toISOString()).toBe(maxDateISO);
// now time should be 12:15, min time should be 11:45, decrementing hour should clamp to min date
calendar.decrementHour(event);
calendar.updateTime();
expect((calendar.value as Date).toISOString()).toBe(minDateISO);
// increment hour should clamp to max date
calendar.incrementHour(event);
calendar.updateTime();
expect((calendar.value as Date).toISOString()).toBe(maxDateISO);
})
});
114 changes: 41 additions & 73 deletions src/app/components/calendar/calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2496,7 +2496,8 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor {
return hours;
};

validateTime(hour: number, minute: number, second: number, pm: boolean) {
constrainTime(hour: number, minute: number, second: number, pm: boolean) {
let returnTimeTriple: number[] = [ hour, minute, second ]
let value = this.value;
const convertedHour = this.convertTo24Hour(hour, pm);
const isRange = this.isRangeSelection(),
Expand All @@ -2515,58 +2516,42 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor {
}
}
const valueDateString = value ? value.toDateString() : null;
if (this.minDate && valueDateString && this.minDate.toDateString() === valueDateString) {
if (this.minDate.getHours() > convertedHour) {
return false;
}
if (this.minDate.getHours() === convertedHour) {
if (this.minDate.getMinutes() > minute) {
return false;
}
if (this.minDate.getMinutes() === minute) {
if (this.minDate.getSeconds() > second) {
return false;
}
}
}
}

if (this.maxDate && valueDateString && this.maxDate.toDateString() === valueDateString) {
if (this.maxDate.getHours() < convertedHour) {
return false;
}
if (this.maxDate.getHours() === convertedHour) {
if (this.maxDate.getMinutes() < minute) {
return false;
}
if (this.maxDate.getMinutes() === minute) {
if (this.maxDate.getSeconds() < second) {
return false;
}
}
}
let isMinDate = this.minDate && valueDateString && this.minDate.toDateString() === valueDateString;
let isMaxDate = this.maxDate && valueDateString && this.maxDate.toDateString() === valueDateString;
switch (true) { // intentional fall through
case isMinDate && this.minDate.getHours() > convertedHour:
returnTimeTriple[0] = this.minDate.getHours();
case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() > minute:
returnTimeTriple[1] = this.minDate.getMinutes();
case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() === minute && this.minDate.getSeconds() > second:
returnTimeTriple[2] = this.minDate.getSeconds();
break;
case isMaxDate && this.maxDate.getHours() < convertedHour:
returnTimeTriple[0] = this.maxDate.getHours();
case isMaxDate && this.maxDate.getHours() === convertedHour && this.maxDate.getMinutes() < minute:
returnTimeTriple[1] = this.maxDate.getMinutes();
case isMaxDate && this.maxDate.getHours() === convertedHour && this.maxDate.getMinutes() === minute && this.maxDate.getSeconds() < second:
returnTimeTriple[2] = this.maxDate.getSeconds();
break;
}
return true;
return returnTimeTriple;
}

incrementHour(event: any) {
const prevHour = this.currentHour;
let newHour = <number>this.currentHour + this.stepHour;
const prevHour = this.currentHour ?? 0;
let newHour = (this.currentHour ?? 0) + this.stepHour;
let newPM = this.pm;

if (this.hourFormat == '24') newHour = newHour >= 24 ? newHour - 24 : newHour;
if (this.hourFormat == '24')
newHour = newHour >= 24 ? newHour - 24 : newHour;
else if (this.hourFormat == '12') {
// Before the AM/PM break, now after
if (<number>prevHour < 12 && newHour > 11) {
if (prevHour < 12 && newHour > 11) {
newPM = !this.pm;
}
newHour = newHour >= 13 ? newHour - 12 : newHour;
}

if (this.validateTime(newHour, <any>this.currentMinute, <any>this.currentSecond, <any>newPM)) {
this.currentHour = newHour;
this.pm = newPM;
}
[ this.currentHour, this.currentMinute, this.currentSecond ] = this.constrainTime(newHour, this.currentMinute!, this.currentSecond!, newPM!);
this.pm = newPM;
event.preventDefault();
}

Expand Down Expand Up @@ -2628,63 +2613,47 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor {
}

decrementHour(event: any) {
let newHour = <number>this.currentHour - this.stepHour;
let newHour = ( this.currentHour ?? 0 ) - this.stepHour;
let newPM = this.pm;

if (this.hourFormat == '24') newHour = newHour < 0 ? 24 + newHour : newHour;
if (this.hourFormat == '24')
newHour = newHour < 0 ? 24 + newHour : newHour;
else if (this.hourFormat == '12') {
// If we were at noon/midnight, then switch
if (this.currentHour === 12) {
newPM = !this.pm;
}
newHour = newHour <= 0 ? 12 + newHour : newHour;
}

if (this.validateTime(newHour, <any>this.currentMinute, <any>this.currentSecond, <any>newPM)) {
this.currentHour = newHour;
this.pm = newPM;
}

[ this.currentHour, this.currentMinute, this.currentSecond ] = this.constrainTime(newHour, this.currentMinute!, this.currentSecond!, newPM!);
this.pm = newPM;
event.preventDefault();
}

incrementMinute(event: any) {
let newMinute = <number>this.currentMinute + this.stepMinute;
let newMinute = ( this.currentMinute ?? 0 ) + this.stepMinute;
newMinute = newMinute > 59 ? newMinute - 60 : newMinute;
if (this.validateTime(<any>this.currentHour, newMinute, <any>this.currentSecond, <any>this.pm)) {
this.currentMinute = newMinute;
}

[ this.currentHour, this.currentMinute, this.currentSecond ] = this.constrainTime(this.currentHour, newMinute, this.currentSecond!, this.pm!);
event.preventDefault();
}

decrementMinute(event: any) {
let newMinute = <any>this.currentMinute - this.stepMinute;
let newMinute = ( this.currentMinute ?? 0 ) - this.stepMinute;
newMinute = newMinute < 0 ? 60 + newMinute : newMinute;
if (this.validateTime(<any>this.currentHour, newMinute, <any>this.currentSecond, <any>this.pm)) {
this.currentMinute = newMinute;
}

[ this.currentHour, this.currentMinute, this.currentSecond ] = this.constrainTime(this.currentHour, newMinute, this.currentSecond, this.pm);
event.preventDefault();
}

incrementSecond(event: any) {
let newSecond = <any>this.currentSecond + this.stepSecond;
newSecond = newSecond > 59 ? newSecond - 60 : newSecond;
if (this.validateTime(<any>this.currentHour, <any>this.currentMinute, newSecond, <any>this.pm)) {
this.currentSecond = newSecond;
}

[ this.currentHour, this.currentMinute, this.currentSecond ] = this.constrainTime(this.currentHour, this.currentMinute, newSecond, this.pm);
event.preventDefault();
}

decrementSecond(event: any) {
let newSecond = <any>this.currentSecond - this.stepSecond;
newSecond = newSecond < 0 ? 60 + newSecond : newSecond;
if (this.validateTime(<any>this.currentHour, <any>this.currentMinute, newSecond, <any>this.pm)) {
this.currentSecond = newSecond;
}

[ this.currentHour, this.currentMinute, this.currentSecond ] = this.constrainTime(this.currentHour, this.currentMinute, newSecond, this.pm);
event.preventDefault();
}

Expand Down Expand Up @@ -2723,10 +2692,9 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor {

toggleAMPM(event: any) {
const newPM = !this.pm;
if (this.validateTime(<any>this.currentHour, <any>this.currentMinute, <any>this.currentSecond, newPM)) {
this.pm = newPM;
this.updateTime();
}
[ this.currentHour, this.currentMinute, this.currentSecond ] = this.constrainTime(this.currentHour, this.currentMinute, this.currentSecond, newPM);
this.pm = newPM;
this.updateTime();
event.preventDefault();
}

Expand Down
8 changes: 4 additions & 4 deletions src/app/showcase/doc/calendar/minmaxdox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Code } from '../../domain/code';
<p>Boundaries for the permitted dates that can be entered are defined with <i>minDate</i> and <i>maxDate</i> properties.</p>
</app-docsectiontext>
<div class="card flex justify-content-center">
<p-calendar [(ngModel)]="date" [minDate]="minDate" [maxDate]="maxDate" [readonlyInput]="true"></p-calendar>
<p-calendar [(ngModel)]="date" [minDate]="minDate" [maxDate]="maxDate" [readonlyInput]="true" [showTime]="true"></p-calendar>
</div>
<app-code [code]="code" selector="calendar-minmax-demo"></app-code>
`
Expand Down Expand Up @@ -39,7 +39,7 @@ export class MinMaxDoc {
code: Code = {
basic: `<p-calendar [(ngModel)]="date" [minDate]="minDate" [maxDate]="maxDate" [readonlyInput]="true"></p-calendar>`,

html: `
html: `
<div class="card flex justify-content-center">
<p-calendar [(ngModel)]="date" [minDate]="minDate" [maxDate]="maxDate" [readonlyInput]="true"></p-calendar>
</div>`,
Expand All @@ -51,9 +51,9 @@ import { Component, OnInit } from '@angular/core';
selector: 'calendar-minmax-demo',
templateUrl: './calendar-minmax-demo.html'
})
export class CalendarMinmaxDemo implements OnInit {
export class CalendarMinmaxDemo implements OnInit {
date: Date | undefined;
minDate: Date | undefined;
maxDate: Date | undefined;
Expand Down

0 comments on commit b4cb0cf

Please sign in to comment.